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