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