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