auth.c revision 1d778f8e
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
56629baa8cSmrg
57629baa8cSmrg#ifdef SVR4
58629baa8cSmrg# include <netdb.h>
59629baa8cSmrg# include <sys/sockio.h>
60629baa8cSmrg# include <sys/stropts.h>
61629baa8cSmrg#endif
62629baa8cSmrg#ifdef __GNU__
63629baa8cSmrg# include <netdb.h>
64629baa8cSmrg# undef SIOCGIFCONF
65629baa8cSmrg#else /* __GNU__ */
66629baa8cSmrg# include <net/if.h>
67629baa8cSmrg#endif /* __GNU__ */
68629baa8cSmrg
69629baa8cSmrg#if defined(TCPCONN) && !defined(WIN32)
70629baa8cSmrg# include <netinet/in.h>
71629baa8cSmrg#endif
72629baa8cSmrg
73629baa8cSmrg/* Solaris provides an extended interface SIOCGLIFCONF for IPv6 support.
74629baa8cSmrg */
75629baa8cSmrg#ifdef SIOCGLIFCONF
76629baa8cSmrg# define USE_SIOCGLIFCONF
77629baa8cSmrg#endif
78629baa8cSmrg
79629baa8cSmrg#ifdef HAVE_SYS_PARAM_H
80b7d26471Smrg# include <sys/param.h>
81629baa8cSmrg# ifdef BSD
82629baa8cSmrg#  if (BSD >= 199103)
83629baa8cSmrg#   define VARIABLE_IFREQ
84629baa8cSmrg#  endif
85629baa8cSmrg# endif
86629baa8cSmrg#endif
87629baa8cSmrg
88629baa8cSmrg
89629baa8cSmrgstruct AuthProtocol {
90629baa8cSmrg    unsigned short  name_length;
91b7d26471Smrg    const char	    *name;
92629baa8cSmrg    void	    (*InitAuth)(unsigned short len, char *name);
93629baa8cSmrg    Xauth	    *(*GetAuth)(unsigned short len, char *name);
94629baa8cSmrg    void	    (*GetXdmcpAuth)(
95629baa8cSmrg			struct protoDisplay	*pdpy,
96629baa8cSmrg			unsigned short	authorizationNameLen,
97629baa8cSmrg			char		*authorizationName);
98629baa8cSmrg    int		    inited;
99629baa8cSmrg};
100629baa8cSmrg
101629baa8cSmrgstatic struct AuthProtocol AuthProtocols[] = {
102629baa8cSmrg{ (unsigned short) 18,	"MIT-MAGIC-COOKIE-1",
103629baa8cSmrg    MitInitAuth, MitGetAuth, NULL
104629baa8cSmrg},
105629baa8cSmrg#ifdef HASXDMAUTH
106629baa8cSmrg{ (unsigned short) 19,	"XDM-AUTHORIZATION-1",
107629baa8cSmrg    XdmInitAuth, XdmGetAuth, XdmGetXdmcpAuth,
108629baa8cSmrg},
109629baa8cSmrg#endif
110629baa8cSmrg#ifdef SECURE_RPC
111629baa8cSmrg{ (unsigned short) 9, "SUN-DES-1",
112629baa8cSmrg    SecureRPCInitAuth, SecureRPCGetAuth, NULL,
113629baa8cSmrg},
114629baa8cSmrg#endif
115629baa8cSmrg#ifdef K5AUTH
116629baa8cSmrg{ (unsigned short) 14, "MIT-KERBEROS-5",
117629baa8cSmrg    Krb5InitAuth, Krb5GetAuth, NULL,
118629baa8cSmrg},
119629baa8cSmrg#endif
120629baa8cSmrg};
121629baa8cSmrg
122629baa8cSmrg#define NUM_AUTHORIZATION (sizeof (AuthProtocols) / sizeof (AuthProtocols[0]))
123629baa8cSmrg
124629baa8cSmrgstatic struct AuthProtocol *
125629baa8cSmrgfindProtocol (unsigned short name_length, char *name)
126629baa8cSmrg{
127629baa8cSmrg    int	i;
128629baa8cSmrg
129629baa8cSmrg    for (i = 0; i < NUM_AUTHORIZATION; i++)
130629baa8cSmrg	if (AuthProtocols[i].name_length == name_length &&
131629baa8cSmrg	    memcmp(AuthProtocols[i].name, name, name_length) == 0)
132629baa8cSmrg	{
133629baa8cSmrg	    return &AuthProtocols[i];
134629baa8cSmrg	}
135629baa8cSmrg    return (struct AuthProtocol *) 0;
136629baa8cSmrg}
137629baa8cSmrg
138629baa8cSmrgint
139629baa8cSmrgValidAuthorization (unsigned short name_length, char *name)
140629baa8cSmrg{
141629baa8cSmrg    if (findProtocol (name_length, name))
142629baa8cSmrg	return TRUE;
143629baa8cSmrg    return FALSE;
144629baa8cSmrg}
145629baa8cSmrg
146629baa8cSmrgstatic Xauth *
147629baa8cSmrgGenerateAuthorization (unsigned short name_length, char *name)
148629baa8cSmrg{
149629baa8cSmrg    struct AuthProtocol	*a;
150629baa8cSmrg    Xauth   *auth = NULL;
151629baa8cSmrg    int	    i;
152629baa8cSmrg
153629baa8cSmrg    Debug ("GenerateAuthorization %*.*s\n",
154629baa8cSmrg	    name_length, name_length, name);
155629baa8cSmrg    a = findProtocol (name_length, name);
156629baa8cSmrg    if (a)
157629baa8cSmrg    {
158629baa8cSmrg	if (!a->inited)
159629baa8cSmrg	{
160629baa8cSmrg	    (*a->InitAuth) (name_length, name);
161629baa8cSmrg	    a->inited = TRUE;
162629baa8cSmrg	}
163629baa8cSmrg	auth = (*a->GetAuth) (name_length, name);
164629baa8cSmrg	if (auth)
165629baa8cSmrg	{
166629baa8cSmrg	    Debug ("Got %p (%d %*.*s) ", auth,
167629baa8cSmrg		auth->name_length, auth->name_length,
168629baa8cSmrg		auth->name_length, auth->name);
169629baa8cSmrg	    for (i = 0; i < (int)auth->data_length; i++)
170629baa8cSmrg		Debug (" %02x", auth->data[i] & 0xff);
171629baa8cSmrg	    Debug ("\n");
172629baa8cSmrg	}
173629baa8cSmrg	else
174629baa8cSmrg	    Debug ("Got (null)\n");
175629baa8cSmrg    }
176629baa8cSmrg    else
177629baa8cSmrg    {
178629baa8cSmrg	Debug ("Unknown authorization %*.*s\n", name_length, name_length, name);
179629baa8cSmrg    }
180629baa8cSmrg    return auth;
181629baa8cSmrg}
182629baa8cSmrg
183629baa8cSmrg#ifdef XDMCP
184629baa8cSmrg
185629baa8cSmrgvoid
186629baa8cSmrgSetProtoDisplayAuthorization (
187629baa8cSmrg    struct protoDisplay	*pdpy,
188629baa8cSmrg    unsigned short	authorizationNameLen,
189629baa8cSmrg    char		*authorizationName)
190629baa8cSmrg{
191629baa8cSmrg    struct AuthProtocol	*a;
192629baa8cSmrg    Xauth   *auth;
193629baa8cSmrg
194629baa8cSmrg    a = findProtocol (authorizationNameLen, authorizationName);
195629baa8cSmrg    pdpy->xdmcpAuthorization = pdpy->fileAuthorization = NULL;
196629baa8cSmrg    if (a)
197629baa8cSmrg    {
198629baa8cSmrg	if (!a->inited)
199629baa8cSmrg	{
200629baa8cSmrg	    (*a->InitAuth) (authorizationNameLen, authorizationName);
201629baa8cSmrg	    a->inited = TRUE;
202629baa8cSmrg	}
203629baa8cSmrg	if (a->GetXdmcpAuth)
204629baa8cSmrg	{
205629baa8cSmrg	    (*a->GetXdmcpAuth) (pdpy, authorizationNameLen, authorizationName);
206629baa8cSmrg	    auth = pdpy->xdmcpAuthorization;
207629baa8cSmrg	}
208629baa8cSmrg	else
209629baa8cSmrg	{
210629baa8cSmrg	    auth = (*a->GetAuth) (authorizationNameLen, authorizationName);
211629baa8cSmrg	    pdpy->fileAuthorization = auth;
212629baa8cSmrg	    pdpy->xdmcpAuthorization = NULL;
213629baa8cSmrg	}
214629baa8cSmrg	if (auth)
215629baa8cSmrg	    Debug ("Got %p (%d %*.*s)\n", auth,
216629baa8cSmrg		auth->name_length, auth->name_length,
217629baa8cSmrg		auth->name_length, auth->name);
218629baa8cSmrg	else
219629baa8cSmrg	    Debug ("Got (null)\n");
220629baa8cSmrg    }
221629baa8cSmrg}
222629baa8cSmrg
223629baa8cSmrg#endif /* XDMCP */
224629baa8cSmrg
225629baa8cSmrgvoid
226629baa8cSmrgCleanUpFileName (char *src, char *dst, int len)
227629baa8cSmrg{
228629baa8cSmrg    while (*src) {
229629baa8cSmrg	if (--len <= 0)
230629baa8cSmrg		break;
231629baa8cSmrg	switch (*src & 0x7f)
232629baa8cSmrg	{
233629baa8cSmrg	case '/':
234629baa8cSmrg	    *dst++ = '_';
235629baa8cSmrg	    break;
236629baa8cSmrg	case '-':
237629baa8cSmrg	    *dst++ = '.';
238629baa8cSmrg	    break;
239629baa8cSmrg	default:
240629baa8cSmrg	    *dst++ = (*src & 0x7f);
241629baa8cSmrg	}
242629baa8cSmrg	++src;
243629baa8cSmrg    }
244629baa8cSmrg    *dst = '\0';
245629baa8cSmrg}
246629baa8cSmrg
247629baa8cSmrg/* Checks to see if specified directory exists, makes it if not
248da2e2ef6Smrg * Returns: 0 if already exists, 1 if created, < 0 if error occurred
249629baa8cSmrg */
250629baa8cSmrgstatic int
251629baa8cSmrgCheckServerAuthDir (const char *path, struct stat *statb, int mode)
252629baa8cSmrg{
253629baa8cSmrg    int r = stat(path, statb);
254629baa8cSmrg
255629baa8cSmrg    if (r != 0) {
256629baa8cSmrg	if (errno == ENOENT) {
257629baa8cSmrg	    r = mkdir(path, mode);
258629baa8cSmrg	    if (r < 0) {
259629baa8cSmrg		LogError ("cannot make authentication directory %s: %s\n",
260629baa8cSmrg			  path, _SysErrorMsg (errno));
261629baa8cSmrg	    } else {
262629baa8cSmrg		r = 1;
263629baa8cSmrg	    }
264629baa8cSmrg	} else {
265629baa8cSmrg	    LogError ("cannot access authentication directory %s: %s\n",
266629baa8cSmrg		      path, _SysErrorMsg (errno));
267629baa8cSmrg	}
268629baa8cSmrg    } else { /* Directory already exists */
269629baa8cSmrg	if (!S_ISDIR(statb->st_mode)) {
270629baa8cSmrg	    LogError ("cannot make authentication directory %s: %s\n",
271629baa8cSmrg		      path, "file with that name already exists");
272629baa8cSmrg	    return -1;
273629baa8cSmrg	}
274629baa8cSmrg    }
275629baa8cSmrg
276629baa8cSmrg    return r;
277629baa8cSmrg}
278629baa8cSmrg
279629baa8cSmrgstatic char authdir1[] = "authdir";
280629baa8cSmrgstatic char authdir2[] = "authfiles";
281629baa8cSmrg
282629baa8cSmrgstatic int
283629baa8cSmrgMakeServerAuthFile (struct display *d, FILE ** file)
284629baa8cSmrg{
285629baa8cSmrg    int len;
286629baa8cSmrg#ifdef MAXNAMELEN
287629baa8cSmrg# define NAMELEN	MAXNAMELEN
288629baa8cSmrg#else
289629baa8cSmrg# define NAMELEN	255
290629baa8cSmrg#endif
291629baa8cSmrg    char    cleanname[NAMELEN];
292629baa8cSmrg    int r;
293629baa8cSmrg#ifdef HAVE_MKSTEMP
294629baa8cSmrg    int fd;
295629baa8cSmrg#endif
296629baa8cSmrg    struct stat	statb;
297629baa8cSmrg
298629baa8cSmrg    *file = NULL;
299629baa8cSmrg
300629baa8cSmrg    if (!d->authFile) {
301629baa8cSmrg	if (d->clientAuthFile && *d->clientAuthFile) {
302629baa8cSmrg	    d->authFile = strdup(d->clientAuthFile);
303629baa8cSmrg	    if (!d->authFile)
304629baa8cSmrg		return FALSE;
305629baa8cSmrg	} else {
306629baa8cSmrg	    CleanUpFileName (d->name, cleanname, NAMELEN - 8);
307629baa8cSmrg
308629baa8cSmrg	    /* Make authDir if it doesn't already exist */
309629baa8cSmrg	    r = CheckServerAuthDir(authDir, &statb, 0755);
310629baa8cSmrg	    if (r < 0) {
311629baa8cSmrg		return FALSE;
312629baa8cSmrg	    }
313629baa8cSmrg
314629baa8cSmrg	    len = strlen (authDir) + strlen (authdir1) + strlen (authdir2)
315629baa8cSmrg		+ strlen (cleanname) + 14;
316629baa8cSmrg	    d->authFile = malloc (len);
317629baa8cSmrg	    if (!d->authFile)
318629baa8cSmrg		return FALSE;
319629baa8cSmrg
320629baa8cSmrg	    snprintf (d->authFile, len, "%s/%s", authDir, authdir1);
321629baa8cSmrg	    r = CheckServerAuthDir(d->authFile, &statb, 0700);
322629baa8cSmrg	    if (r == 0) {
323629baa8cSmrg		if (statb.st_uid != 0)
324629baa8cSmrg		    (void) chown(d->authFile, 0, statb.st_gid);
325629baa8cSmrg		if ((statb.st_mode & 0077) != 0)
326629baa8cSmrg		    (void) chmod(d->authFile, statb.st_mode & 0700);
327629baa8cSmrg	    } else if (r < 0) {
328629baa8cSmrg		free (d->authFile);
329629baa8cSmrg		d->authFile = NULL;
330629baa8cSmrg		return FALSE;
331629baa8cSmrg	    }
332629baa8cSmrg
333629baa8cSmrg	    snprintf (d->authFile, len, "%s/%s/%s",
334629baa8cSmrg		      authDir, authdir1, authdir2);
335629baa8cSmrg	    r = CheckServerAuthDir(d->authFile, &statb, 0700);
336629baa8cSmrg	    if (r < 0) {
337629baa8cSmrg		free (d->authFile);
338629baa8cSmrg		d->authFile = NULL;
339629baa8cSmrg		return FALSE;
340629baa8cSmrg	    }
341629baa8cSmrg	    snprintf (d->authFile, len, "%s/%s/%s/A%s-XXXXXX",
342629baa8cSmrg		      authDir, authdir1, authdir2, cleanname);
343629baa8cSmrg#ifdef HAVE_MKSTEMP
344629baa8cSmrg	    fd = mkstemp (d->authFile);
345629baa8cSmrg	    if (fd < 0) {
346629baa8cSmrg		LogError ("cannot make authentication file %s: %s\n",
347629baa8cSmrg			  d->authFile, _SysErrorMsg (errno));
348629baa8cSmrg		free (d->authFile);
349629baa8cSmrg		d->authFile = NULL;
350629baa8cSmrg		return FALSE;
351629baa8cSmrg	    }
352629baa8cSmrg
353629baa8cSmrg	    *file = fdopen(fd, "w");
354629baa8cSmrg	    if (!*file)
355629baa8cSmrg		(void) close (fd);
356629baa8cSmrg	    return TRUE;
357629baa8cSmrg#else
358629baa8cSmrg	    (void) mktemp (d->authFile);
359629baa8cSmrg#endif
360629baa8cSmrg	}
361629baa8cSmrg    }
362629baa8cSmrg
363629baa8cSmrg    (void) unlink (d->authFile);
364629baa8cSmrg    *file = fopen (d->authFile, "w");
365629baa8cSmrg    return TRUE;
366629baa8cSmrg}
367629baa8cSmrg
368629baa8cSmrgint
369629baa8cSmrgSaveServerAuthorizations (
370629baa8cSmrg    struct display  *d,
371629baa8cSmrg    Xauth	    **auths,
372629baa8cSmrg    int		    count)
373629baa8cSmrg{
374629baa8cSmrg    FILE	*auth_file;
375629baa8cSmrg    mode_t	mask;
376629baa8cSmrg    int		ret;
377629baa8cSmrg    int		i;
378629baa8cSmrg    const char	dummy_auth[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
379629baa8cSmrg		               "XXXXXXXXXXXXXXXXX"; /* 64 "X"s */
380629baa8cSmrg    int		err = 0;
381629baa8cSmrg
382629baa8cSmrg    mask = umask (0077);
383629baa8cSmrg    ret = MakeServerAuthFile(d, &auth_file);
384629baa8cSmrg    umask (mask);
385629baa8cSmrg    if (!ret)
386629baa8cSmrg	return FALSE;
387629baa8cSmrg    if (!auth_file) {
388629baa8cSmrg	LogError ("cannot open server authorization file %s: %s\n",
389629baa8cSmrg		  d->authFile, _SysErrorMsg (errno));
390629baa8cSmrg	ret = FALSE;
391629baa8cSmrg    }
392629baa8cSmrg    else
393629baa8cSmrg    {
394629baa8cSmrg	Debug ("File: %s auth: %p\n", d->authFile, auths);
395629baa8cSmrg	ret = TRUE;
396629baa8cSmrg	if (count == 0)
397629baa8cSmrg	{
398629baa8cSmrg		/*
399629baa8cSmrg		 * This is a crude hack to determine whether we really can
400629baa8cSmrg		 * write to the auth file even if we don't have real data
401629baa8cSmrg		 * to write right now.
402629baa8cSmrg		 */
403629baa8cSmrg
404629baa8cSmrg		/*
405629baa8cSmrg		 * Write garbage data to file to provoke ENOSPC and other
406629baa8cSmrg		 * errors.
407629baa8cSmrg		 */
408629baa8cSmrg		(void) fprintf (auth_file, "%s", dummy_auth);
409629baa8cSmrg		(void) fflush (auth_file);
410629baa8cSmrg		if (ferror (auth_file))
411629baa8cSmrg		{
412629baa8cSmrg		    err = errno;
413629baa8cSmrg		    ret = FALSE;
414629baa8cSmrg		}
415629baa8cSmrg		/*
416629baa8cSmrg		 * Rewind so that the garbage data is overwritten later.
417629baa8cSmrg		 */
418629baa8cSmrg		rewind(auth_file);
419629baa8cSmrg	}
420629baa8cSmrg	for (i = 0; i < count; i++)
421629baa8cSmrg	{
422629baa8cSmrg	    /*
423629baa8cSmrg	     * User-based auths may not have data until
424629baa8cSmrg	     * a user logs in.  In which case don't write
425629baa8cSmrg	     * to the auth file so xrdb and setup programs don't fail.
426629baa8cSmrg	     */
427b7d26471Smrg	    if (auths[i]->data_length > 0) {
428629baa8cSmrg		if (!XauWriteAuth (auth_file, auths[i]))
429629baa8cSmrg		{
430629baa8cSmrg		    Debug ("XauWriteAuth() failed\n");
431629baa8cSmrg		}
432629baa8cSmrg		(void) fflush (auth_file);
433629baa8cSmrg		if (ferror (auth_file))
434629baa8cSmrg		{
435629baa8cSmrg		    err = errno;
436629baa8cSmrg		    ret = FALSE;
437629baa8cSmrg		}
438b7d26471Smrg            }
439629baa8cSmrg	}
440629baa8cSmrg	/*
441629baa8cSmrg	 * XXX: This is not elegant, but stdio has no truncation function.
442629baa8cSmrg	 */
443629baa8cSmrg	if (ftruncate(fileno(auth_file), ftell(auth_file)))
444629baa8cSmrg	{
445629baa8cSmrg		Debug ("ftruncate() failed\n");
446629baa8cSmrg	}
447629baa8cSmrg	fclose (auth_file);
448629baa8cSmrg
449629baa8cSmrg    }
450629baa8cSmrg    if (ret == FALSE)
451629baa8cSmrg    {
452629baa8cSmrg	LogError ("Cannot write to server authorization file %s%s%s\n",
453629baa8cSmrg		  d->authFile,
454629baa8cSmrg		  err ? ": " : "",
455629baa8cSmrg		  err ? _SysErrorMsg (errno) : "");
456629baa8cSmrg	free (d->authFile);
457629baa8cSmrg	d->authFile = NULL;
458629baa8cSmrg    }
459629baa8cSmrg    return ret;
460629baa8cSmrg}
461629baa8cSmrg
462629baa8cSmrgvoid
463629baa8cSmrgSetLocalAuthorization (struct display *d)
464629baa8cSmrg{
465629baa8cSmrg    Xauth	*auth, **auths;
466629baa8cSmrg    int		i, j;
467629baa8cSmrg
468629baa8cSmrg    if (d->authorizations)
469629baa8cSmrg    {
470629baa8cSmrg	for (i = 0; i < d->authNum; i++)
471629baa8cSmrg	    XauDisposeAuth (d->authorizations[i]);
472629baa8cSmrg	free (d->authorizations);
473629baa8cSmrg	d->authorizations = (Xauth **) NULL;
474629baa8cSmrg	d->authNum = 0;
475629baa8cSmrg    }
476629baa8cSmrg    if (!d->authNames)
477629baa8cSmrg	return;
478629baa8cSmrg    for (i = 0; d->authNames[i]; i++)
479629baa8cSmrg	;
480629baa8cSmrg    d->authNameNum = i;
481629baa8cSmrg    free (d->authNameLens);
482629baa8cSmrg    d->authNameLens = malloc (d->authNameNum * sizeof (unsigned short));
483629baa8cSmrg    if (!d->authNameLens)
484629baa8cSmrg	return;
485629baa8cSmrg    for (i = 0; i < d->authNameNum; i++)
486629baa8cSmrg	d->authNameLens[i] = strlen (d->authNames[i]);
487629baa8cSmrg    auths = malloc (d->authNameNum * sizeof (Xauth *));
488629baa8cSmrg    if (!auths)
489629baa8cSmrg	return;
490629baa8cSmrg    j = 0;
491629baa8cSmrg    for (i = 0; i < d->authNameNum; i++)
492629baa8cSmrg    {
493629baa8cSmrg	auth = GenerateAuthorization (d->authNameLens[i], d->authNames[i]);
494629baa8cSmrg	if (auth)
495629baa8cSmrg	    auths[j++] = auth;
496629baa8cSmrg    }
497629baa8cSmrg    if (SaveServerAuthorizations (d, auths, j))
498629baa8cSmrg    {
499629baa8cSmrg	d->authorizations = auths;
500629baa8cSmrg	d->authNum = j;
501629baa8cSmrg    }
502629baa8cSmrg    else
503629baa8cSmrg    {
504629baa8cSmrg	for (i = 0; i < j; i++)
505629baa8cSmrg	    XauDisposeAuth (auths[i]);
506629baa8cSmrg	free (auths);
507629baa8cSmrg    }
508629baa8cSmrg}
509629baa8cSmrg
510629baa8cSmrg/*
511629baa8cSmrg * Set the authorization to use for xdm's initial connection
512629baa8cSmrg * to the X server.  Cannot use user-based authorizations
513629baa8cSmrg * because no one has logged in yet, so we don't have any
514629baa8cSmrg * user credentials.
515629baa8cSmrg * Well, actually we could use SUN-DES-1 because we tell the server
516629baa8cSmrg * to allow root in.  This is bogus and should be fixed.
517629baa8cSmrg */
518629baa8cSmrgvoid
519629baa8cSmrgSetAuthorization (struct display *d)
520629baa8cSmrg{
521629baa8cSmrg    register Xauth **auth = d->authorizations;
522629baa8cSmrg    int i;
523629baa8cSmrg
524629baa8cSmrg    for (i = 0; i < d->authNum; i++)
525629baa8cSmrg    {
526629baa8cSmrg	if (auth[i]->name_length == 9 &&
527629baa8cSmrg	    memcmp(auth[i]->name, "SUN-DES-1", 9) == 0)
528629baa8cSmrg	    continue;
529629baa8cSmrg	if (auth[i]->name_length == 14 &&
530629baa8cSmrg	    memcmp(auth[i]->name, "MIT-KERBEROS-5", 14) == 0)
531629baa8cSmrg	    continue;
532629baa8cSmrg	XSetAuthorization (auth[i]->name, (int) auth[i]->name_length,
533629baa8cSmrg			   auth[i]->data, (int) auth[i]->data_length);
534629baa8cSmrg    }
535629baa8cSmrg}
536629baa8cSmrg
537629baa8cSmrgstatic int
538629baa8cSmrgopenFiles (char *name, char *new_name, FILE **oldp, FILE **newp)
539629baa8cSmrg{
540629baa8cSmrg	mode_t	mask;
541629baa8cSmrg	int newfd;
542629baa8cSmrg
543629baa8cSmrg	strcpy (new_name, name);
544629baa8cSmrg	strcat (new_name, "-n");
545629baa8cSmrg	/*
546629baa8cSmrg	 * Set safe umask for file creation operations.
547629baa8cSmrg	 */
548629baa8cSmrg	mask = umask (0077);
549629baa8cSmrg	/*
550629baa8cSmrg	 * Unlink the authorization file we intend to create, and then open
551629baa8cSmrg	 * it with O_CREAT | O_EXCL to avoid race-based symlink attacks.
552629baa8cSmrg	 */
553629baa8cSmrg	(void) unlink (new_name);
554629baa8cSmrg	newfd = open (new_name, O_WRONLY | O_CREAT | O_EXCL, 0600);
555b7d26471Smrg	if (newfd >= 0) {
556629baa8cSmrg	    *newp = fdopen (newfd, "w");
557b7d26471Smrg	    if (*newp == NULL)
558b7d26471Smrg		close(newfd);
559b7d26471Smrg	}
560629baa8cSmrg	else
561629baa8cSmrg	{
562629baa8cSmrg	    LogError ("Cannot create file %s: %s\n", new_name,
563629baa8cSmrg		      _SysErrorMsg (errno));
564629baa8cSmrg	    *newp = NULL;
565629baa8cSmrg	}
566629baa8cSmrg	/*
567629baa8cSmrg	 * There are no more attempts to create files after this point;
568629baa8cSmrg	 * restore the original umask.
569629baa8cSmrg	 */
570629baa8cSmrg	(void) umask (mask);
571629baa8cSmrg	if (!*newp) {
572629baa8cSmrg		Debug ("can't open new file %s\n", new_name);
573629baa8cSmrg		return 0;
574629baa8cSmrg	}
575629baa8cSmrg	if (!*oldp)
576629baa8cSmrg	    *oldp = fopen (name, "r");
577629baa8cSmrg	Debug ("opens succeeded %s %s\n", name, new_name);
578629baa8cSmrg	return 1;
579629baa8cSmrg}
580629baa8cSmrg
581629baa8cSmrgstatic int
582629baa8cSmrgbinaryEqual (char *a, char *b, unsigned short len)
583629baa8cSmrg{
584629baa8cSmrg	while (len-- > 0)
585629baa8cSmrg		if (*a++ != *b++)
586629baa8cSmrg			return FALSE;
587629baa8cSmrg	return TRUE;
588629baa8cSmrg}
589629baa8cSmrg
590629baa8cSmrgstatic void
591629baa8cSmrgdumpBytes (unsigned short len, char *data)
592629baa8cSmrg{
593629baa8cSmrg	unsigned short	i;
594629baa8cSmrg
595629baa8cSmrg	Debug ("%d: ", len);
596629baa8cSmrg	for (i = 0; i < len; i++)
597629baa8cSmrg		Debug ("%02x ", data[i] & 0377);
598629baa8cSmrg	Debug ("\n");
599629baa8cSmrg}
600629baa8cSmrg
601629baa8cSmrgstatic void
602629baa8cSmrgdumpAuth (Xauth *auth)
603629baa8cSmrg{
604629baa8cSmrg	Debug ("family: %d\n", auth->family);
605629baa8cSmrg	Debug ("addr:   ");
606629baa8cSmrg	dumpBytes (auth->address_length, auth->address);
607629baa8cSmrg	Debug ("number: ");
608629baa8cSmrg	dumpBytes (auth->number_length, auth->number);
609629baa8cSmrg	Debug ("name:   ");
610629baa8cSmrg	dumpBytes (auth->name_length, auth->name);
611629baa8cSmrg	Debug ("data:   ");
612629baa8cSmrg	dumpBytes (auth->data_length, auth->data);
613629baa8cSmrg}
614629baa8cSmrg
615629baa8cSmrgstruct addrList {
616629baa8cSmrg	unsigned short	family;
617629baa8cSmrg	unsigned short	address_length;
618629baa8cSmrg	char	*address;
619629baa8cSmrg	unsigned short	number_length;
620629baa8cSmrg	char	*number;
621629baa8cSmrg	unsigned short	name_length;
622629baa8cSmrg	char	*name;
623629baa8cSmrg	struct addrList	*next;
624629baa8cSmrg};
625629baa8cSmrg
626629baa8cSmrgstatic struct addrList	*addrs;
627629baa8cSmrg
628629baa8cSmrgstatic void
629629baa8cSmrginitAddrs (void)
630629baa8cSmrg{
631629baa8cSmrg	addrs = NULL;
632629baa8cSmrg}
633629baa8cSmrg
634629baa8cSmrgstatic void
635629baa8cSmrgdoneAddrs (void)
636629baa8cSmrg{
637629baa8cSmrg	struct addrList	*a, *n;
638629baa8cSmrg	for (a = addrs; a; a = n) {
639629baa8cSmrg		n = a->next;
640629baa8cSmrg		free (a->address);
641629baa8cSmrg		free (a->number);
642629baa8cSmrg		free (a);
643629baa8cSmrg	}
644da2e2ef6Smrg	addrs = NULL;
645629baa8cSmrg}
646629baa8cSmrg
647629baa8cSmrgstatic int checkEntry (Xauth *auth);
648629baa8cSmrg
649629baa8cSmrgstatic void
650629baa8cSmrgsaveEntry (Xauth *auth)
651629baa8cSmrg{
652629baa8cSmrg	struct addrList	*new;
653629baa8cSmrg
654629baa8cSmrg	new = malloc (sizeof (struct addrList));
655629baa8cSmrg	if (!new) {
656629baa8cSmrg		LogOutOfMem ("saveEntry");
657629baa8cSmrg		return;
658629baa8cSmrg	}
659629baa8cSmrg	if ((new->address_length = auth->address_length) > 0) {
660629baa8cSmrg		new->address = malloc (auth->address_length);
661629baa8cSmrg		if (!new->address) {
662629baa8cSmrg			LogOutOfMem ("saveEntry");
663629baa8cSmrg			free (new);
664629baa8cSmrg			return;
665629baa8cSmrg		}
666f9f7a7f2Smrg		memcpy(new->address, auth->address, (int) auth->address_length);
667629baa8cSmrg	} else
668629baa8cSmrg		new->address = NULL;
669629baa8cSmrg	if ((new->number_length = auth->number_length) > 0) {
670629baa8cSmrg		new->number = malloc (auth->number_length);
671629baa8cSmrg		if (!new->number) {
672629baa8cSmrg			LogOutOfMem ("saveEntry");
673629baa8cSmrg			free (new->address);
674629baa8cSmrg			free (new);
675629baa8cSmrg			return;
676629baa8cSmrg		}
677f9f7a7f2Smrg		memcpy(new->number, auth->number, (int) auth->number_length);
678629baa8cSmrg	} else
679629baa8cSmrg		new->number = NULL;
680629baa8cSmrg	if ((new->name_length = auth->name_length) > 0) {
681629baa8cSmrg		new->name = malloc (auth->name_length);
682629baa8cSmrg		if (!new->name) {
683629baa8cSmrg			LogOutOfMem ("saveEntry");
684629baa8cSmrg			free (new->number);
685629baa8cSmrg			free (new->address);
686629baa8cSmrg			free (new);
687629baa8cSmrg			return;
688629baa8cSmrg		}
689f9f7a7f2Smrg		memcpy(new->name, auth->name, (int) auth->name_length);
690629baa8cSmrg	} else
691629baa8cSmrg		new->name = NULL;
692629baa8cSmrg	new->family = auth->family;
693629baa8cSmrg	new->next = addrs;
694629baa8cSmrg	addrs = new;
695629baa8cSmrg}
696629baa8cSmrg
697629baa8cSmrgstatic int
698629baa8cSmrgcheckEntry (Xauth *auth)
699629baa8cSmrg{
700629baa8cSmrg	struct addrList	*a;
701629baa8cSmrg
702629baa8cSmrg	for (a = addrs; a; a = a->next) {
703629baa8cSmrg		if (a->family == auth->family &&
704629baa8cSmrg		    a->address_length == auth->address_length &&
705629baa8cSmrg		    binaryEqual (a->address, auth->address, auth->address_length) &&
706629baa8cSmrg		    a->number_length == auth->number_length &&
707629baa8cSmrg		    binaryEqual (a->number, auth->number, auth->number_length) &&
708629baa8cSmrg		    a->name_length == auth->name_length &&
709629baa8cSmrg		    binaryEqual (a->name, auth->name, auth->name_length))
710629baa8cSmrg		{
711629baa8cSmrg			return 1;
712629baa8cSmrg		}
713629baa8cSmrg	}
714629baa8cSmrg	return 0;
715629baa8cSmrg}
716629baa8cSmrg
717629baa8cSmrgstatic int  doWrite;
718629baa8cSmrg
719629baa8cSmrgstatic void
720629baa8cSmrgwriteAuth (FILE *file, Xauth *auth)
721629baa8cSmrg{
722629baa8cSmrg    if (debugLevel >= 15) {	/* normally too verbose */
723629baa8cSmrg        Debug ("writeAuth: doWrite = %d\n", doWrite);
724629baa8cSmrg	dumpAuth (auth);	/* does Debug only */
725629baa8cSmrg    }
726629baa8cSmrg	if (doWrite)
727629baa8cSmrg	    XauWriteAuth (file, auth);
728629baa8cSmrg}
729629baa8cSmrg
730629baa8cSmrgstatic void
731629baa8cSmrgwriteAddr (
732629baa8cSmrg    int		family,
733629baa8cSmrg    int		addr_length,
734629baa8cSmrg    char	*addr,
735629baa8cSmrg    FILE	*file,
736629baa8cSmrg    Xauth	*auth)
737629baa8cSmrg{
738629baa8cSmrg	auth->family = (unsigned short) family;
739629baa8cSmrg	auth->address_length = addr_length;
740629baa8cSmrg	auth->address = addr;
741629baa8cSmrg	Debug ("writeAddr: writing and saving an entry\n");
742629baa8cSmrg	writeAuth (file, auth);
743629baa8cSmrg	saveEntry (auth);
744629baa8cSmrg}
745629baa8cSmrg
746629baa8cSmrgstatic void
747629baa8cSmrgDefineLocal (FILE *file, Xauth *auth)
748629baa8cSmrg{
749629baa8cSmrg	char	displayname[100];
750629baa8cSmrg	int	len = _XGetHostname (displayname, sizeof(displayname));
751629baa8cSmrg
752629baa8cSmrg/* Make sure this produces the same string as _XGetHostname in lib/X/XlibInt.c.
753629baa8cSmrg * Otherwise, Xau will not be able to find your cookies in the Xauthority file.
754629baa8cSmrg *
755629baa8cSmrg * Note: POSIX says that the ``nodename'' member of utsname does _not_ have
756629baa8cSmrg *       to have sufficient information for interfacing to the network,
757629baa8cSmrg *       and so, you may be better off using gethostname (if it exists).
758629baa8cSmrg */
759629baa8cSmrg
760629baa8cSmrg
761629baa8cSmrg	writeAddr (FamilyLocal, len, displayname, file, auth);
762629baa8cSmrg}
763629baa8cSmrg
764629baa8cSmrg#ifdef HAVE_GETIFADDRS
765629baa8cSmrg# include <ifaddrs.h>
766629baa8cSmrg
767629baa8cSmrgstatic void
768629baa8cSmrgDefineSelf(int fd, FILE *file, Xauth *auth)
769629baa8cSmrg{
770629baa8cSmrg    struct ifaddrs *ifap, *ifr;
771629baa8cSmrg    char *addr;
772629baa8cSmrg    int family, len;
773629baa8cSmrg
774629baa8cSmrg    Debug("DefineSelf\n");
775629baa8cSmrg    if (getifaddrs(&ifap) < 0)
776629baa8cSmrg	return;
777629baa8cSmrg    for (ifr = ifap; ifr != NULL; ifr = ifr->ifa_next) {
778629baa8cSmrg	len = sizeof(*(ifr->ifa_addr));
779629baa8cSmrg	family = ConvertAddr((XdmcpNetaddr)(ifr->ifa_addr), &len, &addr);
780629baa8cSmrg	if (family == -1 || family == FamilyLocal)
781629baa8cSmrg	    continue;
782629baa8cSmrg	/*
783629baa8cSmrg	 * don't write out 'localhost' entries, as
784629baa8cSmrg	 * they may conflict with other local entries.
785629baa8cSmrg	 * DefineLocal will always be called to add
786629baa8cSmrg	 * the local entry anyway, so this one can
787629baa8cSmrg	 * be tossed.
788629baa8cSmrg	 */
789629baa8cSmrg	if (family == FamilyInternet && len == 4 && addr[0] == 127)
790629baa8cSmrg	{
791629baa8cSmrg	    Debug ("Skipping localhost address\n");
792629baa8cSmrg	    continue;
793629baa8cSmrg	}
7941d778f8eSmrg# ifdef IPv6
795629baa8cSmrg	if(family == FamilyInternet6) {
796629baa8cSmrg	    if (IN6_IS_ADDR_LOOPBACK(((struct in6_addr *)addr))) {
797629baa8cSmrg		Debug ("Skipping IPv6 localhost address\n");
798629baa8cSmrg		continue;
799629baa8cSmrg	    }
800629baa8cSmrg	    /* Also skip XDM-AUTHORIZATION-1 */
801629baa8cSmrg	    if (auth->name_length == 19 &&
802629baa8cSmrg		strcmp(auth->name, "XDM-AUTHORIZATION-1") == 0) {
803629baa8cSmrg		Debug ("Skipping IPv6 XDM-AUTHORIZATION-1\n");
804629baa8cSmrg		continue;
805629baa8cSmrg	    }
806629baa8cSmrg	}
807629baa8cSmrg# endif
808629baa8cSmrg	writeAddr(family, len, addr, file, auth);
809629baa8cSmrg    }
810629baa8cSmrg    freeifaddrs(ifap);
811629baa8cSmrg    Debug("DefineSelf done\n");
812629baa8cSmrg}
813629baa8cSmrg#else  /* GETIFADDRS */
814629baa8cSmrg
815b7d26471Smrg# if defined(SIOCGIFCONF) || defined (USE_SIOCGLIFCONF)
816629baa8cSmrg
817b7d26471Smrg#  ifdef USE_SIOCGLIFCONF
818b7d26471Smrg#   define ifr_type    struct lifreq
819b7d26471Smrg#  else
820b7d26471Smrg#   define ifr_type    struct ifreq
821b7d26471Smrg#  endif
822629baa8cSmrg
823629baa8cSmrg/* Handle variable length ifreq in BNR2 and later */
824b7d26471Smrg#  ifdef VARIABLE_IFREQ
825b7d26471Smrg#   define ifr_size(p) (sizeof (struct ifreq) + \
826629baa8cSmrg		     (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \
827629baa8cSmrg		      p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0))
828b7d26471Smrg#  else
829b7d26471Smrg#   define ifr_size(p) (sizeof (ifr_type))
830b7d26471Smrg#  endif
831629baa8cSmrg
832629baa8cSmrg/* Define this host for access control.  Find all the hosts the OS knows about
833629baa8cSmrg * for this fd and add them to the selfhosts list.
834629baa8cSmrg */
835629baa8cSmrgstatic void
836629baa8cSmrgDefineSelf (int fd, FILE *file, Xauth *auth)
837629baa8cSmrg{
838629baa8cSmrg    char		buf[2048], *cp, *cplim;
839629baa8cSmrg    int 		len;
840629baa8cSmrg    char 		*addr;
841629baa8cSmrg    int 		family;
842629baa8cSmrg    register ifr_type  *ifr;
843b7d26471Smrg#  ifdef USE_SIOCGLIFCONF
844629baa8cSmrg    void *		bufptr = buf;
845629baa8cSmrg    size_t		buflen = sizeof(buf);
846629baa8cSmrg    struct lifconf	ifc;
847b7d26471Smrg#   ifdef SIOCGLIFNUM
848629baa8cSmrg    struct lifnum	ifn;
849b7d26471Smrg#   endif
850b7d26471Smrg#  else
851629baa8cSmrg    struct ifconf	ifc;
852b7d26471Smrg#  endif
853629baa8cSmrg
854b7d26471Smrg#  if defined(SIOCGLIFNUM) && defined(SIOCGLIFCONF)
855629baa8cSmrg    ifn.lifn_family = AF_UNSPEC;
856629baa8cSmrg    ifn.lifn_flags = 0;
857629baa8cSmrg    if (ioctl (fd, (int) SIOCGLIFNUM, (char *) &ifn) < 0)
858629baa8cSmrg	LogError ("Failed getting interface count");
859629baa8cSmrg    if (buflen < (ifn.lifn_count * sizeof(struct lifreq))) {
860629baa8cSmrg	buflen = ifn.lifn_count * sizeof(struct lifreq);
861629baa8cSmrg	bufptr = malloc(buflen);
862629baa8cSmrg    }
863b7d26471Smrg#  endif
864629baa8cSmrg
865b7d26471Smrg#  ifdef USE_SIOCGLIFCONF
866629baa8cSmrg    ifc.lifc_family = AF_UNSPEC;
867629baa8cSmrg    ifc.lifc_flags = 0;
868629baa8cSmrg    ifc.lifc_len = buflen;
869629baa8cSmrg    ifc.lifc_buf = bufptr;
870629baa8cSmrg
871b7d26471Smrg#   define IFC_IOCTL_REQ SIOCGLIFCONF
872b7d26471Smrg#   define IFC_IFC_REQ ifc.lifc_req
873b7d26471Smrg#   define IFC_IFC_LEN ifc.lifc_len
874b7d26471Smrg#   define IFR_IFR_ADDR ifr->lifr_addr
875b7d26471Smrg#   define IFR_IFR_NAME ifr->lifr_name
876629baa8cSmrg
877b7d26471Smrg#  else
878629baa8cSmrg    ifc.ifc_len = sizeof (buf);
879629baa8cSmrg    ifc.ifc_buf = buf;
880629baa8cSmrg
881b7d26471Smrg#   define IFC_IOCTL_REQ SIOCGIFCONF
882b7d26471Smrg#   define IFC_IFC_REQ ifc.ifc_req
883b7d26471Smrg#   define IFC_IFC_LEN ifc.ifc_len
884b7d26471Smrg#   define IFR_IFR_ADDR ifr->ifr_addr
885b7d26471Smrg#   define IFR_IFR_NAME ifr->ifr_name
886b7d26471Smrg#  endif
887629baa8cSmrg
8884901b09eSmrg    if (ioctl (fd, IFC_IOCTL_REQ, (char *) &ifc) < 0) {
889629baa8cSmrg        LogError ("Trouble getting network interface configuration");
890629baa8cSmrg
891b7d26471Smrg#  ifdef USE_SIOCGLIFCONF
892629baa8cSmrg	if (bufptr != buf) {
893629baa8cSmrg	    free(bufptr);
894629baa8cSmrg	}
895b7d26471Smrg#  endif
896629baa8cSmrg	return;
897629baa8cSmrg    }
898629baa8cSmrg
899629baa8cSmrg    cplim = (char *) IFC_IFC_REQ + IFC_IFC_LEN;
900629baa8cSmrg
901629baa8cSmrg    for (cp = (char *) IFC_IFC_REQ; cp < cplim; cp += ifr_size (ifr))
902629baa8cSmrg    {
903629baa8cSmrg	ifr = (ifr_type *) cp;
904b7d26471Smrg	family = ConvertAddr ((XdmcpNetaddr) &IFR_IFR_ADDR, &len, &addr);
905b7d26471Smrg	if (family < 0)
906b7d26471Smrg	    continue;
907b7d26471Smrg
908b7d26471Smrg	if (len == 0)
909b7d26471Smrg	{
910b7d26471Smrg	    Debug ("Skipping zero length address\n");
911b7d26471Smrg	    continue;
912b7d26471Smrg	}
913629baa8cSmrg	/*
914b7d26471Smrg	 * don't write out 'localhost' entries, as
915b7d26471Smrg	 * they may conflict with other local entries.
916b7d26471Smrg	 * DefineLocal will always be called to add
917b7d26471Smrg	 * the local entry anyway, so this one can
918b7d26471Smrg	 * be tossed.
919629baa8cSmrg	 */
920b7d26471Smrg	if (family == FamilyInternet && len == 4 &&
921b7d26471Smrg	    addr[0] == 127 && addr[1] == 0 &&
922b7d26471Smrg	    addr[2] == 0 && addr[3] == 1)
923629baa8cSmrg	{
924b7d26471Smrg	    Debug ("Skipping localhost address\n");
925b7d26471Smrg	    continue;
926b7d26471Smrg	}
9271d778f8eSmrg#  ifdef IPv6
928b7d26471Smrg	if (family == FamilyInternet6) {
929b7d26471Smrg	    if (IN6_IS_ADDR_LOOPBACK(((struct in6_addr *)addr))) {
930b7d26471Smrg		Debug ("Skipping IPv6 localhost address\n");
931629baa8cSmrg		continue;
932629baa8cSmrg	    }
933b7d26471Smrg	    /* Also skip XDM-AUTHORIZATION-1 */
934b7d26471Smrg	    if (auth->name_length == 19 &&
935b7d26471Smrg		strcmp(auth->name, "XDM-AUTHORIZATION-1") == 0) {
936b7d26471Smrg		Debug ("Skipping IPv6 XDM-AUTHORIZATION-1\n");
937b7d26471Smrg		continue;
938629baa8cSmrg	    }
939629baa8cSmrg	}
940b7d26471Smrg#  endif
941629baa8cSmrg	Debug ("DefineSelf: write network address, length %d\n", len);
942629baa8cSmrg	writeAddr (family, len, addr, file, auth);
943629baa8cSmrg    }
944629baa8cSmrg}
945629baa8cSmrg
946b7d26471Smrg# else /* SIOCGIFCONF */
947629baa8cSmrg
948629baa8cSmrg/* Define this host for access control.  Find all the hosts the OS knows about
949629baa8cSmrg * for this fd and add them to the selfhosts list.
950629baa8cSmrg */
951629baa8cSmrgstatic void
952629baa8cSmrgDefineSelf (int fd, int file, int auth)
953629baa8cSmrg{
954629baa8cSmrg    register int n;
955629baa8cSmrg    int	len;
956629baa8cSmrg    caddr_t	addr;
957629baa8cSmrg    int		family;
958629baa8cSmrg
959629baa8cSmrg    struct utsname name;
960629baa8cSmrg    register struct hostent  *hp;
961629baa8cSmrg
962629baa8cSmrg    union {
963629baa8cSmrg	struct  sockaddr   sa;
964629baa8cSmrg	struct  sockaddr_in  in;
965629baa8cSmrg    } saddr;
966629baa8cSmrg
967629baa8cSmrg    struct	sockaddr_in	*inetaddr;
968629baa8cSmrg
969629baa8cSmrg    /* hpux:
970629baa8cSmrg     * Why not use gethostname()?  Well, at least on my system, I've had to
971629baa8cSmrg     * make an ugly kernel patch to get a name longer than 8 characters, and
972629baa8cSmrg     * uname() lets me access to the whole string (it smashes release, you
973629baa8cSmrg     * see), whereas gethostname() kindly truncates it for me.
974629baa8cSmrg     */
975629baa8cSmrg    uname(&name);
976629baa8cSmrg    hp = gethostbyname (name.nodename);
977629baa8cSmrg    if (hp != NULL) {
978629baa8cSmrg	saddr.sa.sa_family = hp->h_addrtype;
979629baa8cSmrg	inetaddr = (struct sockaddr_in *) (&(saddr.sa));
980f9f7a7f2Smrg	memcpy(&(inetaddr->sin_addr), hp->h_addr, hp->h_length);
981629baa8cSmrg	family = ConvertAddr ( &(saddr.sa), &len, &addr);
982629baa8cSmrg	if ( family >= 0) {
983629baa8cSmrg	    writeAddr (FamilyInternet, sizeof (inetaddr->sin_addr),
984629baa8cSmrg			(char *) (&inetaddr->sin_addr), file, auth);
985629baa8cSmrg	}
986629baa8cSmrg    }
987629baa8cSmrg}
988629baa8cSmrg
989629baa8cSmrg
990b7d26471Smrg# endif /* SIOCGIFCONF else */
991629baa8cSmrg#endif /* HAVE_GETIFADDRS */
992629baa8cSmrg
993629baa8cSmrgstatic void
994629baa8cSmrgsetAuthNumber (Xauth *auth, char *name)
995629baa8cSmrg{
996629baa8cSmrg    char	*colon;
997629baa8cSmrg    char	*dot, *number;
998629baa8cSmrg
999629baa8cSmrg    Debug ("setAuthNumber %s\n", name);
1000629baa8cSmrg    colon = strrchr(name, ':');
1001629baa8cSmrg    if (colon) {
1002629baa8cSmrg	++colon;
1003629baa8cSmrg	dot = strchr(colon, '.');
1004629baa8cSmrg	if (dot)
1005629baa8cSmrg	    auth->number_length = dot - colon;
1006629baa8cSmrg	else
1007629baa8cSmrg	    auth->number_length = strlen (colon);
1008629baa8cSmrg	number = malloc (auth->number_length + 1);
1009629baa8cSmrg	if (number) {
1010629baa8cSmrg	    strncpy (number, colon, auth->number_length);
1011629baa8cSmrg	    number[auth->number_length] = '\0';
1012629baa8cSmrg	} else {
1013629baa8cSmrg	    LogOutOfMem ("setAuthNumber");
1014629baa8cSmrg	    auth->number_length = 0;
1015629baa8cSmrg	}
1016629baa8cSmrg	auth->number = number;
1017629baa8cSmrg	Debug ("setAuthNumber: %s\n", number);
1018629baa8cSmrg    }
1019629baa8cSmrg}
1020629baa8cSmrg
1021629baa8cSmrgstatic void
1022629baa8cSmrgwriteLocalAuth (FILE *file, Xauth *auth, char *name)
1023629baa8cSmrg{
1024629baa8cSmrg    int	fd;
1025629baa8cSmrg
1026629baa8cSmrg    Debug ("writeLocalAuth: %s %.*s\n", name, auth->name_length, auth->name);
1027629baa8cSmrg    setAuthNumber (auth, name);
1028629baa8cSmrg#ifdef TCPCONN
10291d778f8eSmrg# ifdef IPv6
1030629baa8cSmrg    fd = socket (AF_INET6, SOCK_STREAM, 0);
1031629baa8cSmrg    if (fd < 0)
1032629baa8cSmrg# endif
1033629baa8cSmrg    fd = socket (AF_INET, SOCK_STREAM, 0);
1034629baa8cSmrg    DefineSelf (fd, file, auth);
1035629baa8cSmrg    close (fd);
1036629baa8cSmrg#endif
1037629baa8cSmrg    DefineLocal (file, auth);
1038629baa8cSmrg}
1039629baa8cSmrg
1040629baa8cSmrg#ifdef XDMCP
1041629baa8cSmrg
1042629baa8cSmrgstatic void
1043629baa8cSmrgwriteRemoteAuth (FILE *file, Xauth *auth, XdmcpNetaddr peer, int peerlen, char *name)
1044629baa8cSmrg{
1045629baa8cSmrg    int	    family = FamilyLocal;
1046629baa8cSmrg    char    *addr;
1047629baa8cSmrg
1048629baa8cSmrg    Debug ("writeRemoteAuth: %s %.*s\n", name, auth->name_length, auth->name);
1049629baa8cSmrg    if (!peer || peerlen < 2)
1050629baa8cSmrg	return;
1051629baa8cSmrg    setAuthNumber (auth, name);
1052629baa8cSmrg    family = ConvertAddr (peer, &peerlen, &addr);
1053629baa8cSmrg    Debug ("writeRemoteAuth: family %d\n", family);
1054629baa8cSmrg    if (family != FamilyLocal)
1055629baa8cSmrg    {
1056629baa8cSmrg	Debug ("writeRemoteAuth: %d, %d, %x\n",
1057629baa8cSmrg		family, peerlen, *(int *)addr);
1058629baa8cSmrg	writeAddr (family, peerlen, addr, file, auth);
1059629baa8cSmrg    }
1060629baa8cSmrg    else
1061629baa8cSmrg    {
1062629baa8cSmrg	writeLocalAuth (file, auth, name);
1063629baa8cSmrg    }
1064629baa8cSmrg}
1065629baa8cSmrg
1066629baa8cSmrg#endif /* XDMCP */
1067629baa8cSmrg
1068629baa8cSmrgvoid
1069629baa8cSmrgSetUserAuthorization (struct display *d, struct verify_info *verify)
1070629baa8cSmrg{
1071629baa8cSmrg    FILE	*old = NULL, *new;
1072629baa8cSmrg    char	home_name[1024], backup_name[1024], new_name[1024];
1073629baa8cSmrg    char	*name = NULL;
1074629baa8cSmrg    char	*home;
1075629baa8cSmrg    char	*envname = NULL;
1076629baa8cSmrg    int	lockStatus;
1077629baa8cSmrg    Xauth	*entry, **auths;
1078629baa8cSmrg    int		setenv = 0;
1079629baa8cSmrg    struct stat	statb;
1080629baa8cSmrg    int		i;
1081629baa8cSmrg    int		magicCookie;
1082629baa8cSmrg    int		data_len;
1083629baa8cSmrg#ifdef HAVE_MKSTEMP
1084629baa8cSmrg    int		fd;
1085629baa8cSmrg#endif
1086629baa8cSmrg
1087629baa8cSmrg    Debug ("SetUserAuthorization\n");
1088629baa8cSmrg    auths = d->authorizations;
1089629baa8cSmrg    if (auths) {
1090629baa8cSmrg	home = getEnv (verify->userEnviron, "HOME");
1091629baa8cSmrg	lockStatus = LOCK_ERROR;
1092629baa8cSmrg	if (home) {
1093629baa8cSmrg	    snprintf (home_name, sizeof(home_name), "%s/.Xauthority", home);
1094629baa8cSmrg	    Debug ("XauLockAuth %s\n", home_name);
1095629baa8cSmrg	    lockStatus = XauLockAuth (home_name, 1, 2, 10);
1096629baa8cSmrg	    Debug ("Lock is %d\n", lockStatus);
1097629baa8cSmrg	    if (lockStatus == LOCK_SUCCESS) {
1098629baa8cSmrg		if (openFiles (home_name, new_name, &old, &new)
1099629baa8cSmrg		    && (old != NULL) && (new != NULL)) {
1100629baa8cSmrg		    name = home_name;
1101629baa8cSmrg		    setenv = 0;
1102629baa8cSmrg		} else {
1103629baa8cSmrg		    Debug ("openFiles failed\n");
1104629baa8cSmrg		    XauUnlockAuth (home_name);
1105629baa8cSmrg		    lockStatus = LOCK_ERROR;
1106629baa8cSmrg		    if (old != NULL) {
1107629baa8cSmrg			(void) fclose (old);
1108629baa8cSmrg			old = NULL;
1109629baa8cSmrg		    }
1110629baa8cSmrg		    if (new != NULL)
1111629baa8cSmrg			(void) fclose (new);
1112629baa8cSmrg		}
1113629baa8cSmrg	    }
1114629baa8cSmrg	}
1115629baa8cSmrg	if (lockStatus != LOCK_SUCCESS) {
1116629baa8cSmrg	    snprintf (backup_name, sizeof(backup_name),
1117629baa8cSmrg		      "%s/.XauthXXXXXX", d->userAuthDir);
1118629baa8cSmrg#ifdef HAVE_MKSTEMP
1119629baa8cSmrg	    fd = mkstemp (backup_name);
1120629baa8cSmrg	    if (fd >= 0) {
1121629baa8cSmrg		old = fdopen (fd, "r");
1122629baa8cSmrg		if (old == NULL)
1123629baa8cSmrg		    (void) close(fd);
1124629baa8cSmrg	    }
1125629baa8cSmrg
1126629baa8cSmrg	    if (old != NULL)
1127629baa8cSmrg#else
1128629baa8cSmrg	    (void) mktemp (backup_name);
1129629baa8cSmrg#endif
1130629baa8cSmrg	    {
1131629baa8cSmrg		lockStatus = XauLockAuth (backup_name, 1, 2, 10);
1132629baa8cSmrg		Debug ("backup lock is %d\n", lockStatus);
1133629baa8cSmrg		if (lockStatus == LOCK_SUCCESS) {
1134629baa8cSmrg		    if (openFiles (backup_name, new_name, &old, &new)
1135629baa8cSmrg			&& (old != NULL) && (new != NULL)) {
1136629baa8cSmrg			name = backup_name;
1137629baa8cSmrg			setenv = 1;
1138629baa8cSmrg		    } else {
1139629baa8cSmrg			XauUnlockAuth (backup_name);
1140629baa8cSmrg			lockStatus = LOCK_ERROR;
1141629baa8cSmrg			if (old != NULL) {
1142629baa8cSmrg			    (void) fclose (old);
1143629baa8cSmrg			    old = NULL;
1144629baa8cSmrg			}
1145629baa8cSmrg			if (new != NULL)
1146629baa8cSmrg			    (void) fclose (new);
1147629baa8cSmrg		    }
1148629baa8cSmrg#ifdef HAVE_MKSTEMP
1149629baa8cSmrg		} else {
1150629baa8cSmrg		    (void) fclose (old);
1151629baa8cSmrg#endif
1152629baa8cSmrg		}
1153629baa8cSmrg	    }
1154629baa8cSmrg	}
1155629baa8cSmrg	if (lockStatus != LOCK_SUCCESS) {
1156629baa8cSmrg	    Debug ("can't lock auth file %s or backup %s\n",
1157629baa8cSmrg			    home_name, backup_name);
1158629baa8cSmrg	    LogError ("can't lock authorization file %s or backup %s\n",
1159629baa8cSmrg			    home_name, backup_name);
1160629baa8cSmrg	    return;
1161629baa8cSmrg	}
1162629baa8cSmrg	initAddrs ();
1163629baa8cSmrg	doWrite = 1;
1164629baa8cSmrg	Debug ("%d authorization protocols for %s\n", d->authNum, d->name);
1165629baa8cSmrg	/*
1166629baa8cSmrg	 * Write MIT-MAGIC-COOKIE-1 authorization first, so that
1167629baa8cSmrg	 * R4 clients which only knew that, and used the first
1168629baa8cSmrg	 * matching entry will continue to function
1169629baa8cSmrg	 */
1170629baa8cSmrg	magicCookie = -1;
1171629baa8cSmrg	for (i = 0; i < d->authNum; i++)
1172629baa8cSmrg	{
1173629baa8cSmrg	    if (auths[i]->name_length == 18 &&
1174629baa8cSmrg		!strncmp (auths[i]->name, "MIT-MAGIC-COOKIE-1", 18))
1175629baa8cSmrg	    {
1176629baa8cSmrg		magicCookie = i;
1177629baa8cSmrg		if (d->displayType.location == Local)
1178629baa8cSmrg		    writeLocalAuth (new, auths[i], d->name);
1179629baa8cSmrg#ifdef XDMCP
1180629baa8cSmrg		else
1181629baa8cSmrg		    writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
1182629baa8cSmrg#endif
1183629baa8cSmrg		break;
1184629baa8cSmrg	    }
1185629baa8cSmrg	}
1186629baa8cSmrg	/* now write other authorizations */
1187629baa8cSmrg	for (i = 0; i < d->authNum; i++)
1188629baa8cSmrg	{
1189629baa8cSmrg	    if (i != magicCookie)
1190629baa8cSmrg	    {
1191629baa8cSmrg		data_len = auths[i]->data_length;
1192629baa8cSmrg		/* client will just use default Kerberos cache, so don't
1193629baa8cSmrg		 * even write cache info into the authority file.
1194629baa8cSmrg		 */
1195629baa8cSmrg		if (auths[i]->name_length == 14 &&
1196629baa8cSmrg		    !strncmp (auths[i]->name, "MIT-KERBEROS-5", 14))
1197629baa8cSmrg		    auths[i]->data_length = 0;
1198629baa8cSmrg		if (d->displayType.location == Local)
1199629baa8cSmrg		    writeLocalAuth (new, auths[i], d->name);
1200629baa8cSmrg#ifdef XDMCP
1201629baa8cSmrg		else
1202629baa8cSmrg		    writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
1203629baa8cSmrg#endif
1204629baa8cSmrg		auths[i]->data_length = data_len;
1205629baa8cSmrg	    }
1206629baa8cSmrg	}
1207629baa8cSmrg	if (old) {
1208629baa8cSmrg	    if (fstat (fileno (old), &statb) != -1)
1209629baa8cSmrg		chmod (new_name, (int) (statb.st_mode & 0777));
1210629baa8cSmrg	    /*SUPPRESS 560*/
1211629baa8cSmrg	    while ((entry = XauReadAuth (old))) {
1212629baa8cSmrg		if (!checkEntry (entry))
1213629baa8cSmrg		{
1214629baa8cSmrg		    Debug ("Writing an entry\n");
1215629baa8cSmrg		    writeAuth (new, entry);
1216629baa8cSmrg		}
1217629baa8cSmrg		XauDisposeAuth (entry);
1218629baa8cSmrg	    }
1219629baa8cSmrg	    fclose (old);
1220629baa8cSmrg	}
1221629baa8cSmrg	doneAddrs ();
1222629baa8cSmrg	fclose (new);
1223629baa8cSmrg	if (unlink (name) == -1)
1224629baa8cSmrg	    if (errno != ENOENT)
1225629baa8cSmrg		LogError ("cannot remove old authorization file %s: %s\n",
1226629baa8cSmrg			  name, _SysErrorMsg (errno));
1227629baa8cSmrg	envname = name;
1228629baa8cSmrg	if (link (new_name, name) == -1) {
1229629baa8cSmrg	    LogError ("cannot link temporary authorization file %s to old "
1230629baa8cSmrg		      "location %s: %s\n", new_name, name,
1231629baa8cSmrg		      _SysErrorMsg (errno));
1232629baa8cSmrg	    setenv = 1;
1233629baa8cSmrg	    envname = new_name;
1234629baa8cSmrg	} else {
1235629baa8cSmrg	    Debug ("authorization file %s successfully updated\n", name);
1236629baa8cSmrg	    if (unlink (new_name))
1237629baa8cSmrg		if (errno != ENOENT)
1238629baa8cSmrg		    LogError ("cannot remove new authorization file %s:"
1239629baa8cSmrg			      " %s\n", new_name, _SysErrorMsg (errno));
1240629baa8cSmrg	}
1241629baa8cSmrg	if (setenv) {
1242629baa8cSmrg	    verify->userEnviron = setEnv (verify->userEnviron,
1243629baa8cSmrg				    "XAUTHORITY", envname);
1244629baa8cSmrg	    verify->systemEnviron = setEnv (verify->systemEnviron,
1245629baa8cSmrg				    "XAUTHORITY", envname);
1246629baa8cSmrg	}
1247629baa8cSmrg	XauUnlockAuth (name);
1248629baa8cSmrg	if (envname)
1249629baa8cSmrg	    chown (envname, verify->uid, verify->gid);
1250629baa8cSmrg    }
1251629baa8cSmrg    Debug ("done SetUserAuthorization\n");
1252629baa8cSmrg}
1253629baa8cSmrg
1254629baa8cSmrgvoid
1255629baa8cSmrgRemoveUserAuthorization (struct display *d, struct verify_info *verify)
1256629baa8cSmrg{
1257629baa8cSmrg    char    *home;
1258629baa8cSmrg    Xauth   **auths, *entry;
1259629baa8cSmrg    char    name[1024], new_name[1024];
1260629baa8cSmrg    int	    lockStatus;
1261629baa8cSmrg    FILE    *old, *new;
1262629baa8cSmrg    struct stat	statb;
1263629baa8cSmrg    int	    i;
1264629baa8cSmrg
1265629baa8cSmrg    if (!(auths = d->authorizations))
1266629baa8cSmrg	return;
1267629baa8cSmrg    home = getEnv (verify->userEnviron, "HOME");
1268629baa8cSmrg    if (!home)
1269629baa8cSmrg	return;
1270629baa8cSmrg    Debug ("RemoveUserAuthorization\n");
1271629baa8cSmrg    snprintf(name, sizeof(name), "%s/.Xauthority", home);
1272629baa8cSmrg    Debug ("XauLockAuth %s\n", name);
1273629baa8cSmrg    lockStatus = XauLockAuth (name, 1, 2, 10);
1274629baa8cSmrg    Debug ("Lock is %d\n", lockStatus);
1275629baa8cSmrg    if (lockStatus != LOCK_SUCCESS)
1276629baa8cSmrg	return;
1277629baa8cSmrg    old = NULL;
1278629baa8cSmrg    if (openFiles (name, new_name, &old, &new))
1279629baa8cSmrg    {
1280629baa8cSmrg	initAddrs ();
1281629baa8cSmrg	doWrite = 0;
1282629baa8cSmrg	for (i = 0; i < d->authNum; i++)
1283629baa8cSmrg	{
1284629baa8cSmrg	    if (d->displayType.location == Local)
1285629baa8cSmrg		writeLocalAuth (new, auths[i], d->name);
1286629baa8cSmrg#ifdef XDMCP
1287629baa8cSmrg	    else
1288629baa8cSmrg		writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
1289629baa8cSmrg#endif
1290629baa8cSmrg	}
1291629baa8cSmrg	doWrite = 1;
1292629baa8cSmrg	if (old) {
1293629baa8cSmrg	    if (fstat (fileno (old), &statb) != -1)
1294629baa8cSmrg		chmod (new_name, (int) (statb.st_mode & 0777));
1295629baa8cSmrg	    /*SUPPRESS 560*/
1296629baa8cSmrg	    while ((entry = XauReadAuth (old))) {
1297629baa8cSmrg		if (!checkEntry (entry))
1298629baa8cSmrg		{
1299629baa8cSmrg		    Debug ("Writing an entry\n");
1300629baa8cSmrg		    writeAuth (new, entry);
1301629baa8cSmrg		}
1302629baa8cSmrg		XauDisposeAuth (entry);
1303629baa8cSmrg	    }
1304629baa8cSmrg	    fclose (old);
1305629baa8cSmrg	}
1306629baa8cSmrg	doneAddrs ();
1307629baa8cSmrg	fclose (new);
1308629baa8cSmrg	if (unlink (name) == -1)
1309629baa8cSmrg	    if (errno != ENOENT)
1310629baa8cSmrg		LogError ("cannot remove new authorization file %s: %s\n",
1311629baa8cSmrg			  name, _SysErrorMsg (errno));
1312629baa8cSmrg	if (link (new_name, name) == -1) {
1313629baa8cSmrg	    LogError ("cannot link temporary authorization file %s to old "
1314629baa8cSmrg		      "location %s: %s\n", new_name, name,
1315629baa8cSmrg		      _SysErrorMsg (errno));
1316629baa8cSmrg	} else {
1317629baa8cSmrg	    Debug ("authorization file %s successfully updated\n", name);
1318629baa8cSmrg	    if (unlink (new_name))
1319629baa8cSmrg		if (errno != ENOENT)
1320629baa8cSmrg		    LogError ("cannot remove new authorization file %s:"
1321629baa8cSmrg			      " %s\n", new_name, _SysErrorMsg (errno));
1322629baa8cSmrg	}
1323629baa8cSmrg    }
1324629baa8cSmrg    XauUnlockAuth (name);
1325629baa8cSmrg}
1326