auth.c revision da2e2ef6
1629baa8cSmrg/*
2629baa8cSmrg
3629baa8cSmrgCopyright 1988, 1998  The Open Group
4629baa8cSmrg
5629baa8cSmrgPermission to use, copy, modify, distribute, and sell this software and its
6629baa8cSmrgdocumentation for any purpose is hereby granted without fee, provided that
7629baa8cSmrgthe above copyright notice appear in all copies and that both that
8629baa8cSmrgcopyright notice and this permission notice appear in supporting
9629baa8cSmrgdocumentation.
10629baa8cSmrg
11629baa8cSmrgThe above copyright notice and this permission notice shall be included
12629baa8cSmrgin all copies or substantial portions of the Software.
13629baa8cSmrg
14629baa8cSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15629baa8cSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16629baa8cSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17629baa8cSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18629baa8cSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19629baa8cSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20629baa8cSmrgOTHER DEALINGS IN THE SOFTWARE.
21629baa8cSmrg
22629baa8cSmrgExcept as contained in this notice, the name of The Open Group shall
23629baa8cSmrgnot be used in advertising or otherwise to promote the sale, use or
24629baa8cSmrgother dealings in this Software without prior written authorization
25629baa8cSmrgfrom The Open Group.
26629baa8cSmrg
27629baa8cSmrg*/
28629baa8cSmrg
29629baa8cSmrg/*
30629baa8cSmrg * xdm - display manager daemon
31629baa8cSmrg * Author:  Keith Packard, MIT X Consortium
32629baa8cSmrg *
33629baa8cSmrg * auth.c
34629baa8cSmrg *
35629baa8cSmrg * maintain the authorization generation daemon
36629baa8cSmrg */
37629baa8cSmrg
38629baa8cSmrg#include <X11/X.h>
39629baa8cSmrg#include <X11/Xlibint.h>
40629baa8cSmrg#include <sys/types.h>
41629baa8cSmrg#include <sys/stat.h>
42629baa8cSmrg
43629baa8cSmrg#include "dm.h"
44629baa8cSmrg#include "dm_auth.h"
45629baa8cSmrg#include "dm_error.h"
46629baa8cSmrg
47629baa8cSmrg#include <errno.h>
48629baa8cSmrg
49629baa8cSmrg#include <sys/ioctl.h>
50629baa8cSmrg
51b7d26471Smrg#ifdef TCPCONN
52629baa8cSmrg# include "dm_socket.h"
53629baa8cSmrg#endif
54629baa8cSmrg
55629baa8cSmrg#if defined(hpux)
56629baa8cSmrg# include <sys/utsname.h>
57629baa8cSmrg#endif
58629baa8cSmrg
59629baa8cSmrg#if defined(SYSV) && defined(i386)
60629baa8cSmrg# include <sys/stream.h>
61629baa8cSmrg#endif /* i386 */
62629baa8cSmrg
63629baa8cSmrg#ifdef SVR4
64629baa8cSmrg# include <netdb.h>
65629baa8cSmrg# include <sys/sockio.h>
66629baa8cSmrg# include <sys/stropts.h>
67629baa8cSmrg#endif
68629baa8cSmrg#ifdef __convex__
69629baa8cSmrg# include <sync/queue.h>
70629baa8cSmrg# include <sync/sema.h>
71629baa8cSmrg#endif
72629baa8cSmrg#ifdef __GNU__
73629baa8cSmrg# include <netdb.h>
74629baa8cSmrg# undef SIOCGIFCONF
75629baa8cSmrg#else /* __GNU__ */
76629baa8cSmrg# include <net/if.h>
77629baa8cSmrg#endif /* __GNU__ */
78629baa8cSmrg
79629baa8cSmrg#if defined(TCPCONN) && !defined(WIN32)
80629baa8cSmrg# include <netinet/in.h>
81629baa8cSmrg#endif
82629baa8cSmrg
83629baa8cSmrg/* Solaris provides an extended interface SIOCGLIFCONF for IPv6 support.
84629baa8cSmrg */
85629baa8cSmrg#ifdef SIOCGLIFCONF
86629baa8cSmrg# define USE_SIOCGLIFCONF
87629baa8cSmrg#endif
88629baa8cSmrg
89b7d26471Smrg#if (defined(SVR4) && !defined(sun)) &&                 \
90629baa8cSmrg    defined(SIOCGIFCONF) && !defined(USE_SIOCGLIFCONF)
91629baa8cSmrg# define SYSV_SIOCGIFCONF
92629baa8cSmrg#endif
93629baa8cSmrg
94629baa8cSmrg#ifdef HAVE_SYS_PARAM_H
95b7d26471Smrg# include <sys/param.h>
96629baa8cSmrg# ifdef BSD
97629baa8cSmrg#  if (BSD >= 199103)
98629baa8cSmrg#   define VARIABLE_IFREQ
99629baa8cSmrg#  endif
100629baa8cSmrg# endif
101629baa8cSmrg#endif
102629baa8cSmrg
103629baa8cSmrg#ifdef __UNIXOS2__
104629baa8cSmrg# define link rename
105629baa8cSmrgint chown(int a,int b,int c) {}
106629baa8cSmrg# include <io.h>
107629baa8cSmrg#endif
108629baa8cSmrg
109629baa8cSmrgstruct AuthProtocol {
110629baa8cSmrg    unsigned short  name_length;
111b7d26471Smrg    const char	    *name;
112629baa8cSmrg    void	    (*InitAuth)(unsigned short len, char *name);
113629baa8cSmrg    Xauth	    *(*GetAuth)(unsigned short len, char *name);
114629baa8cSmrg    void	    (*GetXdmcpAuth)(
115629baa8cSmrg			struct protoDisplay	*pdpy,
116629baa8cSmrg			unsigned short	authorizationNameLen,
117629baa8cSmrg			char		*authorizationName);
118629baa8cSmrg    int		    inited;
119629baa8cSmrg};
120629baa8cSmrg
121629baa8cSmrgstatic struct AuthProtocol AuthProtocols[] = {
122629baa8cSmrg{ (unsigned short) 18,	"MIT-MAGIC-COOKIE-1",
123629baa8cSmrg    MitInitAuth, MitGetAuth, NULL
124629baa8cSmrg},
125629baa8cSmrg#ifdef HASXDMAUTH
126629baa8cSmrg{ (unsigned short) 19,	"XDM-AUTHORIZATION-1",
127629baa8cSmrg    XdmInitAuth, XdmGetAuth, XdmGetXdmcpAuth,
128629baa8cSmrg},
129629baa8cSmrg#endif
130629baa8cSmrg#ifdef SECURE_RPC
131629baa8cSmrg{ (unsigned short) 9, "SUN-DES-1",
132629baa8cSmrg    SecureRPCInitAuth, SecureRPCGetAuth, NULL,
133629baa8cSmrg},
134629baa8cSmrg#endif
135629baa8cSmrg#ifdef K5AUTH
136629baa8cSmrg{ (unsigned short) 14, "MIT-KERBEROS-5",
137629baa8cSmrg    Krb5InitAuth, Krb5GetAuth, NULL,
138629baa8cSmrg},
139629baa8cSmrg#endif
140629baa8cSmrg};
141629baa8cSmrg
142629baa8cSmrg#define NUM_AUTHORIZATION (sizeof (AuthProtocols) / sizeof (AuthProtocols[0]))
143629baa8cSmrg
144629baa8cSmrgstatic struct AuthProtocol *
145629baa8cSmrgfindProtocol (unsigned short name_length, char *name)
146629baa8cSmrg{
147629baa8cSmrg    int	i;
148629baa8cSmrg
149629baa8cSmrg    for (i = 0; i < NUM_AUTHORIZATION; i++)
150629baa8cSmrg	if (AuthProtocols[i].name_length == name_length &&
151629baa8cSmrg	    memcmp(AuthProtocols[i].name, name, name_length) == 0)
152629baa8cSmrg	{
153629baa8cSmrg	    return &AuthProtocols[i];
154629baa8cSmrg	}
155629baa8cSmrg    return (struct AuthProtocol *) 0;
156629baa8cSmrg}
157629baa8cSmrg
158629baa8cSmrgint
159629baa8cSmrgValidAuthorization (unsigned short name_length, char *name)
160629baa8cSmrg{
161629baa8cSmrg    if (findProtocol (name_length, name))
162629baa8cSmrg	return TRUE;
163629baa8cSmrg    return FALSE;
164629baa8cSmrg}
165629baa8cSmrg
166629baa8cSmrgstatic Xauth *
167629baa8cSmrgGenerateAuthorization (unsigned short name_length, char *name)
168629baa8cSmrg{
169629baa8cSmrg    struct AuthProtocol	*a;
170629baa8cSmrg    Xauth   *auth = NULL;
171629baa8cSmrg    int	    i;
172629baa8cSmrg
173629baa8cSmrg    Debug ("GenerateAuthorization %*.*s\n",
174629baa8cSmrg	    name_length, name_length, name);
175629baa8cSmrg    a = findProtocol (name_length, name);
176629baa8cSmrg    if (a)
177629baa8cSmrg    {
178629baa8cSmrg	if (!a->inited)
179629baa8cSmrg	{
180629baa8cSmrg	    (*a->InitAuth) (name_length, name);
181629baa8cSmrg	    a->inited = TRUE;
182629baa8cSmrg	}
183629baa8cSmrg	auth = (*a->GetAuth) (name_length, name);
184629baa8cSmrg	if (auth)
185629baa8cSmrg	{
186629baa8cSmrg	    Debug ("Got %p (%d %*.*s) ", auth,
187629baa8cSmrg		auth->name_length, auth->name_length,
188629baa8cSmrg		auth->name_length, auth->name);
189629baa8cSmrg	    for (i = 0; i < (int)auth->data_length; i++)
190629baa8cSmrg		Debug (" %02x", auth->data[i] & 0xff);
191629baa8cSmrg	    Debug ("\n");
192629baa8cSmrg	}
193629baa8cSmrg	else
194629baa8cSmrg	    Debug ("Got (null)\n");
195629baa8cSmrg    }
196629baa8cSmrg    else
197629baa8cSmrg    {
198629baa8cSmrg	Debug ("Unknown authorization %*.*s\n", name_length, name_length, name);
199629baa8cSmrg    }
200629baa8cSmrg    return auth;
201629baa8cSmrg}
202629baa8cSmrg
203629baa8cSmrg#ifdef XDMCP
204629baa8cSmrg
205629baa8cSmrgvoid
206629baa8cSmrgSetProtoDisplayAuthorization (
207629baa8cSmrg    struct protoDisplay	*pdpy,
208629baa8cSmrg    unsigned short	authorizationNameLen,
209629baa8cSmrg    char		*authorizationName)
210629baa8cSmrg{
211629baa8cSmrg    struct AuthProtocol	*a;
212629baa8cSmrg    Xauth   *auth;
213629baa8cSmrg
214629baa8cSmrg    a = findProtocol (authorizationNameLen, authorizationName);
215629baa8cSmrg    pdpy->xdmcpAuthorization = pdpy->fileAuthorization = NULL;
216629baa8cSmrg    if (a)
217629baa8cSmrg    {
218629baa8cSmrg	if (!a->inited)
219629baa8cSmrg	{
220629baa8cSmrg	    (*a->InitAuth) (authorizationNameLen, authorizationName);
221629baa8cSmrg	    a->inited = TRUE;
222629baa8cSmrg	}
223629baa8cSmrg	if (a->GetXdmcpAuth)
224629baa8cSmrg	{
225629baa8cSmrg	    (*a->GetXdmcpAuth) (pdpy, authorizationNameLen, authorizationName);
226629baa8cSmrg	    auth = pdpy->xdmcpAuthorization;
227629baa8cSmrg	}
228629baa8cSmrg	else
229629baa8cSmrg	{
230629baa8cSmrg	    auth = (*a->GetAuth) (authorizationNameLen, authorizationName);
231629baa8cSmrg	    pdpy->fileAuthorization = auth;
232629baa8cSmrg	    pdpy->xdmcpAuthorization = NULL;
233629baa8cSmrg	}
234629baa8cSmrg	if (auth)
235629baa8cSmrg	    Debug ("Got %p (%d %*.*s)\n", auth,
236629baa8cSmrg		auth->name_length, auth->name_length,
237629baa8cSmrg		auth->name_length, auth->name);
238629baa8cSmrg	else
239629baa8cSmrg	    Debug ("Got (null)\n");
240629baa8cSmrg    }
241629baa8cSmrg}
242629baa8cSmrg
243629baa8cSmrg#endif /* XDMCP */
244629baa8cSmrg
245629baa8cSmrgvoid
246629baa8cSmrgCleanUpFileName (char *src, char *dst, int len)
247629baa8cSmrg{
248629baa8cSmrg    while (*src) {
249629baa8cSmrg	if (--len <= 0)
250629baa8cSmrg		break;
251629baa8cSmrg	switch (*src & 0x7f)
252629baa8cSmrg	{
253629baa8cSmrg	case '/':
254629baa8cSmrg	    *dst++ = '_';
255629baa8cSmrg	    break;
256629baa8cSmrg	case '-':
257629baa8cSmrg	    *dst++ = '.';
258629baa8cSmrg	    break;
259629baa8cSmrg	default:
260629baa8cSmrg	    *dst++ = (*src & 0x7f);
261629baa8cSmrg	}
262629baa8cSmrg	++src;
263629baa8cSmrg    }
264629baa8cSmrg    *dst = '\0';
265629baa8cSmrg}
266629baa8cSmrg
267629baa8cSmrg/* Checks to see if specified directory exists, makes it if not
268da2e2ef6Smrg * Returns: 0 if already exists, 1 if created, < 0 if error occurred
269629baa8cSmrg */
270629baa8cSmrgstatic int
271629baa8cSmrgCheckServerAuthDir (const char *path, struct stat *statb, int mode)
272629baa8cSmrg{
273629baa8cSmrg    int r = stat(path, statb);
274629baa8cSmrg
275629baa8cSmrg    if (r != 0) {
276629baa8cSmrg	if (errno == ENOENT) {
277629baa8cSmrg	    r = mkdir(path, mode);
278629baa8cSmrg	    if (r < 0) {
279629baa8cSmrg		LogError ("cannot make authentication directory %s: %s\n",
280629baa8cSmrg			  path, _SysErrorMsg (errno));
281629baa8cSmrg	    } else {
282629baa8cSmrg		r = 1;
283629baa8cSmrg	    }
284629baa8cSmrg	} else {
285629baa8cSmrg	    LogError ("cannot access authentication directory %s: %s\n",
286629baa8cSmrg		      path, _SysErrorMsg (errno));
287629baa8cSmrg	}
288629baa8cSmrg    } else { /* Directory already exists */
289629baa8cSmrg	if (!S_ISDIR(statb->st_mode)) {
290629baa8cSmrg	    LogError ("cannot make authentication directory %s: %s\n",
291629baa8cSmrg		      path, "file with that name already exists");
292629baa8cSmrg	    return -1;
293629baa8cSmrg	}
294629baa8cSmrg    }
295629baa8cSmrg
296629baa8cSmrg    return r;
297629baa8cSmrg}
298629baa8cSmrg
299629baa8cSmrgstatic char authdir1[] = "authdir";
300629baa8cSmrgstatic char authdir2[] = "authfiles";
301629baa8cSmrg
302629baa8cSmrgstatic int
303629baa8cSmrgMakeServerAuthFile (struct display *d, FILE ** file)
304629baa8cSmrg{
305629baa8cSmrg    int len;
306629baa8cSmrg#ifdef MAXNAMELEN
307629baa8cSmrg# define NAMELEN	MAXNAMELEN
308629baa8cSmrg#else
309629baa8cSmrg# define NAMELEN	255
310629baa8cSmrg#endif
311629baa8cSmrg    char    cleanname[NAMELEN];
312629baa8cSmrg    int r;
313629baa8cSmrg#ifdef HAVE_MKSTEMP
314629baa8cSmrg    int fd;
315629baa8cSmrg#endif
316629baa8cSmrg    struct stat	statb;
317629baa8cSmrg
318629baa8cSmrg    *file = NULL;
319629baa8cSmrg
320629baa8cSmrg    if (!d->authFile) {
321629baa8cSmrg	if (d->clientAuthFile && *d->clientAuthFile) {
322629baa8cSmrg	    d->authFile = strdup(d->clientAuthFile);
323629baa8cSmrg	    if (!d->authFile)
324629baa8cSmrg		return FALSE;
325629baa8cSmrg	} else {
326629baa8cSmrg	    CleanUpFileName (d->name, cleanname, NAMELEN - 8);
327629baa8cSmrg
328629baa8cSmrg	    /* Make authDir if it doesn't already exist */
329629baa8cSmrg	    r = CheckServerAuthDir(authDir, &statb, 0755);
330629baa8cSmrg	    if (r < 0) {
331629baa8cSmrg		return FALSE;
332629baa8cSmrg	    }
333629baa8cSmrg
334629baa8cSmrg	    len = strlen (authDir) + strlen (authdir1) + strlen (authdir2)
335629baa8cSmrg		+ strlen (cleanname) + 14;
336629baa8cSmrg	    d->authFile = malloc (len);
337629baa8cSmrg	    if (!d->authFile)
338629baa8cSmrg		return FALSE;
339629baa8cSmrg
340629baa8cSmrg	    snprintf (d->authFile, len, "%s/%s", authDir, authdir1);
341629baa8cSmrg	    r = CheckServerAuthDir(d->authFile, &statb, 0700);
342629baa8cSmrg	    if (r == 0) {
343629baa8cSmrg		if (statb.st_uid != 0)
344629baa8cSmrg		    (void) chown(d->authFile, 0, statb.st_gid);
345629baa8cSmrg		if ((statb.st_mode & 0077) != 0)
346629baa8cSmrg		    (void) chmod(d->authFile, statb.st_mode & 0700);
347629baa8cSmrg	    } else if (r < 0) {
348629baa8cSmrg		free (d->authFile);
349629baa8cSmrg		d->authFile = NULL;
350629baa8cSmrg		return FALSE;
351629baa8cSmrg	    }
352629baa8cSmrg
353629baa8cSmrg	    snprintf (d->authFile, len, "%s/%s/%s",
354629baa8cSmrg		      authDir, authdir1, authdir2);
355629baa8cSmrg	    r = CheckServerAuthDir(d->authFile, &statb, 0700);
356629baa8cSmrg	    if (r < 0) {
357629baa8cSmrg		free (d->authFile);
358629baa8cSmrg		d->authFile = NULL;
359629baa8cSmrg		return FALSE;
360629baa8cSmrg	    }
361629baa8cSmrg	    snprintf (d->authFile, len, "%s/%s/%s/A%s-XXXXXX",
362629baa8cSmrg		      authDir, authdir1, authdir2, cleanname);
363629baa8cSmrg#ifdef HAVE_MKSTEMP
364629baa8cSmrg	    fd = mkstemp (d->authFile);
365629baa8cSmrg	    if (fd < 0) {
366629baa8cSmrg		LogError ("cannot make authentication file %s: %s\n",
367629baa8cSmrg			  d->authFile, _SysErrorMsg (errno));
368629baa8cSmrg		free (d->authFile);
369629baa8cSmrg		d->authFile = NULL;
370629baa8cSmrg		return FALSE;
371629baa8cSmrg	    }
372629baa8cSmrg
373629baa8cSmrg	    *file = fdopen(fd, "w");
374629baa8cSmrg	    if (!*file)
375629baa8cSmrg		(void) close (fd);
376629baa8cSmrg	    return TRUE;
377629baa8cSmrg#else
378629baa8cSmrg	    (void) mktemp (d->authFile);
379629baa8cSmrg#endif
380629baa8cSmrg	}
381629baa8cSmrg    }
382629baa8cSmrg
383629baa8cSmrg    (void) unlink (d->authFile);
384629baa8cSmrg    *file = fopen (d->authFile, "w");
385629baa8cSmrg    return TRUE;
386629baa8cSmrg}
387629baa8cSmrg
388629baa8cSmrgint
389629baa8cSmrgSaveServerAuthorizations (
390629baa8cSmrg    struct display  *d,
391629baa8cSmrg    Xauth	    **auths,
392629baa8cSmrg    int		    count)
393629baa8cSmrg{
394629baa8cSmrg    FILE	*auth_file;
395629baa8cSmrg    mode_t	mask;
396629baa8cSmrg    int		ret;
397629baa8cSmrg    int		i;
398629baa8cSmrg    const char	dummy_auth[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
399629baa8cSmrg		               "XXXXXXXXXXXXXXXXX"; /* 64 "X"s */
400629baa8cSmrg    int		err = 0;
401629baa8cSmrg
402629baa8cSmrg    mask = umask (0077);
403629baa8cSmrg    ret = MakeServerAuthFile(d, &auth_file);
404629baa8cSmrg    umask (mask);
405629baa8cSmrg    if (!ret)
406629baa8cSmrg	return FALSE;
407629baa8cSmrg    if (!auth_file) {
408629baa8cSmrg	LogError ("cannot open server authorization file %s: %s\n",
409629baa8cSmrg		  d->authFile, _SysErrorMsg (errno));
410629baa8cSmrg	ret = FALSE;
411629baa8cSmrg    }
412629baa8cSmrg    else
413629baa8cSmrg    {
414629baa8cSmrg	Debug ("File: %s auth: %p\n", d->authFile, auths);
415629baa8cSmrg	ret = TRUE;
416629baa8cSmrg	if (count == 0)
417629baa8cSmrg	{
418629baa8cSmrg		/*
419629baa8cSmrg		 * This is a crude hack to determine whether we really can
420629baa8cSmrg		 * write to the auth file even if we don't have real data
421629baa8cSmrg		 * to write right now.
422629baa8cSmrg		 */
423629baa8cSmrg
424629baa8cSmrg		/*
425629baa8cSmrg		 * Write garbage data to file to provoke ENOSPC and other
426629baa8cSmrg		 * errors.
427629baa8cSmrg		 */
428629baa8cSmrg		(void) fprintf (auth_file, "%s", dummy_auth);
429629baa8cSmrg		(void) fflush (auth_file);
430629baa8cSmrg		if (ferror (auth_file))
431629baa8cSmrg		{
432629baa8cSmrg		    err = errno;
433629baa8cSmrg		    ret = FALSE;
434629baa8cSmrg		}
435629baa8cSmrg		/*
436629baa8cSmrg		 * Rewind so that the garbage data is overwritten later.
437629baa8cSmrg		 */
438629baa8cSmrg		rewind(auth_file);
439629baa8cSmrg	}
440629baa8cSmrg	for (i = 0; i < count; i++)
441629baa8cSmrg	{
442629baa8cSmrg	    /*
443629baa8cSmrg	     * User-based auths may not have data until
444629baa8cSmrg	     * a user logs in.  In which case don't write
445629baa8cSmrg	     * to the auth file so xrdb and setup programs don't fail.
446629baa8cSmrg	     */
447b7d26471Smrg	    if (auths[i]->data_length > 0) {
448629baa8cSmrg		if (!XauWriteAuth (auth_file, auths[i]))
449629baa8cSmrg		{
450629baa8cSmrg		    Debug ("XauWriteAuth() failed\n");
451629baa8cSmrg		}
452629baa8cSmrg		(void) fflush (auth_file);
453629baa8cSmrg		if (ferror (auth_file))
454629baa8cSmrg		{
455629baa8cSmrg		    err = errno;
456629baa8cSmrg		    ret = FALSE;
457629baa8cSmrg		}
458b7d26471Smrg            }
459629baa8cSmrg	}
460629baa8cSmrg	/*
461629baa8cSmrg	 * XXX: This is not elegant, but stdio has no truncation function.
462629baa8cSmrg	 */
463629baa8cSmrg	if (ftruncate(fileno(auth_file), ftell(auth_file)))
464629baa8cSmrg	{
465629baa8cSmrg		Debug ("ftruncate() failed\n");
466629baa8cSmrg	}
467629baa8cSmrg	fclose (auth_file);
468629baa8cSmrg
469629baa8cSmrg    }
470629baa8cSmrg    if (ret == FALSE)
471629baa8cSmrg    {
472629baa8cSmrg	LogError ("Cannot write to server authorization file %s%s%s\n",
473629baa8cSmrg		  d->authFile,
474629baa8cSmrg		  err ? ": " : "",
475629baa8cSmrg		  err ? _SysErrorMsg (errno) : "");
476629baa8cSmrg	free (d->authFile);
477629baa8cSmrg	d->authFile = NULL;
478629baa8cSmrg    }
479629baa8cSmrg    return ret;
480629baa8cSmrg}
481629baa8cSmrg
482629baa8cSmrgvoid
483629baa8cSmrgSetLocalAuthorization (struct display *d)
484629baa8cSmrg{
485629baa8cSmrg    Xauth	*auth, **auths;
486629baa8cSmrg    int		i, j;
487629baa8cSmrg
488629baa8cSmrg    if (d->authorizations)
489629baa8cSmrg    {
490629baa8cSmrg	for (i = 0; i < d->authNum; i++)
491629baa8cSmrg	    XauDisposeAuth (d->authorizations[i]);
492629baa8cSmrg	free (d->authorizations);
493629baa8cSmrg	d->authorizations = (Xauth **) NULL;
494629baa8cSmrg	d->authNum = 0;
495629baa8cSmrg    }
496629baa8cSmrg    if (!d->authNames)
497629baa8cSmrg	return;
498629baa8cSmrg    for (i = 0; d->authNames[i]; i++)
499629baa8cSmrg	;
500629baa8cSmrg    d->authNameNum = i;
501629baa8cSmrg    free (d->authNameLens);
502629baa8cSmrg    d->authNameLens = malloc (d->authNameNum * sizeof (unsigned short));
503629baa8cSmrg    if (!d->authNameLens)
504629baa8cSmrg	return;
505629baa8cSmrg    for (i = 0; i < d->authNameNum; i++)
506629baa8cSmrg	d->authNameLens[i] = strlen (d->authNames[i]);
507629baa8cSmrg    auths = malloc (d->authNameNum * sizeof (Xauth *));
508629baa8cSmrg    if (!auths)
509629baa8cSmrg	return;
510629baa8cSmrg    j = 0;
511629baa8cSmrg    for (i = 0; i < d->authNameNum; i++)
512629baa8cSmrg    {
513629baa8cSmrg	auth = GenerateAuthorization (d->authNameLens[i], d->authNames[i]);
514629baa8cSmrg	if (auth)
515629baa8cSmrg	    auths[j++] = auth;
516629baa8cSmrg    }
517629baa8cSmrg    if (SaveServerAuthorizations (d, auths, j))
518629baa8cSmrg    {
519629baa8cSmrg	d->authorizations = auths;
520629baa8cSmrg	d->authNum = j;
521629baa8cSmrg    }
522629baa8cSmrg    else
523629baa8cSmrg    {
524629baa8cSmrg	for (i = 0; i < j; i++)
525629baa8cSmrg	    XauDisposeAuth (auths[i]);
526629baa8cSmrg	free (auths);
527629baa8cSmrg    }
528629baa8cSmrg}
529629baa8cSmrg
530629baa8cSmrg/*
531629baa8cSmrg * Set the authorization to use for xdm's initial connection
532629baa8cSmrg * to the X server.  Cannot use user-based authorizations
533629baa8cSmrg * because no one has logged in yet, so we don't have any
534629baa8cSmrg * user credentials.
535629baa8cSmrg * Well, actually we could use SUN-DES-1 because we tell the server
536629baa8cSmrg * to allow root in.  This is bogus and should be fixed.
537629baa8cSmrg */
538629baa8cSmrgvoid
539629baa8cSmrgSetAuthorization (struct display *d)
540629baa8cSmrg{
541629baa8cSmrg    register Xauth **auth = d->authorizations;
542629baa8cSmrg    int i;
543629baa8cSmrg
544629baa8cSmrg    for (i = 0; i < d->authNum; i++)
545629baa8cSmrg    {
546629baa8cSmrg	if (auth[i]->name_length == 9 &&
547629baa8cSmrg	    memcmp(auth[i]->name, "SUN-DES-1", 9) == 0)
548629baa8cSmrg	    continue;
549629baa8cSmrg	if (auth[i]->name_length == 14 &&
550629baa8cSmrg	    memcmp(auth[i]->name, "MIT-KERBEROS-5", 14) == 0)
551629baa8cSmrg	    continue;
552629baa8cSmrg	XSetAuthorization (auth[i]->name, (int) auth[i]->name_length,
553629baa8cSmrg			   auth[i]->data, (int) auth[i]->data_length);
554629baa8cSmrg    }
555629baa8cSmrg}
556629baa8cSmrg
557629baa8cSmrgstatic int
558629baa8cSmrgopenFiles (char *name, char *new_name, FILE **oldp, FILE **newp)
559629baa8cSmrg{
560629baa8cSmrg	mode_t	mask;
561629baa8cSmrg	int newfd;
562629baa8cSmrg
563629baa8cSmrg	strcpy (new_name, name);
564629baa8cSmrg	strcat (new_name, "-n");
565629baa8cSmrg	/*
566629baa8cSmrg	 * Set safe umask for file creation operations.
567629baa8cSmrg	 */
568629baa8cSmrg	mask = umask (0077);
569629baa8cSmrg	/*
570629baa8cSmrg	 * Unlink the authorization file we intend to create, and then open
571629baa8cSmrg	 * it with O_CREAT | O_EXCL to avoid race-based symlink attacks.
572629baa8cSmrg	 */
573629baa8cSmrg	(void) unlink (new_name);
574629baa8cSmrg	newfd = open (new_name, O_WRONLY | O_CREAT | O_EXCL, 0600);
575b7d26471Smrg	if (newfd >= 0) {
576629baa8cSmrg	    *newp = fdopen (newfd, "w");
577b7d26471Smrg	    if (*newp == NULL)
578b7d26471Smrg		close(newfd);
579b7d26471Smrg	}
580629baa8cSmrg	else
581629baa8cSmrg	{
582629baa8cSmrg	    LogError ("Cannot create file %s: %s\n", new_name,
583629baa8cSmrg		      _SysErrorMsg (errno));
584629baa8cSmrg	    *newp = NULL;
585629baa8cSmrg	}
586629baa8cSmrg	/*
587629baa8cSmrg	 * There are no more attempts to create files after this point;
588629baa8cSmrg	 * restore the original umask.
589629baa8cSmrg	 */
590629baa8cSmrg	(void) umask (mask);
591629baa8cSmrg	if (!*newp) {
592629baa8cSmrg		Debug ("can't open new file %s\n", new_name);
593629baa8cSmrg		return 0;
594629baa8cSmrg	}
595629baa8cSmrg	if (!*oldp)
596629baa8cSmrg	    *oldp = fopen (name, "r");
597629baa8cSmrg	Debug ("opens succeeded %s %s\n", name, new_name);
598629baa8cSmrg	return 1;
599629baa8cSmrg}
600629baa8cSmrg
601629baa8cSmrgstatic int
602629baa8cSmrgbinaryEqual (char *a, char *b, unsigned short len)
603629baa8cSmrg{
604629baa8cSmrg	while (len-- > 0)
605629baa8cSmrg		if (*a++ != *b++)
606629baa8cSmrg			return FALSE;
607629baa8cSmrg	return TRUE;
608629baa8cSmrg}
609629baa8cSmrg
610629baa8cSmrgstatic void
611629baa8cSmrgdumpBytes (unsigned short len, char *data)
612629baa8cSmrg{
613629baa8cSmrg	unsigned short	i;
614629baa8cSmrg
615629baa8cSmrg	Debug ("%d: ", len);
616629baa8cSmrg	for (i = 0; i < len; i++)
617629baa8cSmrg		Debug ("%02x ", data[i] & 0377);
618629baa8cSmrg	Debug ("\n");
619629baa8cSmrg}
620629baa8cSmrg
621629baa8cSmrgstatic void
622629baa8cSmrgdumpAuth (Xauth *auth)
623629baa8cSmrg{
624629baa8cSmrg	Debug ("family: %d\n", auth->family);
625629baa8cSmrg	Debug ("addr:   ");
626629baa8cSmrg	dumpBytes (auth->address_length, auth->address);
627629baa8cSmrg	Debug ("number: ");
628629baa8cSmrg	dumpBytes (auth->number_length, auth->number);
629629baa8cSmrg	Debug ("name:   ");
630629baa8cSmrg	dumpBytes (auth->name_length, auth->name);
631629baa8cSmrg	Debug ("data:   ");
632629baa8cSmrg	dumpBytes (auth->data_length, auth->data);
633629baa8cSmrg}
634629baa8cSmrg
635629baa8cSmrgstruct addrList {
636629baa8cSmrg	unsigned short	family;
637629baa8cSmrg	unsigned short	address_length;
638629baa8cSmrg	char	*address;
639629baa8cSmrg	unsigned short	number_length;
640629baa8cSmrg	char	*number;
641629baa8cSmrg	unsigned short	name_length;
642629baa8cSmrg	char	*name;
643629baa8cSmrg	struct addrList	*next;
644629baa8cSmrg};
645629baa8cSmrg
646629baa8cSmrgstatic struct addrList	*addrs;
647629baa8cSmrg
648629baa8cSmrgstatic void
649629baa8cSmrginitAddrs (void)
650629baa8cSmrg{
651629baa8cSmrg	addrs = NULL;
652629baa8cSmrg}
653629baa8cSmrg
654629baa8cSmrgstatic void
655629baa8cSmrgdoneAddrs (void)
656629baa8cSmrg{
657629baa8cSmrg	struct addrList	*a, *n;
658629baa8cSmrg	for (a = addrs; a; a = n) {
659629baa8cSmrg		n = a->next;
660629baa8cSmrg		free (a->address);
661629baa8cSmrg		free (a->number);
662629baa8cSmrg		free (a);
663629baa8cSmrg	}
664da2e2ef6Smrg	addrs = NULL;
665629baa8cSmrg}
666629baa8cSmrg
667629baa8cSmrgstatic int checkEntry (Xauth *auth);
668629baa8cSmrg
669629baa8cSmrgstatic void
670629baa8cSmrgsaveEntry (Xauth *auth)
671629baa8cSmrg{
672629baa8cSmrg	struct addrList	*new;
673629baa8cSmrg
674629baa8cSmrg	new = malloc (sizeof (struct addrList));
675629baa8cSmrg	if (!new) {
676629baa8cSmrg		LogOutOfMem ("saveEntry");
677629baa8cSmrg		return;
678629baa8cSmrg	}
679629baa8cSmrg	if ((new->address_length = auth->address_length) > 0) {
680629baa8cSmrg		new->address = malloc (auth->address_length);
681629baa8cSmrg		if (!new->address) {
682629baa8cSmrg			LogOutOfMem ("saveEntry");
683629baa8cSmrg			free (new);
684629baa8cSmrg			return;
685629baa8cSmrg		}
686629baa8cSmrg		memmove( new->address, auth->address, (int) auth->address_length);
687629baa8cSmrg	} else
688629baa8cSmrg		new->address = NULL;
689629baa8cSmrg	if ((new->number_length = auth->number_length) > 0) {
690629baa8cSmrg		new->number = malloc (auth->number_length);
691629baa8cSmrg		if (!new->number) {
692629baa8cSmrg			LogOutOfMem ("saveEntry");
693629baa8cSmrg			free (new->address);
694629baa8cSmrg			free (new);
695629baa8cSmrg			return;
696629baa8cSmrg		}
697629baa8cSmrg		memmove( new->number, auth->number, (int) auth->number_length);
698629baa8cSmrg	} else
699629baa8cSmrg		new->number = NULL;
700629baa8cSmrg	if ((new->name_length = auth->name_length) > 0) {
701629baa8cSmrg		new->name = malloc (auth->name_length);
702629baa8cSmrg		if (!new->name) {
703629baa8cSmrg			LogOutOfMem ("saveEntry");
704629baa8cSmrg			free (new->number);
705629baa8cSmrg			free (new->address);
706629baa8cSmrg			free (new);
707629baa8cSmrg			return;
708629baa8cSmrg		}
709629baa8cSmrg		memmove( new->name, auth->name, (int) auth->name_length);
710629baa8cSmrg	} else
711629baa8cSmrg		new->name = NULL;
712629baa8cSmrg	new->family = auth->family;
713629baa8cSmrg	new->next = addrs;
714629baa8cSmrg	addrs = new;
715629baa8cSmrg}
716629baa8cSmrg
717629baa8cSmrgstatic int
718629baa8cSmrgcheckEntry (Xauth *auth)
719629baa8cSmrg{
720629baa8cSmrg	struct addrList	*a;
721629baa8cSmrg
722629baa8cSmrg	for (a = addrs; a; a = a->next) {
723629baa8cSmrg		if (a->family == auth->family &&
724629baa8cSmrg		    a->address_length == auth->address_length &&
725629baa8cSmrg		    binaryEqual (a->address, auth->address, auth->address_length) &&
726629baa8cSmrg		    a->number_length == auth->number_length &&
727629baa8cSmrg		    binaryEqual (a->number, auth->number, auth->number_length) &&
728629baa8cSmrg		    a->name_length == auth->name_length &&
729629baa8cSmrg		    binaryEqual (a->name, auth->name, auth->name_length))
730629baa8cSmrg		{
731629baa8cSmrg			return 1;
732629baa8cSmrg		}
733629baa8cSmrg	}
734629baa8cSmrg	return 0;
735629baa8cSmrg}
736629baa8cSmrg
737629baa8cSmrgstatic int  doWrite;
738629baa8cSmrg
739629baa8cSmrgstatic void
740629baa8cSmrgwriteAuth (FILE *file, Xauth *auth)
741629baa8cSmrg{
742629baa8cSmrg    if (debugLevel >= 15) {	/* normally too verbose */
743629baa8cSmrg        Debug ("writeAuth: doWrite = %d\n", doWrite);
744629baa8cSmrg	dumpAuth (auth);	/* does Debug only */
745629baa8cSmrg    }
746629baa8cSmrg	if (doWrite)
747629baa8cSmrg	    XauWriteAuth (file, auth);
748629baa8cSmrg}
749629baa8cSmrg
750629baa8cSmrgstatic void
751629baa8cSmrgwriteAddr (
752629baa8cSmrg    int		family,
753629baa8cSmrg    int		addr_length,
754629baa8cSmrg    char	*addr,
755629baa8cSmrg    FILE	*file,
756629baa8cSmrg    Xauth	*auth)
757629baa8cSmrg{
758629baa8cSmrg	auth->family = (unsigned short) family;
759629baa8cSmrg	auth->address_length = addr_length;
760629baa8cSmrg	auth->address = addr;
761629baa8cSmrg	Debug ("writeAddr: writing and saving an entry\n");
762629baa8cSmrg	writeAuth (file, auth);
763629baa8cSmrg	saveEntry (auth);
764629baa8cSmrg}
765629baa8cSmrg
766629baa8cSmrgstatic void
767629baa8cSmrgDefineLocal (FILE *file, Xauth *auth)
768629baa8cSmrg{
769629baa8cSmrg	char	displayname[100];
770629baa8cSmrg	int	len = _XGetHostname (displayname, sizeof(displayname));
771629baa8cSmrg
772629baa8cSmrg/* Make sure this produces the same string as _XGetHostname in lib/X/XlibInt.c.
773629baa8cSmrg * Otherwise, Xau will not be able to find your cookies in the Xauthority file.
774629baa8cSmrg *
775629baa8cSmrg * Note: POSIX says that the ``nodename'' member of utsname does _not_ have
776629baa8cSmrg *       to have sufficient information for interfacing to the network,
777629baa8cSmrg *       and so, you may be better off using gethostname (if it exists).
778629baa8cSmrg */
779629baa8cSmrg
780629baa8cSmrg#if defined(hpux)
781629baa8cSmrg	/*
782629baa8cSmrg	 * For HP-UX, HP's Xlib expects a fully-qualified domain name, which
783da2e2ef6Smrg	 * is achieved by using gethostname().  For compatibility, we must
784629baa8cSmrg	 * also still create the entry using uname().
785629baa8cSmrg	 */
786629baa8cSmrg	char	tmp_displayname[100];
787629baa8cSmrg	struct utsname name;
788629baa8cSmrg
789629baa8cSmrg	tmp_displayname[0] = 0;
790629baa8cSmrg	uname(&name);
791629baa8cSmrg	snprintf(tmp_displayname, sizeof(tmp_displayname), "%s", name.nodename);
792629baa8cSmrg	writeAddr (FamilyLocal, strlen (tmp_displayname), tmp_displayname,
793629baa8cSmrg		   file, auth);
794629baa8cSmrg
795629baa8cSmrg	/*
796629baa8cSmrg	 * If _XGetHostname() returned the same value as uname(), don't
797629baa8cSmrg	 * write a duplicate entry.
798629baa8cSmrg	 */
799629baa8cSmrg	if (strcmp (displayname, tmp_displayname))
800629baa8cSmrg#endif
801629baa8cSmrg
802629baa8cSmrg	writeAddr (FamilyLocal, len, displayname, file, auth);
803629baa8cSmrg}
804629baa8cSmrg
805629baa8cSmrg#ifdef HAVE_GETIFADDRS
806629baa8cSmrg# include <ifaddrs.h>
807629baa8cSmrg
808629baa8cSmrgstatic void
809629baa8cSmrgDefineSelf(int fd, FILE *file, Xauth *auth)
810629baa8cSmrg{
811629baa8cSmrg    struct ifaddrs *ifap, *ifr;
812629baa8cSmrg    char *addr;
813629baa8cSmrg    int family, len;
814629baa8cSmrg
815629baa8cSmrg    Debug("DefineSelf\n");
816629baa8cSmrg    if (getifaddrs(&ifap) < 0)
817629baa8cSmrg	return;
818629baa8cSmrg    for (ifr = ifap; ifr != NULL; ifr = ifr->ifa_next) {
819629baa8cSmrg	len = sizeof(*(ifr->ifa_addr));
820629baa8cSmrg	family = ConvertAddr((XdmcpNetaddr)(ifr->ifa_addr), &len, &addr);
821629baa8cSmrg	if (family == -1 || family == FamilyLocal)
822629baa8cSmrg	    continue;
823629baa8cSmrg	/*
824629baa8cSmrg	 * don't write out 'localhost' entries, as
825629baa8cSmrg	 * they may conflict with other local entries.
826629baa8cSmrg	 * DefineLocal will always be called to add
827629baa8cSmrg	 * the local entry anyway, so this one can
828629baa8cSmrg	 * be tossed.
829629baa8cSmrg	 */
830629baa8cSmrg	if (family == FamilyInternet && len == 4 && addr[0] == 127)
831629baa8cSmrg	{
832629baa8cSmrg	    Debug ("Skipping localhost address\n");
833629baa8cSmrg	    continue;
834629baa8cSmrg	}
835629baa8cSmrg# if defined(IPv6) && defined(AF_INET6)
836629baa8cSmrg	if(family == FamilyInternet6) {
837629baa8cSmrg	    if (IN6_IS_ADDR_LOOPBACK(((struct in6_addr *)addr))) {
838629baa8cSmrg		Debug ("Skipping IPv6 localhost address\n");
839629baa8cSmrg		continue;
840629baa8cSmrg	    }
841629baa8cSmrg	    /* Also skip XDM-AUTHORIZATION-1 */
842629baa8cSmrg	    if (auth->name_length == 19 &&
843629baa8cSmrg		strcmp(auth->name, "XDM-AUTHORIZATION-1") == 0) {
844629baa8cSmrg		Debug ("Skipping IPv6 XDM-AUTHORIZATION-1\n");
845629baa8cSmrg		continue;
846629baa8cSmrg	    }
847629baa8cSmrg	}
848629baa8cSmrg# endif
849629baa8cSmrg	writeAddr(family, len, addr, file, auth);
850629baa8cSmrg    }
851629baa8cSmrg    freeifaddrs(ifap);
852629baa8cSmrg    Debug("DefineSelf done\n");
853629baa8cSmrg}
854629baa8cSmrg#else  /* GETIFADDRS */
855629baa8cSmrg
856629baa8cSmrg# ifdef SYSV_SIOCGIFCONF
857629baa8cSmrg
858629baa8cSmrg/* Deal with different SIOCGIFCONF ioctl semantics on SYSV, SVR4 */
859629baa8cSmrg
860629baa8cSmrgstatic int
861629baa8cSmrgifioctl (int fd, int cmd, char *arg)
862629baa8cSmrg{
863629baa8cSmrg    struct strioctl ioc;
864629baa8cSmrg    int ret;
865629baa8cSmrg
866629baa8cSmrg    bzero((char *) &ioc, sizeof(ioc));
867629baa8cSmrg    ioc.ic_cmd = cmd;
868629baa8cSmrg    ioc.ic_timout = 0;
869629baa8cSmrg    if (cmd == SIOCGIFCONF)
870629baa8cSmrg    {
871629baa8cSmrg	ioc.ic_len = ((struct ifconf *) arg)->ifc_len;
872629baa8cSmrg	ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf;
873629baa8cSmrg    }
874629baa8cSmrg    else
875629baa8cSmrg    {
876629baa8cSmrg	ioc.ic_len = sizeof(struct ifreq);
877629baa8cSmrg	ioc.ic_dp = arg;
878629baa8cSmrg    }
879629baa8cSmrg    ret = ioctl(fd, I_STR, (char *) &ioc);
880629baa8cSmrg    if (ret >= 0 && cmd == SIOCGIFCONF)
881629baa8cSmrg	((struct ifconf *) arg)->ifc_len = ioc.ic_len;
882629baa8cSmrg    return(ret);
883629baa8cSmrg}
884629baa8cSmrg# else /* SYSV_SIOCGIFCONF */
885629baa8cSmrg#  define ifioctl ioctl
886629baa8cSmrg# endif /* SYSV_SIOCGIFCONF */
887629baa8cSmrg
888629baa8cSmrg
889629baa8cSmrg
890b7d26471Smrg# if defined(SIOCGIFCONF) || defined (USE_SIOCGLIFCONF)
891629baa8cSmrg
892b7d26471Smrg#  ifdef USE_SIOCGLIFCONF
893b7d26471Smrg#   define ifr_type    struct lifreq
894b7d26471Smrg#  else
895b7d26471Smrg#   define ifr_type    struct ifreq
896b7d26471Smrg#  endif
897629baa8cSmrg
898629baa8cSmrg/* Handle variable length ifreq in BNR2 and later */
899b7d26471Smrg#  ifdef VARIABLE_IFREQ
900b7d26471Smrg#   define ifr_size(p) (sizeof (struct ifreq) + \
901629baa8cSmrg		     (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \
902629baa8cSmrg		      p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0))
903b7d26471Smrg#  else
904b7d26471Smrg#   define ifr_size(p) (sizeof (ifr_type))
905b7d26471Smrg#  endif
906629baa8cSmrg
907629baa8cSmrg/* Define this host for access control.  Find all the hosts the OS knows about
908629baa8cSmrg * for this fd and add them to the selfhosts list.
909629baa8cSmrg */
910629baa8cSmrgstatic void
911629baa8cSmrgDefineSelf (int fd, FILE *file, Xauth *auth)
912629baa8cSmrg{
913629baa8cSmrg    char		buf[2048], *cp, *cplim;
914629baa8cSmrg    int 		len;
915629baa8cSmrg    char 		*addr;
916629baa8cSmrg    int 		family;
917629baa8cSmrg    register ifr_type  *ifr;
918b7d26471Smrg#  ifdef USE_SIOCGLIFCONF
919629baa8cSmrg    void *		bufptr = buf;
920629baa8cSmrg    size_t		buflen = sizeof(buf);
921629baa8cSmrg    struct lifconf	ifc;
922b7d26471Smrg#   ifdef SIOCGLIFNUM
923629baa8cSmrg    struct lifnum	ifn;
924b7d26471Smrg#   endif
925b7d26471Smrg#  else
926629baa8cSmrg    struct ifconf	ifc;
927b7d26471Smrg#  endif
928629baa8cSmrg
929b7d26471Smrg#  if defined(SIOCGLIFNUM) && defined(SIOCGLIFCONF)
930629baa8cSmrg    ifn.lifn_family = AF_UNSPEC;
931629baa8cSmrg    ifn.lifn_flags = 0;
932629baa8cSmrg    if (ioctl (fd, (int) SIOCGLIFNUM, (char *) &ifn) < 0)
933629baa8cSmrg	LogError ("Failed getting interface count");
934629baa8cSmrg    if (buflen < (ifn.lifn_count * sizeof(struct lifreq))) {
935629baa8cSmrg	buflen = ifn.lifn_count * sizeof(struct lifreq);
936629baa8cSmrg	bufptr = malloc(buflen);
937629baa8cSmrg    }
938b7d26471Smrg#  endif
939629baa8cSmrg
940b7d26471Smrg#  ifdef USE_SIOCGLIFCONF
941629baa8cSmrg    ifc.lifc_family = AF_UNSPEC;
942629baa8cSmrg    ifc.lifc_flags = 0;
943629baa8cSmrg    ifc.lifc_len = buflen;
944629baa8cSmrg    ifc.lifc_buf = bufptr;
945629baa8cSmrg
946b7d26471Smrg#   define IFC_IOCTL_REQ SIOCGLIFCONF
947b7d26471Smrg#   define IFC_IFC_REQ ifc.lifc_req
948b7d26471Smrg#   define IFC_IFC_LEN ifc.lifc_len
949b7d26471Smrg#   define IFR_IFR_ADDR ifr->lifr_addr
950b7d26471Smrg#   define IFR_IFR_NAME ifr->lifr_name
951629baa8cSmrg
952b7d26471Smrg#  else
953629baa8cSmrg    ifc.ifc_len = sizeof (buf);
954629baa8cSmrg    ifc.ifc_buf = buf;
955629baa8cSmrg
956b7d26471Smrg#   define IFC_IOCTL_REQ SIOCGIFCONF
957b7d26471Smrg#   define IFC_IFC_REQ ifc.ifc_req
958b7d26471Smrg#   define IFC_IFC_LEN ifc.ifc_len
959b7d26471Smrg#   define IFR_IFR_ADDR ifr->ifr_addr
960b7d26471Smrg#   define IFR_IFR_NAME ifr->ifr_name
961b7d26471Smrg#  endif
962629baa8cSmrg
963629baa8cSmrg    if (ifioctl (fd, IFC_IOCTL_REQ, (char *) &ifc) < 0) {
964629baa8cSmrg        LogError ("Trouble getting network interface configuration");
965629baa8cSmrg
966b7d26471Smrg#  ifdef USE_SIOCGLIFCONF
967629baa8cSmrg	if (bufptr != buf) {
968629baa8cSmrg	    free(bufptr);
969629baa8cSmrg	}
970b7d26471Smrg#  endif
971629baa8cSmrg	return;
972629baa8cSmrg    }
973629baa8cSmrg
974629baa8cSmrg    cplim = (char *) IFC_IFC_REQ + IFC_IFC_LEN;
975629baa8cSmrg
976629baa8cSmrg    for (cp = (char *) IFC_IFC_REQ; cp < cplim; cp += ifr_size (ifr))
977629baa8cSmrg    {
978629baa8cSmrg	ifr = (ifr_type *) cp;
979b7d26471Smrg	family = ConvertAddr ((XdmcpNetaddr) &IFR_IFR_ADDR, &len, &addr);
980b7d26471Smrg	if (family < 0)
981b7d26471Smrg	    continue;
982b7d26471Smrg
983b7d26471Smrg	if (len == 0)
984b7d26471Smrg	{
985b7d26471Smrg	    Debug ("Skipping zero length address\n");
986b7d26471Smrg	    continue;
987b7d26471Smrg	}
988629baa8cSmrg	/*
989b7d26471Smrg	 * don't write out 'localhost' entries, as
990b7d26471Smrg	 * they may conflict with other local entries.
991b7d26471Smrg	 * DefineLocal will always be called to add
992b7d26471Smrg	 * the local entry anyway, so this one can
993b7d26471Smrg	 * be tossed.
994629baa8cSmrg	 */
995b7d26471Smrg	if (family == FamilyInternet && len == 4 &&
996b7d26471Smrg	    addr[0] == 127 && addr[1] == 0 &&
997b7d26471Smrg	    addr[2] == 0 && addr[3] == 1)
998629baa8cSmrg	{
999b7d26471Smrg	    Debug ("Skipping localhost address\n");
1000b7d26471Smrg	    continue;
1001b7d26471Smrg	}
1002b7d26471Smrg#  if defined(IPv6) && defined(AF_INET6)
1003b7d26471Smrg	if (family == FamilyInternet6) {
1004b7d26471Smrg	    if (IN6_IS_ADDR_LOOPBACK(((struct in6_addr *)addr))) {
1005b7d26471Smrg		Debug ("Skipping IPv6 localhost address\n");
1006629baa8cSmrg		continue;
1007629baa8cSmrg	    }
1008b7d26471Smrg	    /* Also skip XDM-AUTHORIZATION-1 */
1009b7d26471Smrg	    if (auth->name_length == 19 &&
1010b7d26471Smrg		strcmp(auth->name, "XDM-AUTHORIZATION-1") == 0) {
1011b7d26471Smrg		Debug ("Skipping IPv6 XDM-AUTHORIZATION-1\n");
1012b7d26471Smrg		continue;
1013629baa8cSmrg	    }
1014629baa8cSmrg	}
1015b7d26471Smrg#  endif
1016629baa8cSmrg	Debug ("DefineSelf: write network address, length %d\n", len);
1017629baa8cSmrg	writeAddr (family, len, addr, file, auth);
1018629baa8cSmrg    }
1019629baa8cSmrg}
1020629baa8cSmrg
1021b7d26471Smrg# else /* SIOCGIFCONF */
1022629baa8cSmrg
1023629baa8cSmrg/* Define this host for access control.  Find all the hosts the OS knows about
1024629baa8cSmrg * for this fd and add them to the selfhosts list.
1025629baa8cSmrg */
1026629baa8cSmrgstatic void
1027629baa8cSmrgDefineSelf (int fd, int file, int auth)
1028629baa8cSmrg{
1029629baa8cSmrg    register int n;
1030629baa8cSmrg    int	len;
1031629baa8cSmrg    caddr_t	addr;
1032629baa8cSmrg    int		family;
1033629baa8cSmrg
1034629baa8cSmrg    struct utsname name;
1035629baa8cSmrg    register struct hostent  *hp;
1036629baa8cSmrg
1037629baa8cSmrg    union {
1038629baa8cSmrg	struct  sockaddr   sa;
1039629baa8cSmrg	struct  sockaddr_in  in;
1040629baa8cSmrg    } saddr;
1041629baa8cSmrg
1042629baa8cSmrg    struct	sockaddr_in	*inetaddr;
1043629baa8cSmrg
1044629baa8cSmrg    /* hpux:
1045629baa8cSmrg     * Why not use gethostname()?  Well, at least on my system, I've had to
1046629baa8cSmrg     * make an ugly kernel patch to get a name longer than 8 characters, and
1047629baa8cSmrg     * uname() lets me access to the whole string (it smashes release, you
1048629baa8cSmrg     * see), whereas gethostname() kindly truncates it for me.
1049629baa8cSmrg     */
1050629baa8cSmrg    uname(&name);
1051629baa8cSmrg    hp = gethostbyname (name.nodename);
1052629baa8cSmrg    if (hp != NULL) {
1053629baa8cSmrg	saddr.sa.sa_family = hp->h_addrtype;
1054629baa8cSmrg	inetaddr = (struct sockaddr_in *) (&(saddr.sa));
1055629baa8cSmrg	memmove( (char *) &(inetaddr->sin_addr), (char *) hp->h_addr, (int) hp->h_length);
1056629baa8cSmrg	family = ConvertAddr ( &(saddr.sa), &len, &addr);
1057629baa8cSmrg	if ( family >= 0) {
1058629baa8cSmrg	    writeAddr (FamilyInternet, sizeof (inetaddr->sin_addr),
1059629baa8cSmrg			(char *) (&inetaddr->sin_addr), file, auth);
1060629baa8cSmrg	}
1061629baa8cSmrg    }
1062629baa8cSmrg}
1063629baa8cSmrg
1064629baa8cSmrg
1065b7d26471Smrg# endif /* SIOCGIFCONF else */
1066629baa8cSmrg#endif /* HAVE_GETIFADDRS */
1067629baa8cSmrg
1068629baa8cSmrgstatic void
1069629baa8cSmrgsetAuthNumber (Xauth *auth, char *name)
1070629baa8cSmrg{
1071629baa8cSmrg    char	*colon;
1072629baa8cSmrg    char	*dot, *number;
1073629baa8cSmrg
1074629baa8cSmrg    Debug ("setAuthNumber %s\n", name);
1075629baa8cSmrg    colon = strrchr(name, ':');
1076629baa8cSmrg    if (colon) {
1077629baa8cSmrg	++colon;
1078629baa8cSmrg	dot = strchr(colon, '.');
1079629baa8cSmrg	if (dot)
1080629baa8cSmrg	    auth->number_length = dot - colon;
1081629baa8cSmrg	else
1082629baa8cSmrg	    auth->number_length = strlen (colon);
1083629baa8cSmrg	number = malloc (auth->number_length + 1);
1084629baa8cSmrg	if (number) {
1085629baa8cSmrg	    strncpy (number, colon, auth->number_length);
1086629baa8cSmrg	    number[auth->number_length] = '\0';
1087629baa8cSmrg	} else {
1088629baa8cSmrg	    LogOutOfMem ("setAuthNumber");
1089629baa8cSmrg	    auth->number_length = 0;
1090629baa8cSmrg	}
1091629baa8cSmrg	auth->number = number;
1092629baa8cSmrg	Debug ("setAuthNumber: %s\n", number);
1093629baa8cSmrg    }
1094629baa8cSmrg}
1095629baa8cSmrg
1096629baa8cSmrgstatic void
1097629baa8cSmrgwriteLocalAuth (FILE *file, Xauth *auth, char *name)
1098629baa8cSmrg{
1099629baa8cSmrg    int	fd;
1100629baa8cSmrg
1101629baa8cSmrg    Debug ("writeLocalAuth: %s %.*s\n", name, auth->name_length, auth->name);
1102629baa8cSmrg    setAuthNumber (auth, name);
1103629baa8cSmrg#ifdef TCPCONN
1104629baa8cSmrg# if defined(IPv6) && defined(AF_INET6)
1105629baa8cSmrg    fd = socket (AF_INET6, SOCK_STREAM, 0);
1106629baa8cSmrg    if (fd < 0)
1107629baa8cSmrg# endif
1108629baa8cSmrg    fd = socket (AF_INET, SOCK_STREAM, 0);
1109629baa8cSmrg    DefineSelf (fd, file, auth);
1110629baa8cSmrg    close (fd);
1111629baa8cSmrg#endif
1112629baa8cSmrg    DefineLocal (file, auth);
1113629baa8cSmrg}
1114629baa8cSmrg
1115629baa8cSmrg#ifdef XDMCP
1116629baa8cSmrg
1117629baa8cSmrgstatic void
1118629baa8cSmrgwriteRemoteAuth (FILE *file, Xauth *auth, XdmcpNetaddr peer, int peerlen, char *name)
1119629baa8cSmrg{
1120629baa8cSmrg    int	    family = FamilyLocal;
1121629baa8cSmrg    char    *addr;
1122629baa8cSmrg
1123629baa8cSmrg    Debug ("writeRemoteAuth: %s %.*s\n", name, auth->name_length, auth->name);
1124629baa8cSmrg    if (!peer || peerlen < 2)
1125629baa8cSmrg	return;
1126629baa8cSmrg    setAuthNumber (auth, name);
1127629baa8cSmrg    family = ConvertAddr (peer, &peerlen, &addr);
1128629baa8cSmrg    Debug ("writeRemoteAuth: family %d\n", family);
1129629baa8cSmrg    if (family != FamilyLocal)
1130629baa8cSmrg    {
1131629baa8cSmrg	Debug ("writeRemoteAuth: %d, %d, %x\n",
1132629baa8cSmrg		family, peerlen, *(int *)addr);
1133629baa8cSmrg	writeAddr (family, peerlen, addr, file, auth);
1134629baa8cSmrg    }
1135629baa8cSmrg    else
1136629baa8cSmrg    {
1137629baa8cSmrg	writeLocalAuth (file, auth, name);
1138629baa8cSmrg    }
1139629baa8cSmrg}
1140629baa8cSmrg
1141629baa8cSmrg#endif /* XDMCP */
1142629baa8cSmrg
1143629baa8cSmrgvoid
1144629baa8cSmrgSetUserAuthorization (struct display *d, struct verify_info *verify)
1145629baa8cSmrg{
1146629baa8cSmrg    FILE	*old = NULL, *new;
1147629baa8cSmrg    char	home_name[1024], backup_name[1024], new_name[1024];
1148629baa8cSmrg    char	*name = NULL;
1149629baa8cSmrg    char	*home;
1150629baa8cSmrg    char	*envname = NULL;
1151629baa8cSmrg    int	lockStatus;
1152629baa8cSmrg    Xauth	*entry, **auths;
1153629baa8cSmrg    int		setenv = 0;
1154629baa8cSmrg    struct stat	statb;
1155629baa8cSmrg    int		i;
1156629baa8cSmrg    int		magicCookie;
1157629baa8cSmrg    int		data_len;
1158629baa8cSmrg#ifdef HAVE_MKSTEMP
1159629baa8cSmrg    int		fd;
1160629baa8cSmrg#endif
1161629baa8cSmrg
1162629baa8cSmrg    Debug ("SetUserAuthorization\n");
1163629baa8cSmrg    auths = d->authorizations;
1164629baa8cSmrg    if (auths) {
1165629baa8cSmrg	home = getEnv (verify->userEnviron, "HOME");
1166629baa8cSmrg	lockStatus = LOCK_ERROR;
1167629baa8cSmrg	if (home) {
1168629baa8cSmrg	    snprintf (home_name, sizeof(home_name), "%s/.Xauthority", home);
1169629baa8cSmrg	    Debug ("XauLockAuth %s\n", home_name);
1170629baa8cSmrg	    lockStatus = XauLockAuth (home_name, 1, 2, 10);
1171629baa8cSmrg	    Debug ("Lock is %d\n", lockStatus);
1172629baa8cSmrg	    if (lockStatus == LOCK_SUCCESS) {
1173629baa8cSmrg		if (openFiles (home_name, new_name, &old, &new)
1174629baa8cSmrg		    && (old != NULL) && (new != NULL)) {
1175629baa8cSmrg		    name = home_name;
1176629baa8cSmrg		    setenv = 0;
1177629baa8cSmrg		} else {
1178629baa8cSmrg		    Debug ("openFiles failed\n");
1179629baa8cSmrg		    XauUnlockAuth (home_name);
1180629baa8cSmrg		    lockStatus = LOCK_ERROR;
1181629baa8cSmrg		    if (old != NULL) {
1182629baa8cSmrg			(void) fclose (old);
1183629baa8cSmrg			old = NULL;
1184629baa8cSmrg		    }
1185629baa8cSmrg		    if (new != NULL)
1186629baa8cSmrg			(void) fclose (new);
1187629baa8cSmrg		}
1188629baa8cSmrg	    }
1189629baa8cSmrg	}
1190629baa8cSmrg	if (lockStatus != LOCK_SUCCESS) {
1191629baa8cSmrg	    snprintf (backup_name, sizeof(backup_name),
1192629baa8cSmrg		      "%s/.XauthXXXXXX", d->userAuthDir);
1193629baa8cSmrg#ifdef HAVE_MKSTEMP
1194629baa8cSmrg	    fd = mkstemp (backup_name);
1195629baa8cSmrg	    if (fd >= 0) {
1196629baa8cSmrg		old = fdopen (fd, "r");
1197629baa8cSmrg		if (old == NULL)
1198629baa8cSmrg		    (void) close(fd);
1199629baa8cSmrg	    }
1200629baa8cSmrg
1201629baa8cSmrg	    if (old != NULL)
1202629baa8cSmrg#else
1203629baa8cSmrg	    (void) mktemp (backup_name);
1204629baa8cSmrg#endif
1205629baa8cSmrg	    {
1206629baa8cSmrg		lockStatus = XauLockAuth (backup_name, 1, 2, 10);
1207629baa8cSmrg		Debug ("backup lock is %d\n", lockStatus);
1208629baa8cSmrg		if (lockStatus == LOCK_SUCCESS) {
1209629baa8cSmrg		    if (openFiles (backup_name, new_name, &old, &new)
1210629baa8cSmrg			&& (old != NULL) && (new != NULL)) {
1211629baa8cSmrg			name = backup_name;
1212629baa8cSmrg			setenv = 1;
1213629baa8cSmrg		    } else {
1214629baa8cSmrg			XauUnlockAuth (backup_name);
1215629baa8cSmrg			lockStatus = LOCK_ERROR;
1216629baa8cSmrg			if (old != NULL) {
1217629baa8cSmrg			    (void) fclose (old);
1218629baa8cSmrg			    old = NULL;
1219629baa8cSmrg			}
1220629baa8cSmrg			if (new != NULL)
1221629baa8cSmrg			    (void) fclose (new);
1222629baa8cSmrg		    }
1223629baa8cSmrg#ifdef HAVE_MKSTEMP
1224629baa8cSmrg		} else {
1225629baa8cSmrg		    (void) fclose (old);
1226629baa8cSmrg#endif
1227629baa8cSmrg		}
1228629baa8cSmrg	    }
1229629baa8cSmrg	}
1230629baa8cSmrg	if (lockStatus != LOCK_SUCCESS) {
1231629baa8cSmrg	    Debug ("can't lock auth file %s or backup %s\n",
1232629baa8cSmrg			    home_name, backup_name);
1233629baa8cSmrg	    LogError ("can't lock authorization file %s or backup %s\n",
1234629baa8cSmrg			    home_name, backup_name);
1235629baa8cSmrg	    return;
1236629baa8cSmrg	}
1237629baa8cSmrg	initAddrs ();
1238629baa8cSmrg	doWrite = 1;
1239629baa8cSmrg	Debug ("%d authorization protocols for %s\n", d->authNum, d->name);
1240629baa8cSmrg	/*
1241629baa8cSmrg	 * Write MIT-MAGIC-COOKIE-1 authorization first, so that
1242629baa8cSmrg	 * R4 clients which only knew that, and used the first
1243629baa8cSmrg	 * matching entry will continue to function
1244629baa8cSmrg	 */
1245629baa8cSmrg	magicCookie = -1;
1246629baa8cSmrg	for (i = 0; i < d->authNum; i++)
1247629baa8cSmrg	{
1248629baa8cSmrg	    if (auths[i]->name_length == 18 &&
1249629baa8cSmrg		!strncmp (auths[i]->name, "MIT-MAGIC-COOKIE-1", 18))
1250629baa8cSmrg	    {
1251629baa8cSmrg		magicCookie = i;
1252629baa8cSmrg		if (d->displayType.location == Local)
1253629baa8cSmrg		    writeLocalAuth (new, auths[i], d->name);
1254629baa8cSmrg#ifdef XDMCP
1255629baa8cSmrg		else
1256629baa8cSmrg		    writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
1257629baa8cSmrg#endif
1258629baa8cSmrg		break;
1259629baa8cSmrg	    }
1260629baa8cSmrg	}
1261629baa8cSmrg	/* now write other authorizations */
1262629baa8cSmrg	for (i = 0; i < d->authNum; i++)
1263629baa8cSmrg	{
1264629baa8cSmrg	    if (i != magicCookie)
1265629baa8cSmrg	    {
1266629baa8cSmrg		data_len = auths[i]->data_length;
1267629baa8cSmrg		/* client will just use default Kerberos cache, so don't
1268629baa8cSmrg		 * even write cache info into the authority file.
1269629baa8cSmrg		 */
1270629baa8cSmrg		if (auths[i]->name_length == 14 &&
1271629baa8cSmrg		    !strncmp (auths[i]->name, "MIT-KERBEROS-5", 14))
1272629baa8cSmrg		    auths[i]->data_length = 0;
1273629baa8cSmrg		if (d->displayType.location == Local)
1274629baa8cSmrg		    writeLocalAuth (new, auths[i], d->name);
1275629baa8cSmrg#ifdef XDMCP
1276629baa8cSmrg		else
1277629baa8cSmrg		    writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
1278629baa8cSmrg#endif
1279629baa8cSmrg		auths[i]->data_length = data_len;
1280629baa8cSmrg	    }
1281629baa8cSmrg	}
1282629baa8cSmrg	if (old) {
1283629baa8cSmrg	    if (fstat (fileno (old), &statb) != -1)
1284629baa8cSmrg		chmod (new_name, (int) (statb.st_mode & 0777));
1285629baa8cSmrg	    /*SUPPRESS 560*/
1286629baa8cSmrg	    while ((entry = XauReadAuth (old))) {
1287629baa8cSmrg		if (!checkEntry (entry))
1288629baa8cSmrg		{
1289629baa8cSmrg		    Debug ("Writing an entry\n");
1290629baa8cSmrg		    writeAuth (new, entry);
1291629baa8cSmrg		}
1292629baa8cSmrg		XauDisposeAuth (entry);
1293629baa8cSmrg	    }
1294629baa8cSmrg	    fclose (old);
1295629baa8cSmrg	}
1296629baa8cSmrg	doneAddrs ();
1297629baa8cSmrg	fclose (new);
1298629baa8cSmrg	if (unlink (name) == -1)
1299629baa8cSmrg	    if (errno != ENOENT)
1300629baa8cSmrg		LogError ("cannot remove old authorization file %s: %s\n",
1301629baa8cSmrg			  name, _SysErrorMsg (errno));
1302629baa8cSmrg	envname = name;
1303629baa8cSmrg	if (link (new_name, name) == -1) {
1304629baa8cSmrg	    LogError ("cannot link temporary authorization file %s to old "
1305629baa8cSmrg		      "location %s: %s\n", new_name, name,
1306629baa8cSmrg		      _SysErrorMsg (errno));
1307629baa8cSmrg	    setenv = 1;
1308629baa8cSmrg	    envname = new_name;
1309629baa8cSmrg	} else {
1310629baa8cSmrg	    Debug ("authorization file %s successfully updated\n", name);
1311629baa8cSmrg	    if (unlink (new_name))
1312629baa8cSmrg		if (errno != ENOENT)
1313629baa8cSmrg		    LogError ("cannot remove new authorization file %s:"
1314629baa8cSmrg			      " %s\n", new_name, _SysErrorMsg (errno));
1315629baa8cSmrg	}
1316629baa8cSmrg	if (setenv) {
1317629baa8cSmrg	    verify->userEnviron = setEnv (verify->userEnviron,
1318629baa8cSmrg				    "XAUTHORITY", envname);
1319629baa8cSmrg	    verify->systemEnviron = setEnv (verify->systemEnviron,
1320629baa8cSmrg				    "XAUTHORITY", envname);
1321629baa8cSmrg	}
1322629baa8cSmrg	XauUnlockAuth (name);
1323629baa8cSmrg	if (envname)
1324629baa8cSmrg	    chown (envname, verify->uid, verify->gid);
1325629baa8cSmrg    }
1326629baa8cSmrg    Debug ("done SetUserAuthorization\n");
1327629baa8cSmrg}
1328629baa8cSmrg
1329629baa8cSmrgvoid
1330629baa8cSmrgRemoveUserAuthorization (struct display *d, struct verify_info *verify)
1331629baa8cSmrg{
1332629baa8cSmrg    char    *home;
1333629baa8cSmrg    Xauth   **auths, *entry;
1334629baa8cSmrg    char    name[1024], new_name[1024];
1335629baa8cSmrg    int	    lockStatus;
1336629baa8cSmrg    FILE    *old, *new;
1337629baa8cSmrg    struct stat	statb;
1338629baa8cSmrg    int	    i;
1339629baa8cSmrg
1340629baa8cSmrg    if (!(auths = d->authorizations))
1341629baa8cSmrg	return;
1342629baa8cSmrg    home = getEnv (verify->userEnviron, "HOME");
1343629baa8cSmrg    if (!home)
1344629baa8cSmrg	return;
1345629baa8cSmrg    Debug ("RemoveUserAuthorization\n");
1346629baa8cSmrg    snprintf(name, sizeof(name), "%s/.Xauthority", home);
1347629baa8cSmrg    Debug ("XauLockAuth %s\n", name);
1348629baa8cSmrg    lockStatus = XauLockAuth (name, 1, 2, 10);
1349629baa8cSmrg    Debug ("Lock is %d\n", lockStatus);
1350629baa8cSmrg    if (lockStatus != LOCK_SUCCESS)
1351629baa8cSmrg	return;
1352629baa8cSmrg    old = NULL;
1353629baa8cSmrg    if (openFiles (name, new_name, &old, &new))
1354629baa8cSmrg    {
1355629baa8cSmrg	initAddrs ();
1356629baa8cSmrg	doWrite = 0;
1357629baa8cSmrg	for (i = 0; i < d->authNum; i++)
1358629baa8cSmrg	{
1359629baa8cSmrg	    if (d->displayType.location == Local)
1360629baa8cSmrg		writeLocalAuth (new, auths[i], d->name);
1361629baa8cSmrg#ifdef XDMCP
1362629baa8cSmrg	    else
1363629baa8cSmrg		writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
1364629baa8cSmrg#endif
1365629baa8cSmrg	}
1366629baa8cSmrg	doWrite = 1;
1367629baa8cSmrg	if (old) {
1368629baa8cSmrg	    if (fstat (fileno (old), &statb) != -1)
1369629baa8cSmrg		chmod (new_name, (int) (statb.st_mode & 0777));
1370629baa8cSmrg	    /*SUPPRESS 560*/
1371629baa8cSmrg	    while ((entry = XauReadAuth (old))) {
1372629baa8cSmrg		if (!checkEntry (entry))
1373629baa8cSmrg		{
1374629baa8cSmrg		    Debug ("Writing an entry\n");
1375629baa8cSmrg		    writeAuth (new, entry);
1376629baa8cSmrg		}
1377629baa8cSmrg		XauDisposeAuth (entry);
1378629baa8cSmrg	    }
1379629baa8cSmrg	    fclose (old);
1380629baa8cSmrg	}
1381629baa8cSmrg	doneAddrs ();
1382629baa8cSmrg	fclose (new);
1383629baa8cSmrg	if (unlink (name) == -1)
1384629baa8cSmrg	    if (errno != ENOENT)
1385629baa8cSmrg		LogError ("cannot remove new authorization file %s: %s\n",
1386629baa8cSmrg			  name, _SysErrorMsg (errno));
1387629baa8cSmrg	if (link (new_name, name) == -1) {
1388629baa8cSmrg	    LogError ("cannot link temporary authorization file %s to old "
1389629baa8cSmrg		      "location %s: %s\n", new_name, name,
1390629baa8cSmrg		      _SysErrorMsg (errno));
1391629baa8cSmrg	} else {
1392629baa8cSmrg	    Debug ("authorization file %s successfully updated\n", name);
1393629baa8cSmrg	    if (unlink (new_name))
1394629baa8cSmrg		if (errno != ENOENT)
1395629baa8cSmrg		    LogError ("cannot remove new authorization file %s:"
1396629baa8cSmrg			      " %s\n", new_name, _SysErrorMsg (errno));
1397629baa8cSmrg	}
1398629baa8cSmrg    }
1399629baa8cSmrg    XauUnlockAuth (name);
1400629baa8cSmrg}
1401