Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtlogin / auth.c
1 /* $TOG: auth.c /main/6 1997/03/14 13:44:25 barstow $ */
2 /* (c) Copyright 1997 The Open Group */
3 /*                                                                      *
4  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
5  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
6  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
7  * (c) Copyright 1993, 1994 Novell, Inc.                                *
8  */
9
10 /*
11  * @DEC_COPYRIGHT@
12  */
13 /*
14  * HISTORY
15  * $Log$
16  * Revision 1.1.2.3  1995/06/06  20:21:58  Chris_Beute
17  *      Code snapshot merge from March 15 and SIA changes
18  *      [1995/05/31  20:09:58  Chris_Beute]
19  *
20  * Revision 1.1.2.2  1995/04/21  13:05:15  Peter_Derr
21  *      dtlogin auth key fixes from deltacde
22  *      [1995/04/12  19:20:51  Peter_Derr]
23  * 
24  *      R6 version of auth.c to handle multiple authentication protocols.
25  *      [1995/04/12  18:05:30  Peter_Derr]
26  * 
27  * $EndLog$
28  */
29
30 /*
31
32 Copyright (c) 1988  X Consortium
33
34 Permission is hereby granted, free of charge, to any person obtaining
35 a copy of this software and associated documentation files (the
36 "Software"), to deal in the Software without restriction, including
37 without limitation the rights to use, copy, modify, merge, publish,
38 distribute, sublicense, and/or sell copies of the Software, and to
39 permit persons to whom the Software is furnished to do so, subject to
40 the following conditions:
41
42 The above copyright notice and this permission notice shall be included
43 in all copies or substantial portions of the Software.
44
45 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
46 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
47 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
48 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
49 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
50 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
51 OTHER DEALINGS IN THE SOFTWARE.
52
53 Except as contained in this notice, the name of the X Consortium shall
54 not be used in advertising or otherwise to promote the sale, use or
55 other dealings in this Software without prior written authorization
56 from the X Consortium.
57
58 */
59
60 /*
61  * xdm - display manager daemon
62  * Author:  Keith Packard, MIT X Consortium
63  *
64  * auth.c
65  *
66  * maintain the authorization generation daemon
67  */
68
69 #include "dm.h"
70 #include "vgmsg.h"
71
72 #include <X11/X.h>
73 #include <sys/types.h>
74 #include <sys/stat.h>
75
76 #include <errno.h>
77 #ifdef X_NOT_STDC_ENV
78 extern int errno;
79 #endif
80
81 #include <sys/socket.h>
82 #ifndef ESIX
83 # include <sys/ioctl.h>
84 #endif /* !ESIX */
85
86 #ifdef TCPCONN
87 # include <netinet/in.h>
88 #endif
89 #ifdef DNETCONN
90 # include <netdnet/dn.h>
91 # include <netdnet/dnetdb.h>
92 #endif
93
94 #if (defined(_POSIX_SOURCE) && !defined(AIXV3)) || defined(hpux) || defined(USG) || defined(SVR4)
95 #define NEED_UTSNAME
96 #include <sys/utsname.h>
97 #endif
98
99 #if defined(SYSV) && defined(SYSV386)
100 # include <sys/stream.h>
101 # ifdef ISC
102 #  include <sys/sioctl.h>
103 # endif /* ISC */
104 # ifdef ESIX
105 #  include <lan/net_ioctl.h>
106 # endif /* ESIX */
107 #endif /* SYSV386 */
108
109 #ifdef SVR4
110 # include <netdb.h>
111 # include <sys/sockio.h>
112 #ifdef USL
113 # include <sys/stropts.h>
114 #endif
115 #endif
116 #ifdef __convex__
117 # include <sync/queue.h>
118 # include <sync/sema.h>
119 #endif
120 #include <net/if.h>
121
122 #ifdef SECURE_RPC
123 extern int      SecureRPCInitAuth ();
124 extern Xauth    *SecureRPCGetAuth ();
125 #endif
126
127 #ifdef K5AUTH
128 extern int      Krb5InitAuth ();
129 extern Xauth    *Krb5GetAuth ();
130 #endif
131
132 struct AuthProtocol {
133     unsigned short  name_length;
134     char            *name;
135
136     int             (*InitAuth)(
137 #if NeedWidePrototypes
138                         unsigned int name_len,
139 #else
140                         unsigned short name_len,
141 #endif /* NeedWidePrototypes */
142                         char *name) ;
143
144     Xauth           *(*GetAuth)(
145 #if NeedWidePrototypes
146                         unsigned int namelen,
147 #else
148                         unsigned short namelen,
149 #endif /* NeedWidePrototypes */
150                         char *name) ;
151
152     void            (*GetXdmcpAuth)();
153     int             inited;
154 };
155
156 static struct AuthProtocol AuthProtocols[] = {
157 { (unsigned short) 18,  "MIT-MAGIC-COOKIE-1",
158     MitInitAuth, MitGetAuth, NULL
159 },
160 #ifdef HASXDMAUTH
161 { (unsigned short) 19,  "XDM-AUTHORIZATION-1",
162     XdmInitAuth, XdmGetAuth, XdmGetXdmcpAuth,
163 },
164 #endif
165 #ifdef SECURE_RPC
166 { (unsigned short) 9, "SUN-DES-1",
167     SecureRPCInitAuth, SecureRPCGetAuth, NULL,
168 },
169 #endif
170 #ifdef K5AUTH
171 { (unsigned short) 14, "MIT-KERBEROS-5",
172     Krb5InitAuth, Krb5GetAuth, NULL,
173 },
174 #endif
175 };
176
177 #define NUM_AUTHORIZATION (sizeof (AuthProtocols) / sizeof (AuthProtocols[0]))
178
179 static struct AuthProtocol *
180 findProtocol (name_length, name)
181     unsigned short  name_length;
182     char            *name;
183 {
184     int i;
185
186     for (i = 0; i < NUM_AUTHORIZATION; i++)
187         if (AuthProtocols[i].name_length == name_length &&
188             memcmp(AuthProtocols[i].name, name, name_length) == 0)
189         {
190             return &AuthProtocols[i];
191         }
192     return (struct AuthProtocol *) 0;
193 }
194
195 ValidAuthorization (name_length, name)
196 #if NeedWidePrototypes
197     unsigned int  name_length;
198 #else
199     unsigned short  name_length;
200 #endif /* NeedWidePrototypes */
201     char            *name;
202 {
203     if (findProtocol (name_length, name))
204         return TRUE;
205     return FALSE;
206 }
207
208 static Xauth *
209 GenerateAuthorization (name_length, name)
210 unsigned short  name_length;
211 char            *name;
212 {
213     struct AuthProtocol *a;
214     Xauth   *auth = 0;
215     int     i;
216
217     Debug ("GenerateAuthorization %*.*s\n",
218             name_length, name_length, name);
219     a = findProtocol (name_length, name);
220     if (a)
221     {
222         if (!a->inited)
223         {
224             (*a->InitAuth) (name_length, name);
225             a->inited = TRUE;
226         }
227         auth = (*a->GetAuth) (name_length, name);
228         if (auth)
229         {
230             Debug ("Got 0x%x (%d %*.*s) ", auth,
231                 auth->name_length, auth->name_length,
232                 auth->name_length, auth->name);
233             for (i = 0; i < (int)auth->data_length; i++)
234                 Debug (" %02x", auth->data[i] & 0xff);
235             Debug ("\n");
236         }
237         else
238             Debug ("Got (null)\n");
239     }
240     else
241     {
242         Debug ("Unknown authorization %*.*s\n", name_length, name_length, name);
243     }
244     return auth;
245 }
246
247 void
248 SetProtoDisplayAuthorization (pdpy,
249     authorizationNameLen, authorizationName)
250     struct protoDisplay *pdpy;
251 #if NeedWidePrototypes
252     unsigned int        authorizationNameLen;
253 #else
254     unsigned short      authorizationNameLen;
255 #endif /* NeedWidePrototypes */
256     char                *authorizationName;
257 {
258     struct AuthProtocol *a;
259     Xauth   *auth;
260
261     a = findProtocol (authorizationNameLen, authorizationName);
262     pdpy->xdmcpAuthorization = pdpy->fileAuthorization = 0;
263     if (a)
264     {
265         if (!a->inited)
266         {
267             (*a->InitAuth) (authorizationNameLen, authorizationName);
268             a->inited = TRUE;
269         }
270         if (a->GetXdmcpAuth)
271         {
272             (*a->GetXdmcpAuth) (pdpy, authorizationNameLen, authorizationName);
273             auth = pdpy->xdmcpAuthorization;
274         }
275         else
276         {
277             auth = (*a->GetAuth) (authorizationNameLen, authorizationName);
278             pdpy->fileAuthorization = auth;
279             pdpy->xdmcpAuthorization = 0;
280         }
281         if (auth)
282             Debug ("Got 0x%x (%d %*.*s)\n", auth,
283                 auth->name_length, auth->name_length,
284                 auth->name_length, auth->name);
285         else
286             Debug ("Got (null)\n");
287     }
288 }
289
290 void
291 CleanUpFileName (src, dst, len)
292     char *src, *dst;
293     int  len;
294 {
295     while (*src) {
296         if (--len <= 0)
297                 break;
298         switch (*src & 0x7f)
299         {
300         case '/':
301             *dst++ = '_';
302             break;
303         case '-':
304             *dst++ = '.';
305             break;
306         default:
307             *dst++ = (*src & 0x7f);
308         }
309         ++src;
310     }
311     *dst = '\0';
312 }
313
314 static char authdir1[] = "authdir";
315 static char authdir2[] = "authfiles";
316
317 static
318 MakeServerAuthFile (d)
319     struct display  *d;
320 {
321     int len;
322 #ifdef SYSV
323 #define NAMELEN 14
324 #else
325 #define NAMELEN 255
326 #endif
327     char    cleanname[NAMELEN];
328     int r;
329     struct stat statb;
330
331     if (d->clientAuthFile && *d->clientAuthFile)
332         len = strlen (d->clientAuthFile) + 1;
333     else
334     {
335         CleanUpFileName (d->name, cleanname, NAMELEN - 8);
336         len = strlen (authDir) + strlen (authdir1) + strlen (authdir2)
337             + strlen (cleanname) + 14;
338     }
339     if (d->authFile)
340         free (d->authFile);
341     d->authFile = malloc ((unsigned) len);
342     if (!d->authFile)
343         return FALSE;
344     if (d->clientAuthFile && *d->clientAuthFile)
345         strcpy (d->authFile, d->clientAuthFile);
346     else
347     {
348         sprintf (d->authFile, "%s/%s", authDir, authdir1);
349         r = stat(d->authFile, &statb);
350         if (r == 0) {
351             if (statb.st_uid != 0)
352                 (void) chown(d->authFile, 0, statb.st_gid);
353             if ((statb.st_mode & 0077) != 0)
354                 (void) chmod(d->authFile, statb.st_mode & 0700);
355         } else {
356             if (errno == ENOENT)
357                 r = mkdir(d->authFile, 0700);
358             if (r < 0) {
359                 free (d->authFile);
360                 d->authFile = NULL;
361                 return FALSE;
362             }
363         }
364         sprintf (d->authFile, "%s/%s/%s", authDir, authdir1, authdir2);
365         r = mkdir(d->authFile, 0700);
366         if (r < 0  &&  errno != EEXIST) {
367             free (d->authFile);
368             d->authFile = NULL;
369             return FALSE;
370         }
371         sprintf (d->authFile, "%s/%s/%s/A%s-XXXXXX",
372                  authDir, authdir1, authdir2, cleanname);
373         (void) mktemp (d->authFile);
374     }
375     return TRUE;
376 }
377
378 SaveServerAuthorizations (d, auths, count)
379     struct display  *d;
380     Xauth           **auths;
381     int             count;
382 {
383     FILE        *auth_file;
384     int         mask;
385     int         ret;
386     int         i;
387
388     mask = umask (0077);
389     if (!d->authFile && !MakeServerAuthFile (d))
390         return FALSE;
391     (void) unlink (d->authFile);
392     auth_file = fopen (d->authFile, "w");
393     umask (mask);
394     if (!auth_file) {
395         Debug ("Can't creat auth file %s\n", d->authFile);
396         LogError (ReadCatalog(MC_LOG_SET,MC_LOG_SRV_OPEN,MC_DEF_LOG_SRV_OPEN),
397                   d->authFile);
398         free (d->authFile);
399         d->authFile = NULL;
400         ret = FALSE;
401     }
402     else
403     {
404         Debug ("File: %s auth: %x\n", d->authFile, auths);
405         ret = TRUE;
406         for (i = 0; i < count; i++)
407         {
408             /*
409              * User-based auths may not have data until
410              * a user logs in.  In which case don't write
411              * to the auth file so xrdb and setup programs don't fail.
412              */
413             if (auths[i]->data_length > 0)
414                 if (!XauWriteAuth (auth_file, auths[i]) ||
415                     fflush (auth_file) == EOF)
416                 {
417                     LogError (
418                       ReadCatalog(MC_LOG_SET,MC_LOG_SRV_WRT,MC_DEF_LOG_SRV_WRT),
419                           d->authFile);
420                     ret = FALSE;
421                     free (d->authFile);
422                     d->authFile = NULL;
423                 }
424         }
425         fclose (auth_file);
426     }
427     return ret;
428 }
429
430 void
431 SetLocalAuthorization (d)
432     struct display      *d;
433 {
434     Xauth       *auth, **auths;
435     int         i, j;
436
437     if (d->authorizations)
438     {
439         for (i = 0; i < d->authNum; i++)
440             XauDisposeAuth (d->authorizations[i]);
441         free ((char *) d->authorizations);
442         d->authorizations = (Xauth **) NULL;
443         d->authNum = 0;
444     }
445     if (!d->authNames)
446         return;
447     for (i = 0; d->authNames[i]; i++)
448         ;
449     d->authNameNum = i;
450     if (d->authNameLens)
451         free ((char *) d->authNameLens);
452     d->authNameLens = (unsigned short *) malloc
453                                 (d->authNameNum * sizeof (unsigned short));
454     if (!d->authNameLens)
455         return;
456     for (i = 0; i < d->authNameNum; i++)
457         d->authNameLens[i] = strlen (d->authNames[i]);
458     auths = (Xauth **) malloc (d->authNameNum * sizeof (Xauth *));
459     if (!auths)
460         return;
461     j = 0;
462     for (i = 0; i < d->authNameNum; i++)
463     {
464         auth = GenerateAuthorization (d->authNameLens[i], d->authNames[i]);
465         if (auth)
466             auths[j++] = auth;
467     }
468     if (SaveServerAuthorizations (d, auths, j))
469     {
470         d->authorizations = auths;
471         d->authNum = j;
472     }
473     else
474     {
475         for (i = 0; i < j; i++)
476             XauDisposeAuth (auths[i]);
477         free ((char *) auths);
478     }
479 }
480
481 /*
482  * Set the authorization to use for xdm's initial connection
483  * to the X server.  Cannot use user-based authorizations
484  * because no one has logged in yet, so we don't have any
485  * user credentials.
486  * Well, actually we could use SUN-DES-1 because we tell the server
487  * to allow root in.  This is bogus and should be fixed.
488  */
489 void 
490 SetAuthorization (d)
491     struct display  *d;
492 {
493     register Xauth **auth = d->authorizations;
494     int i;
495
496     for (i = 0; i < d->authNum; i++)
497     {
498         if (auth[i]->name_length == 9 &&
499             memcmp(auth[i]->name, "SUN-DES-1", 9) == 0)
500             continue;
501         if (auth[i]->name_length == 14 &&
502             memcmp(auth[i]->name, "MIT-KERBEROS-5", 14) == 0)
503             continue;
504         XSetAuthorization (auth[i]->name, (int) auth[i]->name_length,
505                            auth[i]->data, (int) auth[i]->data_length);
506     }
507 }
508
509 static
510 openFiles (name, new_name, oldp, newp)
511 char    *name, *new_name;
512 FILE    **oldp, **newp;
513 {
514         int     mask;
515         int     null_data = 0;
516
517         strcpy (new_name, name);
518         strcat (new_name, "-n");
519         mask = umask (0077);
520         (void) unlink (new_name);
521         *newp = fopen (new_name, "w");
522         (void) umask (mask);
523         if (!*newp) {
524                 Debug ("can't open new file %s\n", new_name);
525                 return 0;
526         }
527         /*
528          * Make sure that the device is not 100% full by actually writing
529          * to the file.
530          */
531         if ((sizeof(int) != fwrite(&null_data, 1, sizeof(int), *newp))
532            || fflush(*newp)) {
533                 Debug ("can't write to new file %s\n", new_name);
534                 fclose(*newp);
535                 (void) unlink (new_name);
536                 return 0;
537         }
538         rewind(*newp);
539         *oldp = fopen (name, "r");
540         Debug ("opens succeeded %s %s\n", name, new_name);
541         return 1;
542 }
543
544 static
545 binaryEqual (a, b, len)
546 char    *a, *b;
547 unsigned short  len;
548 {
549         while (len-- > 0)
550                 if (*a++ != *b++)
551                         return 0;
552         return 1;
553 }
554
555 static
556 dumpBytes (len, data)
557 unsigned short  len;
558 char    *data;
559 {
560         unsigned short  i;
561
562         Debug ("%d: ", len);
563         for (i = 0; i < len; i++)
564                 Debug ("%02x ", data[i] & 0377);
565         Debug ("\n");
566 }
567
568 static
569 dumpAuth (auth)
570     Xauth       *auth;
571 {
572         Debug ("family: %d\n", auth->family);
573         Debug ("addr:   ");
574         dumpBytes (auth->address_length, auth->address);
575         Debug ("number: ");
576         dumpBytes (auth->number_length, auth->number);
577         Debug ("name:   ");
578         dumpBytes (auth->name_length, auth->name);
579         Debug ("data:   ");
580         dumpBytes (auth->data_length, auth->data);
581 }
582
583 struct addrList {
584         unsigned short  family;
585         unsigned short  address_length;
586         char    *address;
587         unsigned short  number_length;
588         char    *number;
589         unsigned short  name_length;
590         char    *name;
591         struct addrList *next;
592 };
593
594 static struct addrList  *addrs;
595
596 static
597 initAddrs ()
598 {
599         addrs = 0;
600 }
601
602 static
603 doneAddrs ()
604 {
605         struct addrList *a, *n;
606         for (a = addrs; a; a = n) {
607                 n = a->next;
608                 if (a->address)
609                         free (a->address);
610                 if (a->number)
611                         free (a->number);
612                 free ((char *) a);
613         }
614 }
615
616 static checkEntry ();
617
618 static void
619 saveEntry (auth)
620     Xauth       *auth;
621 {
622         struct addrList *new;
623
624         new = (struct addrList *) malloc (sizeof (struct addrList));
625         if (!new) {
626                 LogOutOfMem (ReadCatalog(
627                         MC_LOG_SET,MC_LOG_SAVE_ADDR,MC_DEF_LOG_SAVE_ADDR));
628                 return;
629         }
630         if ((new->address_length = auth->address_length) > 0) {
631                 new->address = malloc (auth->address_length);
632                 if (!new->address) {
633                         LogOutOfMem (ReadCatalog(
634                             MC_LOG_SET,MC_LOG_SAVE_ADDR,MC_DEF_LOG_SAVE_ADDR));
635                         free ((char *) new);
636                         return;
637                 }
638                 memmove( new->address, auth->address, (int) auth->address_length);
639         } else
640                 new->address = 0;
641         if ((new->number_length = auth->number_length) > 0) {
642                 new->number = malloc (auth->number_length);
643                 if (!new->number) {
644                         LogOutOfMem (ReadCatalog(
645                             MC_LOG_SET,MC_LOG_SAVE_ADDR,MC_DEF_LOG_SAVE_ADDR));
646                         free (new->address);
647                         free ((char *) new);
648                         return;
649                 }
650                 memmove( new->number, auth->number, (int) auth->number_length);
651         } else
652                 new->number = 0;
653         if ((new->name_length = auth->name_length) > 0) {
654                 new->name = malloc (auth->name_length);
655                 if (!new->name) {
656                         LogOutOfMem (ReadCatalog(
657                             MC_LOG_SET,MC_LOG_SAVE_ADDR,MC_DEF_LOG_SAVE_ADDR));
658                         free (new->number);
659                         free (new->address);
660                         free ((char *) new);
661                         return;
662                 }
663                 memmove( new->name, auth->name, (int) auth->name_length);
664         } else
665                 new->name = 0;
666         new->family = auth->family;
667         new->next = addrs;
668         addrs = new;
669 }
670
671 static
672 checkEntry (auth)
673     Xauth       *auth;
674 {
675         struct addrList *a;
676
677         for (a = addrs; a; a = a->next) {
678                 if (a->family == auth->family &&
679                     a->address_length == auth->address_length &&
680                     binaryEqual (a->address, auth->address, auth->address_length) &&
681                     a->number_length == auth->number_length &&
682                     binaryEqual (a->number, auth->number, auth->number_length) &&
683                     a->name_length == auth->name_length &&
684                     binaryEqual (a->name, auth->name, auth->name_length))
685                 {
686                         return 1;
687                 }
688         }
689         return 0;
690 }
691
692 static int  doWrite;
693
694 static
695 writeAuth (file, auth)
696     FILE        *file;
697     Xauth       *auth;
698 {
699     if (debugLevel >= 15) {     /* normally too verbose */
700         Debug ("writeAuth: doWrite = %d\n", doWrite);
701         dumpAuth (auth);        /* does Debug only */
702     }
703     
704     if (doWrite)
705         if (!XauWriteAuth (file, auth) || fflush (file) == EOF)  {
706                 LogError(
707                     ReadCatalog(MC_LOG_SET,MC_LOG_SRV_WRT,MC_DEF_LOG_SRV_WRT),
708                     file);
709                 return 0;
710         }
711         else
712                 return 1;
713 }
714
715 static
716 writeAddr (family, addr_length, addr, file, auth)
717     int         family;
718     int         addr_length;
719     char        *addr;
720     FILE        *file;
721     Xauth       *auth;
722 {
723         auth->family = (unsigned short) family;
724         auth->address_length = addr_length;
725         auth->address = addr;
726         Debug ("writeAddr: writing and saving an entry\n");
727         writeAuth (file, auth);
728         saveEntry (auth);
729 }
730
731 static
732 DefineLocal (file, auth)
733     FILE        *file;
734     Xauth       *auth;
735 {
736         char    displayname[100];
737
738         /* stolen from xinit.c */
739
740 /* Make sure this produces the same string as _XGetHostname in lib/X/XlibInt.c.
741  * Otherwise, Xau will not be able to find your cookies in the Xauthority file.
742  *
743  * Note: POSIX says that the ``nodename'' member of utsname does _not_ have
744  *       to have sufficient information for interfacing to the network,
745  *       and so, you may be better off using gethostname (if it exists).
746  */
747
748 #ifdef NEED_UTSNAME
749
750         /* hpux:
751          * Why not use gethostname()?  Well, at least on my system, I've had to
752          * make an ugly kernel patch to get a name longer than 8 characters, and
753          * uname() lets me access to the whole string (it smashes release, you
754          * see), whereas gethostname() kindly truncates it for me.
755          */
756         {
757         struct utsname name;
758
759         uname(&name);
760         strcpy(displayname, name.nodename);
761         }
762         writeAddr (FamilyLocal, strlen (displayname), displayname, file, auth);
763 #endif
764
765 #if (!defined(NEED_UTSNAME) || defined (hpux))
766         /* AIXV3:
767          * In AIXV3, _POSIX_SOURCE is defined, but uname gives only first
768          * field of hostname. Thus, we use gethostname instead.
769          */
770
771         /*
772          * For HP-UX, HP's Xlib expects a fully-qualified domain name, which
773          * is achieved by using gethostname().  For compatability, we must
774          * also still create the entry using uname() above.
775          */
776
777         gethostname(displayname, sizeof(displayname));
778         writeAddr (FamilyLocal, strlen (displayname), displayname, file, auth);
779 #endif
780 }
781
782 #ifdef USL
783 /* Deal with different SIOCGIFCONF ioctl semantics on UnixWare */
784 static int
785 ifioctl (fd, cmd, arg)
786     int fd;
787     int cmd;
788     char *arg;
789 {
790     struct strioctl ioc;
791     int ret;
792
793     bzero((char *) &ioc, sizeof(ioc));
794     ioc.ic_cmd = cmd;
795     ioc.ic_timout = 0;
796     if (cmd == SIOCGIFCONF)
797     {
798         ioc.ic_len = ((struct ifconf *) arg)->ifc_len;
799         ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf;
800     }
801     else
802     {
803         ioc.ic_len = sizeof(struct ifreq);
804         ioc.ic_dp = arg;
805     }
806     ret = ioctl(fd, I_STR, (char *) &ioc);
807     if (ret >= 0 && cmd == SIOCGIFCONF)
808         ((struct ifconf *) arg)->ifc_len = ioc.ic_len;
809     return(ret);
810 }
811 #endif /* USL */
812
813
814 #ifdef WINTCP /* NCR with Wollongong TCP */
815
816 #include <sys/un.h>
817 #include <stropts.h>
818 #include <tiuser.h>
819
820 #include <sys/stream.h>
821 #include <net/if.h>
822 #include <netinet/ip.h>
823 #include <netinet/ip_var.h>
824 #include <netinet/in.h>
825 #include <netinet/in_var.h>
826
827 static
828 DefineSelf (fd, file, auth)
829     int fd;
830     FILE        *file;
831     Xauth       *auth;
832 {
833     /*
834      * The Wolongong drivers used by NCR SVR4/MP-RAS don't understand the
835      * socket IO calls that most other drivers seem to like. Because of
836      * this, this routine must be special cased for NCR. Eventually,
837      * this will be cleared up.
838      */
839
840     struct ipb ifnet;
841     struct in_ifaddr ifaddr;
842     struct strioctl str;
843     unsigned char *addr;
844     int family, len, ipfd;
845
846     if ((ipfd = open ("/dev/ip", O_RDWR, 0 )) < 0)
847         LogError ((unsigned char *)"Getting interface configuration");
848
849     /* Indicate that we want to start at the begining */
850     ifnet.ib_next = (struct ipb *) 1;
851
852     while (ifnet.ib_next)
853     {
854         str.ic_cmd = IPIOC_GETIPB;
855         str.ic_timout = 0;
856         str.ic_len = sizeof (struct ipb);
857         str.ic_dp = (char *) &ifnet;
858
859         if (ioctl (ipfd, (int) I_STR, (char *) &str) < 0)
860         {
861             close (ipfd);
862             LogError ((unsigned char *) "Getting interface configuration");
863         }
864
865         ifaddr.ia_next = (struct in_ifaddr *) ifnet.if_addrlist;
866         str.ic_cmd = IPIOC_GETINADDR;
867         str.ic_timout = 0;
868         str.ic_len = sizeof (struct in_ifaddr);
869         str.ic_dp = (char *) &ifaddr;
870
871         if (ioctl (ipfd, (int) I_STR, (char *) &str) < 0)
872         {
873             close (ipfd);
874             LogError ((unsigned char *) "Getting interface configuration");
875         }
876
877         /*
878          * Ignore the 127.0.0.1 entry.
879          */
880         if (IA_SIN(&ifaddr)->sin_addr.s_addr == htonl(0x7f000001) )
881                 continue;
882
883         writeAddr (FamilyInternet, 4, (char *)&(IA_SIN(&ifaddr)->sin_addr), file, auth);
884  
885     }
886     close(ipfd);
887
888 }
889
890 #else /* WINTCP */
891
892 #ifdef SIOCGIFCONF
893 #ifdef __osf__
894 #define DECnetInstalled (0 == access("/usr/shlib/libdnet.so", F_OK))
895 #else
896     /* think of something... */
897 #define DECnetInstalled True
898 #endif /* __osf __ */
899
900 /* Define this host for access control.  Find all the hosts the OS knows about 
901  * for this fd and add them to the selfhosts list.
902  */
903 static
904 #ifdef __osf__
905 DefineSelf (fd, file, auth, addr_family)
906 #else
907 DefineSelf (fd, file, auth)
908 #endif /* __osf__*/
909     int fd;
910     FILE        *file;
911     Xauth       *auth;
912 {
913     char                buf[2048];
914     struct ifconf       ifc;
915     register int        n;
916     int                 len;
917     char                *addr;
918     int                 family;
919     register struct ifreq *ifr;
920     
921     ifc.ifc_len = sizeof (buf);
922     ifc.ifc_buf = buf;
923
924 #ifdef USL
925     if (ifioctl (fd, SIOCGIFCONF, (char *) &ifc) < 0)
926 #else
927     if (ioctl (fd, SIOCGIFCONF, (char *) &ifc) < 0)
928 #endif
929 #ifdef __osf__
930         switch (addr_family)
931             {
932 #ifdef TCPCONN
933             case AF_INET:
934                 perror("xdm");
935                 LogError ((unsigned char *)"Trouble getting Internet network interface configuration\n");
936                 break;
937 #endif
938 #ifdef DNETCONN
939             case AF_DECnet:
940                 if (DECnetInstalled)
941                     LogError ((unsigned char *)"Trouble getting DECnet network interface configuration\n");
942                 break;
943 #endif
944             default:
945                 LogError ((unsigned char *)"Trouble getting network interface configuration\n");
946             }
947 #else
948         LogError ((unsigned char *)"Trouble getting network interface configuration");
949 #endif /* __osf__ */
950
951     for (ifr = ifc.ifc_req
952 #if defined(BSD44SOCKETS) || defined(CSRG_BASED)
953          ; (char *)ifr < ifc.ifc_buf + ifc.ifc_len;
954          ifr = (struct ifreq *)((char *)ifr + sizeof (struct ifreq) +
955                    (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr) ?
956                     ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr) : 0))
957 #else
958          , n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++
959 #endif
960          )
961     {
962 #ifdef DNETCONN
963         /*
964          * this is ugly but SIOCGIFCONF returns decnet addresses in
965          * a different form from other decnet calls
966          */
967         if (ifr->ifr_addr.sa_family == AF_DECnet) {
968                 len = sizeof (struct dn_naddr);
969                 addr = (char *)ifr->ifr_addr.sa_data;
970                 family = FamilyDECnet;
971         } else
972 #endif
973         {
974             if (ConvertAddr ((XdmcpNetaddr) &ifr->ifr_addr, &len, &addr) < 0)
975                 continue;
976             if (len == 0)
977             {
978                 Debug ("Skipping zero length address\n");
979                 continue;
980             }
981             /*
982              * don't write out 'localhost' entries, as
983              * they may conflict with other local entries.
984              * DefineLocal will always be called to add
985              * the local entry anyway, so this one can
986              * be tossed.
987              */
988             if (len == 4 &&
989                 addr[0] == 127 && addr[1] == 0 &&
990                 addr[2] == 0 && addr[3] == 1)
991             {
992                     Debug ("Skipping localhost address\n");
993                     continue;
994             }
995             family = FamilyInternet;
996         }
997         Debug ("DefineSelf: write network address, length %d\n", len);
998         writeAddr (family, len, addr, file, auth);
999     }
1000 }
1001
1002 #else /* SIOCGIFCONF */
1003
1004 /* Define this host for access control.  Find all the hosts the OS knows about 
1005  * for this fd and add them to the selfhosts list.
1006  */
1007 static
1008 DefineSelf (fd, file, auth)
1009     int fd;
1010 {
1011     register int n;
1012     int len;
1013     caddr_t     addr;
1014     int         family;
1015
1016     struct utsname name;
1017     register struct hostent  *hp;
1018
1019     union {
1020         struct  sockaddr   sa;
1021         struct  sockaddr_in  in;
1022     } saddr;
1023         
1024     struct      sockaddr_in     *inetaddr;
1025
1026     /* hpux:
1027      * Why not use gethostname()?  Well, at least on my system, I've had to
1028      * make an ugly kernel patch to get a name longer than 8 characters, and
1029      * uname() lets me access to the whole string (it smashes release, you
1030      * see), whereas gethostname() kindly truncates it for me.
1031      */
1032     uname(&name);
1033     hp = gethostbyname (name.nodename);
1034     if (hp != NULL) {
1035         saddr.sa.sa_family = hp->h_addrtype;
1036         inetaddr = (struct sockaddr_in *) (&(saddr.sa));
1037         memmove( (char *) &(inetaddr->sin_addr), (char *) hp->h_addr, (int) hp->h_length);
1038         family = ConvertAddr ( &(saddr.sa), &len, &addr);
1039         if ( family >= 0) {
1040             writeAddr (FamilyInternet, sizeof (inetaddr->sin_addr),
1041                         (char *) (&inetaddr->sin_addr), file, auth);
1042         }
1043     }
1044 }
1045
1046 #endif /* SIOCGIFCONF else */
1047
1048 #endif /* WINTCP */
1049
1050
1051 static
1052 setAuthNumber (auth, name)
1053     Xauth   *auth;
1054     char    *name;
1055 {
1056     char        *colon;
1057     char        *dot, *number;
1058
1059     Debug ("setAuthNumber %s\n", name);
1060     colon = strrchr(name, ':');
1061     if (colon) {
1062         ++colon;
1063         dot = strchr(colon, '.');
1064         if (dot)
1065             auth->number_length = dot - colon;
1066         else
1067             auth->number_length = strlen (colon);
1068         number = malloc (auth->number_length + 1);
1069         if (number) {
1070             strncpy (number, colon, auth->number_length);
1071             number[auth->number_length] = '\0';
1072         } else {
1073             LogOutOfMem (ReadCatalog(
1074                 MC_LOG_SET,MC_LOG_NET_CFG,MC_DEF_LOG_NET_CFG));
1075             auth->number_length = 0;
1076         }
1077         auth->number = number;
1078         Debug ("setAuthNumber: %s\n", number);
1079     }
1080 }
1081
1082 static
1083 writeLocalAuth (file, auth, name)
1084     FILE        *file;
1085     Xauth       *auth;
1086     char        *name;
1087 {
1088     int fd;
1089
1090     Debug ("writeLocalAuth: %s %.*s\n", name, auth->name_length, auth->name);
1091     setAuthNumber (auth, name);
1092 #ifdef STREAMSCONN
1093     fd = t_open ("/dev/tcp", O_RDWR, 0);
1094     t_bind(fd, NULL, NULL);
1095     DefineSelf (fd, file, auth);
1096     t_unbind (fd);
1097     t_close (fd);
1098 #endif
1099 #ifdef TCPCONN
1100     fd = socket (AF_INET, SOCK_STREAM, 0);
1101     DefineSelf (fd, file, auth);
1102     close (fd);
1103 #endif
1104 #ifdef DNETCONN
1105     fd = socket (AF_DECnet, SOCK_STREAM, 0);
1106     DefineSelf (fd, file, auth);
1107     close (fd);
1108 #endif
1109     DefineLocal (file, auth);
1110 }
1111
1112 #ifdef XDMCP
1113
1114 static void
1115 writeRemoteAuth (file, auth, peer, peerlen, name)
1116     FILE            *file;
1117     Xauth           *auth;
1118     XdmcpNetaddr    peer;
1119     int             peerlen;
1120     char            *name;
1121 {
1122     int     family = FamilyLocal;
1123     char    *addr;
1124     
1125     Debug ("writeRemoteAuth: %s %.*s\n", name, auth->name_length, auth->name);
1126     if (!peer || peerlen < 2)
1127         return;
1128     setAuthNumber (auth, name);
1129     family = ConvertAddr (peer, &peerlen, &addr);
1130     Debug ("writeRemoteAuth: family %d\n", family);
1131     if (family != FamilyLocal)
1132     {
1133         Debug ("writeRemoteAuth: %d, %d, %x\n",
1134                 family, peerlen, *(int *)addr);
1135         writeAddr (family, peerlen, addr, file, auth);
1136     }
1137     else
1138     {
1139         writeLocalAuth (file, auth, name);
1140     }
1141 }
1142
1143 #endif /* XDMCP */
1144
1145 void
1146 SetUserAuthorization (d, verify)
1147     struct display              *d;
1148     struct verify_info  *verify;
1149 {
1150     FILE        *old, *new;
1151     char        home_name[1024], backup_name[1024], new_name[1024];
1152     char        *name;
1153     char        *home;
1154     char        *envname = 0;
1155     int lockStatus;
1156     Xauth       *entry, **auths;
1157     int setenv;
1158     char        **setEnv (), *getEnv ();
1159     struct stat statb;
1160     int         i;
1161     int         magicCookie;
1162     int         data_len;
1163
1164     Debug ("SetUserAuthorization\n");
1165     auths = d->authorizations;
1166     if (auths) {
1167         home = getEnv (verify->userEnviron, "HOME");
1168         lockStatus = LOCK_ERROR;
1169         if (home) {
1170             strcpy (home_name, home);
1171             if (home[strlen(home) - 1] != '/')
1172                 strcat (home_name, "/");
1173             strcat (home_name, ".Xauthority");
1174             Debug ("XauLockAuth %s\n", home_name);
1175             lockStatus = XauLockAuth (home_name, 1, 2, 10);
1176             Debug ("Lock is %d\n", lockStatus);
1177             if (lockStatus == LOCK_SUCCESS) {
1178                 if (openFiles (home_name, new_name, &old, &new)) {
1179                     name = home_name;
1180                     setenv = 0;
1181                 } else {
1182                     Debug ("openFiles failed\n");
1183                     XauUnlockAuth (home_name);
1184                     lockStatus = LOCK_ERROR;
1185                 }       
1186             }
1187         }
1188         if (lockStatus != LOCK_SUCCESS) {
1189             sprintf (backup_name, "%s/.XauthXXXXXX", d->userAuthDir);
1190             (void) mktemp (backup_name);
1191             Debug ("XauLockAuth %s\n", backup_name);
1192             lockStatus = XauLockAuth (backup_name, 1, 2, 10);
1193             Debug ("backup lock is %d\n", lockStatus);
1194             if (lockStatus == LOCK_SUCCESS) {
1195                 if (openFiles (backup_name, new_name, &old, &new)) {
1196                     name = backup_name;
1197                     setenv = 1;
1198                 } else {
1199                     XauUnlockAuth (backup_name);
1200                     lockStatus = LOCK_ERROR;
1201                 }       
1202             }
1203             /*
1204              * Won't be using this file so unlock it.
1205              */
1206             XauUnlockAuth (home_name);
1207         }
1208         if (lockStatus != LOCK_SUCCESS) {
1209             Debug ("can't lock auth file %s or backup %s\n",
1210                             home_name, backup_name);
1211             LogError (ReadCatalog
1212                          (MC_LOG_SET,MC_LOG_LCK_AUTH,MC_DEF_LOG_LCK_AUTH),
1213                          home_name, backup_name);
1214             return;
1215         }
1216         initAddrs ();
1217         doWrite = 1;
1218         Debug ("%d authorization protocols for %s\n", d->authNum, d->name);
1219         /*
1220          * Write MIT-MAGIC-COOKIE-1 authorization first, so that
1221          * R4 clients which only knew that, and used the first
1222          * matching entry will continue to function
1223          */
1224         magicCookie = -1;
1225         for (i = 0; i < d->authNum; i++)
1226         {
1227             if (auths[i]->name_length == 18 &&
1228                 !strncmp (auths[i]->name, "MIT-MAGIC-COOKIE-1", 18))
1229             {
1230                 magicCookie = i;
1231                 if (d->displayType.location == Local)
1232                     writeLocalAuth (new, auths[i], d->name);
1233 #ifdef XDMCP
1234                 else
1235                     writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
1236 #endif
1237                 break;
1238             }
1239         }
1240         /* now write other authorizations */
1241         for (i = 0; i < d->authNum; i++)
1242         {
1243             Debug("SetUserAuthorization: checking authorization # %d\n", i+1);
1244             if (i != magicCookie)
1245             {
1246                 data_len = auths[i]->data_length;
1247                 /* client will just use default Kerberos cache, so don't
1248                  * even write cache info into the authority file.
1249                  */
1250                 if (auths[i]->name_length == 14 &&
1251                     !strncmp (auths[i]->name, "MIT-KERBEROS-5", 14))
1252                     auths[i]->data_length = 0;
1253                 if (d->displayType.location == Local)
1254                     writeLocalAuth (new, auths[i], d->name);
1255 #ifdef XDMCP
1256                 else
1257                     writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
1258 #endif
1259                 auths[i]->data_length = data_len;
1260             }
1261         }
1262         Debug ("SetUserAuthorization: old = %x\n", old);
1263         if (old) {
1264             if (fstat (fileno (old), &statb) != -1)
1265                 chmod (new_name, (int) (statb.st_mode & 0777));
1266             /*SUPPRESS 560*/
1267             while (entry = XauReadAuth (old)) {
1268                 if (!checkEntry (entry))
1269                 {
1270                     Debug ("Writing an entry\n");
1271                     writeAuth (new, entry);
1272                 }
1273                 XauDisposeAuth (entry);
1274             }
1275             fclose (old);
1276         }
1277         doneAddrs ();
1278         fclose (new);
1279         Debug ("SetUserAuthorization: name     = %s\n", name);
1280         Debug ("SetUserAuthorization: new_name = %s\n", new_name);
1281         Debug ("SetUserAuthorization: unlink(%s)\n", name);
1282         if (unlink (name) == -1)
1283             Debug ("SetUserAuthorization: unlink(%s) failed!\n", name);
1284         envname = name;
1285         if (link (new_name, name) == -1) {
1286             Debug ("link failed %s %s\n", new_name, name);
1287             LogError (
1288                 ReadCatalog(MC_LOG_SET,MC_LOG_NOT_AUTH,MC_DEF_LOG_NOT_AUTH));
1289             setenv = 1;
1290             envname = new_name;
1291         } else {
1292             Debug ("SetUserAuthorization: link(%s,%s) OK\n", new_name, name);
1293             Debug ("SetUserAuthorization: unlink(%s)\n", new_name);
1294             unlink (new_name);
1295         }
1296         if (setenv) {
1297             Debug ("SetUserAuthorization: setenv(XAUTHORITY=%s)\n", envname);
1298             verify->userEnviron = setEnv (verify->userEnviron,
1299                                     "XAUTHORITY", envname);
1300             verify->systemEnviron = setEnv (verify->systemEnviron,
1301                                     "XAUTHORITY", envname);
1302         }
1303         Debug ("SetUserAuthorization: XauUnLockAuth(%s)\n", name);
1304         XauUnlockAuth (name);
1305         Debug ("SetUserAuthorization: envname = %s\n", envname);
1306         if (envname) {
1307 #ifdef NGROUPS
1308             Debug ("SetUserAuthorization: chown(%s,%d,%d)\n",
1309                    envname, verify->uid, verify->groups[0]);
1310             chown (envname, verify->uid, verify->groups[0]);
1311 #else
1312             Debug ("SetUserAuthorization: chown(%s,%d,%d)\n",
1313                    envname, verify->uid, verify->gid);
1314             chown (envname, verify->uid, verify->gid);
1315 #endif /* NGROUPS */
1316         }
1317     }
1318     Debug ("done SetUserAuthorization\n");
1319 }
1320
1321 void
1322 RemoveUserAuthorization (d, verify)
1323     struct display      *d;
1324     struct verify_info  *verify;
1325 {
1326     char    *home;
1327     Xauth   **auths, *entry;
1328     char    name[1024], new_name[1024];
1329     int     lockStatus;
1330     FILE    *old, *new;
1331     struct stat statb;
1332     int     i;
1333     char    *getEnv ();
1334
1335     if (!(auths = d->authorizations))
1336         return;
1337     home = getEnv (verify->userEnviron, "HOME");
1338     if (!home)
1339         return;
1340     Debug ("RemoveUserAuthorization\n");
1341     strcpy (name, home);
1342     if (home[strlen(home) - 1] != '/')
1343         strcat (name, "/");
1344     strcat (name, ".Xauthority");
1345     Debug ("XauLockAuth %s\n", name);
1346     lockStatus = XauLockAuth (name, 1, 2, 10);
1347     Debug ("Lock is %d\n", lockStatus);
1348     if (lockStatus != LOCK_SUCCESS)
1349         return;
1350     if (openFiles (name, new_name, &old, &new))
1351     {
1352         initAddrs ();
1353         doWrite = 0;
1354         for (i = 0; i < d->authNum; i++)
1355         {
1356             if (d->displayType.location == Local)
1357                 writeLocalAuth (new, auths[i], d->name);
1358 #ifdef XDMCP
1359             else
1360                 writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
1361 #endif
1362         }
1363         doWrite = 1;
1364         if (old) {
1365             if (fstat (fileno (old), &statb) != -1)
1366                 chmod (new_name, (int) (statb.st_mode & 0777));
1367             /*SUPPRESS 560*/
1368             while (entry = XauReadAuth (old)) {
1369                 if (!checkEntry (entry))
1370                 {
1371                     Debug ("Writing an entry\n");
1372                     writeAuth (new, entry);
1373                 }
1374                 XauDisposeAuth (entry);
1375             }
1376             fclose (old);
1377         }
1378         doneAddrs ();
1379         fclose (new);
1380         if (unlink (name) == -1)
1381             Debug ("unlink %s failed\n", name);
1382         if (link (new_name, name) == -1) {
1383             Debug ("link failed %s %s\n", new_name, name);
1384             LogError (
1385                 ReadCatalog(MC_LOG_SET,MC_LOG_NOT_AUTH,MC_DEF_LOG_NOT_AUTH));
1386         } else {
1387             Debug ("new is in place, go for it!\n");
1388             unlink (new_name);
1389         }
1390     }
1391     XauUnlockAuth (name);
1392 }