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