Merge branch 'master' of https://git.code.sf.net/p/cdesktopenv/code
[oweals/cde.git] / cde / programs / dtsession / SmAuth.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  * (c) Copyright 1995 Digital Equipment Corporation.
25  * (c) Copyright 1995 Hewlett-Packard Company.
26  * (c) Copyright 1995 International Business Machines Corp.
27  * (c) Copyright 1995 Sun Microsystems, Inc.
28  * (c) Copyright 1995 Novell, Inc.
29  * (c) Copyright 1995 FUJITSU LIMITED.
30  * (c) Copyright 1995 Hitachi.
31  *
32  * $TOG: SmAuth.c /main/4 1997/03/14 14:11:50 barstow $
33  */
34 /******************************************************************************
35
36 Copyright (c) 1993  X Consortium
37
38 Permission is hereby granted, free of charge, to any person obtaining a copy
39 of this software and associated documentation files (the "Software"), to deal
40 in the Software without restriction, including without limitation the rights
41 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42 copies of the Software, and to permit persons to whom the Software is
43 furnished to do so, subject to the following conditions:
44
45 The above copyright notice and this permission notice shall be included in
46 all copies or substantial portions of the Software.
47
48 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
51 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
52 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
53 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
54
55 Except as contained in this notice, the name of the X Consortium shall not be
56 used in advertising or otherwise to promote the sale, use or other dealings
57 in this Software without prior written authorization from the X Consortium.
58 ******************************************************************************/
59
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64 #include <sys/stat.h>
65 #include <sys/param.h>
66
67 #include <X11/Intrinsic.h>
68 #include <X11/SM/SMlib.h>
69 #include <X11/ICE/ICEutil.h>
70
71 #include "SmAuth.h"
72
73 typedef struct _IceAuthFileEntryList
74 {
75   IceAuthFileEntry *fileEntry;
76   struct _IceAuthFileEntryList *next;
77 } IceAuthFileEntryList;
78
79 /*
80  * Private data
81  */
82 #define MAGIC_COOKIE_LEN 16
83 #define AUTH_RETRIES 10
84 #define AUTH_TIMEOUT 2
85 #define AUTH_DEADTIME 600L
86
87 /*
88  * Private functions - forward declarations
89  */
90
91 static int
92 writeIceauth (
93         int                     nEntries,
94         IceAuthDataEntry        *entries,
95         int                     restore);
96
97 static int
98 addToEntryList (
99         IceAuthFileEntryList    **entryListP,
100         IceAuthFileEntry        *fileEntry);
101
102 static int
103 fileEntryInDataEntries (
104         int                     nEntries,
105         IceAuthDataEntry        *entries,
106         IceAuthFileEntry        *fileEntry);
107
108 static void
109 freeEntryList (
110         IceAuthFileEntryList    *entryList);
111
112 /*
113  * Private functions - implemenation.
114  */
115 static void
116 freeEntryList (
117         IceAuthFileEntryList    *entryList)
118 {
119     IceAuthFileEntryList *nextEntryP;
120
121     while (entryList != (IceAuthFileEntryList *)NULL)
122     {
123         nextEntryP = entryList->next;
124
125         IceFreeAuthFileEntry(entryList->fileEntry);
126         XtFree((char *)entryList);
127
128         entryList = nextEntryP;
129     }
130 }
131
132 static int
133 fileEntryInDataEntries (
134         int                     nEntries,
135         IceAuthDataEntry        *entries,
136         IceAuthFileEntry        *fileEntry)
137 {
138     int i;
139
140 #define SAME_STR(field) \
141     ((entries->field != (char *)NULL) &&\
142      (fileEntry->field != (char *)NULL) &&\
143      (strcmp(entries->field, fileEntry->field) == 0))
144
145     for (i = 0; i < nEntries; i++, entries++)
146     {
147         if (SAME_STR(protocol_name) &&
148             SAME_STR(network_id) &&
149             SAME_STR(auth_name))
150             return 1;
151     }
152
153 #undef SAME_STR
154
155     return 0;
156 }
157
158 static int
159 addToEntryList (
160         IceAuthFileEntryList    **entryListP,
161         IceAuthFileEntry        *fileEntry)
162 {
163     IceAuthFileEntryList *newItem;
164
165     if ((newItem =
166          (IceAuthFileEntryList *)XtMalloc(sizeof(IceAuthFileEntryList)))
167         == (IceAuthFileEntryList *)NULL)
168         return 0;
169
170     /* I assume it's ok to reverse the order; otherwise */
171     /* we need to add the new item onto the end of the list. */
172     newItem->fileEntry = fileEntry;
173     newItem->next = *entryListP;
174     *entryListP = newItem;
175
176     return 1;
177 }
178
179 static int
180 writeIceauth (
181         int                     nEntries,
182         IceAuthDataEntry        *entries,
183         int                     restore)
184 {
185     FILE *fp = NULL;
186     char *path;
187     char *extraPath;
188     int oldUmask;
189     int i;
190     IceAuthDataEntry *dataEntry;
191     IceAuthFileEntry *fileEntry;
192     IceAuthFileEntry newEntry;
193     IceAuthFileEntryList *fileEntryList = (IceAuthFileEntryList *)NULL;
194     IceAuthFileEntryList *fileEntryP;
195
196     if ((path = IceAuthFileName()) == (char *)NULL)
197         return 0;
198
199     if (IceLockAuthFile(path, AUTH_RETRIES, AUTH_TIMEOUT, AUTH_DEADTIME)
200         != IceAuthLockSuccess) {
201         /*
202          * Let's try another PATH, in case IceLockAuthFile's call to
203          * link() fails.  This workaround code was taken from 
204          * dtlogin/auth.c.
205          */
206         IceUnlockAuthFile(path);
207         extraPath = XtMalloc (MAXPATHLEN);
208         (void) strcpy (extraPath, CDE_CONFIGURATION_TOP ".ICEauthority");
209         if (IceLockAuthFile(extraPath, AUTH_RETRIES, AUTH_TIMEOUT, AUTH_DEADTIME)
210                 != IceAuthLockSuccess) {
211             IceUnlockAuthFile (extraPath);
212             return 0;
213          }
214          path = extraPath;
215     }
216
217     /* If file exists, read entries into memory. */
218     if (access(path, F_OK) == 0)
219     {
220         if ((fp = fopen(path, "rb")) == (FILE *)NULL)
221         {
222             IceUnlockAuthFile(path);
223             return 0;
224         }
225
226         /* For each file entry: if matches something in entries, discard. */
227         /* Otherwise, hold onto it - we'll be writing it back to file. */
228         while ((fileEntry = IceReadAuthFileEntry(fp))
229                != (IceAuthFileEntry *)NULL)
230         {
231             if (!fileEntryInDataEntries(nEntries, entries, fileEntry) &&
232                 !addToEntryList(&fileEntryList, fileEntry))
233             {
234                 freeEntryList(fileEntryList);
235                 IceUnlockAuthFile(path);
236                 fclose(fp);
237                 return 0;
238             }
239         }
240
241         fclose(fp);
242     }
243
244     /* Set umask to disallow non-owner access. */
245     oldUmask = umask(0077);
246
247     /* Write entries and fileEntryList to file. */
248     if ((fp = fopen(path, "wb")) == (FILE *)NULL)
249     {
250         freeEntryList(fileEntryList);
251         IceUnlockAuthFile(path);
252         umask(oldUmask);
253         return 0;
254     }
255
256     for (fileEntryP = fileEntryList;
257          fileEntryP != (IceAuthFileEntryList *)NULL;
258          fileEntryP = fileEntryP->next)
259     {
260         if (IceWriteAuthFileEntry(fp, fileEntryP->fileEntry) == 0)
261         {
262             fclose(fp);
263             umask(oldUmask);
264             freeEntryList(fileEntryList);
265             IceUnlockAuthFile(path);
266             return 0;
267         }
268     }
269
270     /* Done with fileEntryList - free it up. */
271     freeEntryList(fileEntryList);
272
273     if (!restore)
274     {
275         for (i = 0; i < nEntries; i++)
276         {
277             dataEntry = &(entries[i]);
278             newEntry.protocol_name = dataEntry->protocol_name;
279             newEntry.protocol_data_length = 0;
280             newEntry.protocol_data = "";
281             newEntry.network_id = dataEntry->network_id;
282             newEntry.auth_name = dataEntry->auth_name;
283             newEntry.auth_data_length = dataEntry->auth_data_length;
284             newEntry.auth_data = dataEntry->auth_data;
285
286             if (IceWriteAuthFileEntry(fp, &newEntry) == 0)
287             {
288                 fclose(fp);
289                 umask(oldUmask);
290                 IceUnlockAuthFile(path);
291                 return 0;
292             }
293         }
294     }
295
296     /* Success! */
297     fclose(fp);
298     umask(oldUmask);
299     IceUnlockAuthFile(path);
300     return 1;
301 }
302
303 /*
304  * Host Based Authentication Callback.  This callback is invoked if
305  * the connecting client can't offer any authentication methods that
306  * we can accept.  We can accept/reject based on the hostname.
307  */
308 Bool
309 HostBasedAuthProc (
310         char                    *hostname)
311
312 {
313     /* 
314      * For now, we don't support host based authentication 
315      */
316     return (0);       
317 }
318
319
320 /*
321  * Provide authentication data to clients that wish to connect
322  */
323 Status
324 SetAuthentication (
325         int                     count,
326         IceListenObj            *listenObjs,
327         IceAuthDataEntry        **authDataEntries)
328 {
329     int         i;
330     int         nEntries = count * 2;
331
332     if ((*authDataEntries = (IceAuthDataEntry *) XtMalloc (
333         nEntries * sizeof (IceAuthDataEntry))) == NULL)
334         return 0;
335
336     for (i = 0; i < nEntries; i += 2)
337     {
338         (*authDataEntries)[i].network_id =
339             IceGetListenConnectionString (listenObjs[i/2]);
340         (*authDataEntries)[i].protocol_name = "ICE";
341         (*authDataEntries)[i].auth_name = "MIT-MAGIC-COOKIE-1";
342
343         (*authDataEntries)[i].auth_data =
344             IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
345         (*authDataEntries)[i].auth_data_length = MAGIC_COOKIE_LEN;
346
347         (*authDataEntries)[i+1].network_id =
348             IceGetListenConnectionString (listenObjs[i/2]);
349         (*authDataEntries)[i+1].protocol_name = "XSMP";
350         (*authDataEntries)[i+1].auth_name = "MIT-MAGIC-COOKIE-1";
351
352         (*authDataEntries)[i+1].auth_data = 
353             IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
354         (*authDataEntries)[i+1].auth_data_length = MAGIC_COOKIE_LEN;
355
356         IceSetHostBasedAuthProc (listenObjs[i/2], HostBasedAuthProc);
357     }
358
359     /* Merge new entries into auth file. */
360     if (!writeIceauth(nEntries, *authDataEntries, 0))
361         return 0;
362
363     IceSetPaAuthData(nEntries, *authDataEntries);
364
365     return 1;
366 }
367
368 /*
369  * Free up authentication data.
370  */
371 void
372 FreeAuthenticationData (
373         int                     count,
374         IceAuthDataEntry        *authDataEntries)
375 {
376     int i;
377     int nEntries = count * 2;
378
379     /* Restore auth file to (approx) state before we ran.  We remove all */
380     /* new entries... some of these entries may have existed in the auth */
381     /* file before but were replaced when we came up. */
382     writeIceauth(nEntries, authDataEntries, 1);
383
384     /* Each transport has entries for ICE and XSMP */
385     for (i = 0; i < nEntries; i++)
386     {
387         free (authDataEntries[i].network_id);
388         free (authDataEntries[i].auth_data);
389     }
390
391     XtFree ((char *) authDataEntries);
392 }