Home | History | Annotate | Line # | Download | only in xdm
      1 /*
      2  * Copyright (c) 2002, Oracle and/or its affiliates.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  */
     23 /*
     24  *
     25 Copyright 1990, 1998  The Open Group
     26 
     27 Permission to use, copy, modify, distribute, and sell this software and its
     28 documentation for any purpose is hereby granted without fee, provided that
     29 the above copyright notice appear in all copies and that both that
     30 copyright notice and this permission notice appear in supporting
     31 documentation.
     32 
     33 The above copyright notice and this permission notice shall be included in
     34 all copies or substantial portions of the Software.
     35 
     36 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     37 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     38 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     39 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     40 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     41 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     42 
     43 Except as contained in this notice, the name of a copyright holder shall not be
     44 used in advertising or otherwise to promote the sale, use or other dealings
     45 in this Software without prior written authorization from the copyright holder.
     46  *
     47  * Author:  Keith Packard, MIT X Consortium
     48  */
     49 
     50 
     51 /*
     52  * Access control for XDMCP - keep a database of allowable display addresses
     53  * and (potentially) a list of hosts to send ForwardQuery packets to
     54  */
     55 
     56 #include   "dm.h"
     57 #include   "dm_error.h"
     58 
     59 #ifdef XDMCP
     60 
     61 # include   <X11/Xos.h>
     62 # include   <X11/Xdmcp.h>
     63 # include   <X11/X.h>
     64 # include   <stdio.h>
     65 # include   <ctype.h>
     66 
     67 # include   "dm_socket.h"
     68 
     69 # include   <netdb.h>
     70 
     71 # ifdef IPv6
     72 #  include        <arpa/inet.h>
     73 # endif
     74 
     75 # if defined(IPv6) && !defined(AF_INET6)
     76 #  error "Cannot build IPv6 support without AF_INET6"
     77 # endif
     78 
     79 # define ALIAS_CHARACTER	    '%'
     80 # define NEGATE_CHARACTER    '!'
     81 # define CHOOSER_STRING	    "CHOOSER"
     82 # define BROADCAST_STRING    "BROADCAST"
     83 # define NOBROADCAST_STRING  "NOBROADCAST"
     84 # define LISTEN_STRING	    "LISTEN"
     85 # define WILDCARD_STRING	    "*"
     86 
     87 # define HOST_ALIAS	    0
     88 # define HOST_ADDRESS	    1
     89 # define HOST_BROADCAST	    2
     90 # define HOST_CHOOSER	    3
     91 # define HOST_NOBROADCAST    4
     92 # define HOST_ANYADDR	    5
     93 
     94 typedef struct _hostEntry {
     95     struct _hostEntry	*next;
     96     int	    type;
     97     union _hostOrAlias {
     98 	char	*aliasName;
     99 	ARRAY8	hostAddress;
    100     } entry;
    101     int			hopCount;
    102 } HostEntry;
    103 
    104 # define DISPLAY_ALIAS	    0
    105 # define DISPLAY_PATTERN	    1
    106 # define DISPLAY_ADDRESS	    2
    107 # define DISPLAY_LISTEN	    3
    108 
    109 typedef struct _displayEntry {
    110     struct _displayEntry    *next;
    111     int			    type;
    112     int			    notAllowed;
    113     int			    notBroadcast;
    114     int			    chooser;
    115     union _displayType {
    116 	char		    *aliasName;
    117 	char		    *displayPattern;
    118 	struct _display {
    119 	    ARRAY8	    clientAddress;
    120 	    CARD16	    connectionType;
    121 	} displayAddress;
    122     } entry;
    123     HostEntry		    *hosts;
    124 } DisplayEntry;
    125 
    126 static DisplayEntry	*database;
    127 
    128 ARRAY8Ptr
    129 getLocalAddress (void)
    130 {
    131     static ARRAY8   localAddress;
    132     static int	haveLocalAddress;
    133 
    134     if (!haveLocalAddress)
    135     {
    136 # ifdef HAVE_GETADDRINFO
    137 	struct addrinfo *ai;
    138 	struct addrinfo hints = {
    139 #  ifdef IPv6
    140 	    .ai_family = AF_UNSPEC
    141 #  else
    142 	    .ai_family = AF_INET
    143 #  endif
    144 	};
    145 
    146 	if (getaddrinfo(localHostname(), NULL, &hints, &ai) != 0) {
    147 	    if (XdmcpAllocARRAY8 (&localAddress, 4)) {
    148 		localAddress.data[0] = 127;
    149 		localAddress.data[1] = 0;
    150 		localAddress.data[2] = 0;
    151 		localAddress.data[3] = 1;
    152 		haveLocalAddress = 1;
    153 	    }
    154 	} else {
    155 	    if (ai->ai_addr->sa_family == AF_INET) {
    156 		if (XdmcpAllocARRAY8 (&localAddress, sizeof(struct in_addr))) {
    157 		    memcpy(localAddress.data,
    158 			   &((struct sockaddr_in *)ai->ai_addr)->sin_addr,
    159 			   sizeof(struct in_addr));
    160 		    haveLocalAddress = 1;
    161 		}
    162 #  ifdef IPv6
    163 	    } else if (ai->ai_addr->sa_family == AF_INET6) {
    164 		if (XdmcpAllocARRAY8 (&localAddress, sizeof(struct in6_addr)))
    165 		{
    166 		    memcpy(localAddress.data,
    167 			   &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr,
    168 			   sizeof(struct in6_addr));
    169 		    haveLocalAddress = 1;
    170 		}
    171 #  endif
    172 	    }
    173 	    freeaddrinfo(ai);
    174 	}
    175 # else /* !HAVE_GETADDRINFO */
    176 	struct hostent	*hostent;
    177 
    178 	hostent = gethostbyname (localHostname());
    179 	if (hostent != NULL) {
    180 	    if (XdmcpAllocARRAY8 (&localAddress, hostent->h_length)) {
    181 		memcpy(localAddress.data, hostent->h_addr, hostent->h_length);
    182 		haveLocalAddress = 1;
    183 	    }
    184 	} else {
    185 	    /* Assume 127.0.0.1 */
    186 	    if (XdmcpAllocARRAY8 (&localAddress, 4)) {
    187 		localAddress.data[0] = 127;
    188 		localAddress.data[1] = 0;
    189 		localAddress.data[2] = 0;
    190 		localAddress.data[3] = 1;
    191 		haveLocalAddress = 1;
    192 	    }
    193 	}
    194 # endif
    195 
    196     }
    197     return &localAddress;
    198 }
    199 
    200 static void
    201 FreeHostEntry (HostEntry *h)
    202 {
    203     switch (h->type) {
    204     case HOST_ALIAS:
    205 	free (h->entry.aliasName);
    206 	break;
    207     case HOST_ADDRESS:
    208 	XdmcpDisposeARRAY8 (&h->entry.hostAddress);
    209 	break;
    210     case HOST_CHOOSER:
    211 	break;
    212     }
    213     free (h);
    214 }
    215 
    216 static void
    217 FreeDisplayEntry (DisplayEntry *d)
    218 {
    219     HostEntry	*h, *next;
    220     switch (d->type) {
    221     case DISPLAY_ALIAS:
    222 	free (d->entry.aliasName);
    223 	break;
    224     case DISPLAY_PATTERN:
    225 	free (d->entry.displayPattern);
    226 	break;
    227     case DISPLAY_ADDRESS:
    228 	XdmcpDisposeARRAY8 (&d->entry.displayAddress.clientAddress);
    229 	break;
    230     case DISPLAY_LISTEN:
    231 	/* do nothing - this case doesn't use the d->entry union */
    232 	break;
    233     }
    234     for (h = d->hosts; h; h = next) {
    235 	next = h->next;
    236 	FreeHostEntry (h);
    237     }
    238     free (d);
    239 }
    240 
    241 static void
    242 FreeAccessDatabase (void)
    243 {
    244     DisplayEntry    *d, *next;
    245 
    246     for (d = database; d; d = next)
    247     {
    248 	next = d->next;
    249 	FreeDisplayEntry (d);
    250     }
    251     database = NULL;
    252 }
    253 
    254 # define WORD_LEN    256
    255 static char	wordBuffer[WORD_LEN];
    256 static int	nextIsEOF;
    257 
    258 static char *
    259 ReadWord (FILE *file, int EOFatEOL)
    260 {
    261     int	    c;
    262     char    *wordp;
    263     int	    quoted;
    264 
    265     wordp = wordBuffer;
    266     if (nextIsEOF)
    267     {
    268 	nextIsEOF = FALSE;
    269 	return NULL;
    270     }
    271     quoted = FALSE;
    272     for (;wordp - wordBuffer < sizeof(wordBuffer)-2;) {
    273 	c = getc (file);
    274 	switch (c) {
    275 	case '#':
    276 	    if (quoted)
    277 	    {
    278 		*wordp++ = c;
    279 		break;
    280 	    }
    281 	    while ((c = getc (file)) != EOF && c != '\n')
    282 		;
    283 	case '\n':
    284 	case EOF:
    285 	    if (c == EOF || (EOFatEOL && !quoted))
    286 	    {
    287 		ungetc (c, file);
    288 		if (wordp == wordBuffer)
    289 		    return NULL;
    290 		*wordp = '\0';
    291 		nextIsEOF = TRUE;
    292 		return wordBuffer;
    293 	    }
    294 	case ' ':
    295 	case '\t':
    296 	    if (wordp != wordBuffer)
    297 	    {
    298 		ungetc (c, file);
    299 		*wordp = '\0';
    300 		return wordBuffer;
    301 	    }
    302 	    break;
    303 	case '\\':
    304 	    if (!quoted)
    305 	    {
    306 		quoted = TRUE;
    307 		continue;
    308 	    }
    309 	default:
    310 	    if (wordp < &(wordBuffer[WORD_LEN]))
    311 	      *wordp++ = c;
    312 	    break;
    313 	}
    314 	quoted = FALSE;
    315     }
    316     return NULL;
    317 }
    318 
    319 static HostEntry *
    320 ReadHostEntry (FILE *file)
    321 {
    322     char	    *hostOrAlias;
    323     HostEntry	    *h;
    324 
    325 tryagain:
    326     hostOrAlias = ReadWord (file, TRUE);
    327     if (!hostOrAlias)
    328 	return NULL;
    329     h = malloc (sizeof (DisplayEntry));
    330     if (!h)
    331     {
    332 	LogOutOfMem ("ReadHostEntry: DisplayEntry\n");
    333 	return NULL;
    334     }
    335     h->hopCount = 1;
    336     if (*hostOrAlias == ALIAS_CHARACTER)
    337     {
    338 	h->type = HOST_ALIAS;
    339 	h->entry.aliasName = strdup (hostOrAlias);
    340 	if (!h->entry.aliasName) {
    341 	    free (h);
    342 	    return NULL;
    343 	}
    344     }
    345     else if (!strcmp (hostOrAlias, CHOOSER_STRING))
    346     {
    347 	h->type = HOST_CHOOSER;
    348     }
    349     else if (!strcmp (hostOrAlias, BROADCAST_STRING))
    350     {
    351 	h->type = HOST_BROADCAST;
    352     }
    353     else if (!strcmp (hostOrAlias, NOBROADCAST_STRING))
    354     {
    355 	h->type = HOST_NOBROADCAST;
    356     }
    357     else if (!strcmp (hostOrAlias, WILDCARD_STRING))
    358     {
    359 	h->type = HOST_ANYADDR;
    360 	h->entry.hostAddress.length = 0;
    361     }
    362     else
    363     {
    364 	void *addr=NULL;
    365 	size_t addr_length=0;
    366 # ifdef HAVE_GETADDRINFO
    367 	struct addrinfo *ai = NULL;
    368 	struct addrinfo hints = {
    369 #  ifdef IPv6
    370 	    .ai_family = AF_UNSPEC
    371 #  else
    372 	    .ai_family = AF_INET
    373 #  endif
    374 	};
    375 # else
    376 	struct hostent	*hostent;
    377 # endif
    378 	char *hops = strrchr(hostOrAlias, '/');
    379 
    380 	if (hops) {
    381 	    *(hops++) = '\0';
    382 	    h->hopCount = strtol(hops, NULL, 10);
    383 	    if (h->hopCount < 1)
    384 		h->hopCount = 1;
    385 	}
    386 
    387 # ifdef HAVE_GETADDRINFO
    388 	if (getaddrinfo(hostOrAlias, NULL, &hints, &ai) == 0) {
    389 	    if (ai->ai_addr->sa_family == AF_INET) {
    390 		addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
    391 		addr_length = sizeof(struct in_addr);
    392 #  ifdef IPv6
    393 	    } else if (ai->ai_addr->sa_family == AF_INET6) {
    394 		addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
    395 		addr_length = sizeof(struct in6_addr);
    396 #  endif
    397 	    }
    398 	}
    399 # else /* !HAVE_GETADDRINFO */
    400 	hostent = gethostbyname (hostOrAlias);
    401 	if (hostent) {
    402 	    addr = hostent->h_addr;
    403 	    addr_length = hostent->h_length;
    404 	}
    405 # endif
    406 	h->type = HOST_ADDRESS;
    407 
    408 	if (!addr)
    409 	{
    410 	    Debug ("No such host %s\n", hostOrAlias);
    411 	    LogError ("Access file \"%s\", host \"%s\" not found\n", accessFile, hostOrAlias);
    412 	    free (h);
    413 # ifdef HAVE_GETADDRINFO
    414 	    if (ai)
    415 		freeaddrinfo(ai);
    416 # endif
    417 	    goto tryagain;
    418 	}
    419 	if (!XdmcpAllocARRAY8 (&h->entry.hostAddress, addr_length))
    420 	{
    421 	    LogOutOfMem ("ReadHostEntry\n");
    422 	    free (h);
    423 # ifdef HAVE_GETADDRINFO
    424 	    if (ai)
    425 		freeaddrinfo(ai);
    426 # endif
    427 	    return NULL;
    428 	}
    429 	memcpy(h->entry.hostAddress.data, addr, addr_length);
    430 # ifdef HAVE_GETADDRINFO
    431 	if (ai)
    432 	    freeaddrinfo(ai);
    433 # endif
    434     }
    435     return h;
    436 }
    437 
    438 static int
    439 HasGlobCharacters (char *s)
    440 {
    441     for (;;)
    442 	switch (*s++) {
    443 	case '?':
    444 	case '*':
    445 	    return 1;
    446 	case '\0':
    447 	    return 0;
    448 	}
    449 }
    450 
    451 static DisplayEntry *
    452 ReadDisplayEntry (FILE *file)
    453 {
    454     char	    *displayOrAlias;
    455     DisplayEntry    *d;
    456     struct _display *display;
    457     HostEntry	    *h, **prev;
    458 
    459 tryagain:
    460     displayOrAlias = ReadWord (file, FALSE);
    461     if (!displayOrAlias)
    462 	return NULL;
    463     d = malloc (sizeof (DisplayEntry));
    464     if (!d)
    465     {
    466 	LogOutOfMem ("ReadDisplayEntry: DisplayEntry\n");
    467 	return NULL;
    468     }
    469     d->notAllowed = 0;
    470     d->notBroadcast = 0;
    471     d->chooser = 0;
    472     if (*displayOrAlias == ALIAS_CHARACTER)
    473     {
    474 	d->type = DISPLAY_ALIAS;
    475 	d->entry.aliasName = strdup (displayOrAlias);
    476 	if (!d->entry.aliasName)
    477 	{
    478 	    free (d);
    479 	    return NULL;
    480 	}
    481     }
    482     else if (!strcmp(displayOrAlias, LISTEN_STRING))
    483     {
    484 	d->type = DISPLAY_LISTEN;
    485     }
    486     else
    487     {
    488 	if (*displayOrAlias == NEGATE_CHARACTER)
    489 	{
    490 	    d->notAllowed = 1;
    491 	    ++displayOrAlias;
    492 	}
    493 	if (HasGlobCharacters (displayOrAlias))
    494 	{
    495 	    d->type = DISPLAY_PATTERN;
    496 	    d->entry.displayPattern = strdup (displayOrAlias);
    497 	    if (!d->entry.displayPattern)
    498 	    {
    499 		free (d);
    500 		return NULL;
    501 	    }
    502 	}
    503 	else
    504 	{
    505 	    void *addr = NULL;
    506 	    size_t addr_length = 0;
    507 	    int addrtype = 0;
    508 
    509 # ifdef HAVE_GETADDRINFO
    510 	    struct addrinfo *ai = NULL;
    511 	    struct addrinfo hints = {
    512 #  ifdef IPv6
    513 		.ai_family = AF_UNSPEC
    514 #  else
    515 		.ai_family = AF_INET
    516 #  endif
    517 	    };
    518 
    519 	    if (getaddrinfo(displayOrAlias, NULL, &hints, &ai) == 0) {
    520 		addrtype = ai->ai_addr->sa_family;
    521 		if (addrtype == AF_INET) {
    522 		    addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
    523 		    addr_length = sizeof(struct in_addr);
    524 #  ifdef IPv6
    525 		} else if (addrtype == AF_INET6) {
    526 		    addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
    527 		    addr_length = sizeof(struct in6_addr);
    528 #  endif
    529 		}
    530 	    }
    531 # else /* !HAVE_GETADDRINFO */
    532 	    struct hostent  *hostent;
    533 
    534 	    if ((hostent = gethostbyname (displayOrAlias)) != NULL)
    535 	    {
    536 		Debug("ReadDisplayEntry: %s\n", displayOrAlias);
    537 		addr = hostent->h_addr;
    538 		addrtype = hostent->h_addrtype;
    539 		addr_length = hostent->h_length;
    540 	    }
    541 # endif
    542 	    if (addr == NULL)
    543 	    {
    544 		LogError ("Access file %s, display %s unknown\n", accessFile, displayOrAlias);
    545 		free (d);
    546 # ifdef HAVE_GETADDRINFO
    547 		if (ai)
    548 		    freeaddrinfo(ai);
    549 # endif
    550 		goto tryagain;
    551 	    }
    552 	    d->type = DISPLAY_ADDRESS;
    553 	    display = &d->entry.displayAddress;
    554 	    if (!XdmcpAllocARRAY8 (&display->clientAddress, addr_length))
    555 	    {
    556 		free (d);
    557 # ifdef HAVE_GETADDRINFO
    558 		if (ai)
    559 		    freeaddrinfo(ai);
    560 # endif
    561 		return NULL;
    562 	    }
    563 	    memcpy(display->clientAddress.data, addr, addr_length);
    564 # ifdef HAVE_GETADDRINFO
    565 	    if (ai)
    566 		freeaddrinfo(ai);
    567 # endif
    568 	    switch (addrtype)
    569 	    {
    570 # ifdef AF_UNIX
    571 	    case AF_UNIX:
    572 		display->connectionType = FamilyLocal;
    573 		break;
    574 # endif
    575 # ifdef AF_INET
    576 	    case AF_INET:
    577 		display->connectionType = FamilyInternet;
    578 		break;
    579 # endif
    580 # ifdef IPv6
    581 	    case AF_INET6:
    582 		display->connectionType = FamilyInternet6;
    583 		break;
    584 # endif
    585 	    default:
    586 		display->connectionType = FamilyLocal;
    587 		break;
    588 	    }
    589 	}
    590     }
    591     prev = &d->hosts;
    592     while ((h = ReadHostEntry (file)))
    593     {
    594 	if (h->type == HOST_CHOOSER)
    595 	{
    596 	    FreeHostEntry (h);
    597 	    d->chooser = 1;
    598 	} else if (h->type == HOST_NOBROADCAST) {
    599 	    FreeHostEntry (h);
    600 	    d->notBroadcast = 1;
    601 	} else if (h->type == HOST_ANYADDR) {
    602 	    if (d->type == DISPLAY_LISTEN) {
    603 		*prev = h;
    604 		prev = &h->next;
    605 	    } else {
    606 		Debug("Wildcard host specified in Xaccess for type other than LISTEN -- ignoring\n");
    607 		FreeHostEntry (h);
    608 	    }
    609 	} else {
    610 	    *prev = h;
    611 	    prev = &h->next;
    612 	}
    613     }
    614     *prev = NULL;
    615     return d;
    616 }
    617 
    618 static void
    619 ReadAccessDatabase (FILE *file)
    620 {
    621     DisplayEntry    *d, **prev;
    622 
    623     prev = &database;
    624     while ((d = ReadDisplayEntry (file)))
    625     {
    626 	*prev = d;
    627 	prev = &d->next;
    628     }
    629     *prev = NULL;
    630 }
    631 
    632 int
    633 ScanAccessDatabase (void)
    634 {
    635     FILE	*datafile;
    636 
    637     FreeAccessDatabase ();
    638     if (*accessFile)
    639     {
    640 	datafile = fopen (accessFile, "r");
    641 	if (!datafile)
    642 	{
    643 	    LogError ("Cannot open access control file %s, no XDMCP requests will be granted\n", accessFile);
    644 	    return 0;
    645 	}
    646 	ReadAccessDatabase (datafile);
    647 	fclose (datafile);
    648     }
    649     return 1;
    650 }
    651 
    652 /*
    653  * calls the given function for each valid indirect entry.  Returns TRUE if
    654  * the local host exists on any of the lists, else FALSE
    655  */
    656 
    657 # define MAX_DEPTH   32
    658 
    659 static int indirectAlias (
    660     char	*alias,
    661     ARRAY8Ptr	clientAddress,
    662     CARD16	connectionType,
    663     ChooserFunc	function,
    664     char	*closure,
    665     int		depth,
    666     int		broadcast);
    667 
    668 
    669 static int
    670 scanHostlist (
    671     HostEntry	*h,
    672     ARRAY8Ptr	clientAddress,
    673     CARD16	connectionType,
    674     ChooserFunc	function,
    675     char	*closure,
    676     int		depth,
    677     int		broadcast)
    678 {
    679     int	haveLocalhost = 0;
    680 
    681     for (; h; h = h->next)
    682     {
    683 	switch (h->type) {
    684 	case HOST_ALIAS:
    685 	    if (indirectAlias (h->entry.aliasName, clientAddress,
    686 			       connectionType, function, closure, depth,
    687 			       broadcast))
    688 		haveLocalhost = 1;
    689 	    break;
    690 	case HOST_ADDRESS:
    691 	    if (XdmcpARRAY8Equal (getLocalAddress(), &h->entry.hostAddress))
    692 		haveLocalhost = 1;
    693 	    else if (function)
    694 		(*function) (connectionType, &h->entry.hostAddress, closure);
    695 	    break;
    696 	case HOST_BROADCAST:
    697 	    if (broadcast)
    698 	    {
    699 		ARRAY8	temp;
    700 
    701 		if (function)
    702 		{
    703 		    temp.data = (BYTE *) BROADCAST_STRING;
    704 		    temp.length = strlen ((char *)temp.data);
    705 		    (*function) (connectionType, &temp, closure);
    706 		}
    707 	    }
    708 	    break;
    709 	}
    710     }
    711     return haveLocalhost;
    712 }
    713 
    714 /* Returns non-0 iff string is matched by pattern.  Does case folding.
    715  */
    716 static int
    717 patternMatch (const char *string, char *pattern)
    718 {
    719     int	    p, s;
    720 
    721     if (!string)
    722 	string = "";
    723 
    724     for (;;)
    725     {
    726 	s = *string++;
    727 	switch (p = *pattern++) {
    728 	case '*':
    729 	    if (!*pattern)
    730 		return 1;
    731 	    for (string--; *string; string++)
    732 		if (patternMatch (string, pattern))
    733 		    return 1;
    734 	    return 0;
    735 	case '?':
    736 	    if (s == '\0')
    737 		return 0;
    738 	    break;
    739 	case '\0':
    740 	    return s == '\0';
    741 	case '\\':
    742 	    p = *pattern++;
    743 	    /* fall through */
    744 	default:
    745 	    if (isupper(p)) p = tolower(p);
    746 	    if (isupper(s)) s = tolower(s);
    747 	    if (p != s)
    748 		return 0;
    749 	}
    750     }
    751 }
    752 
    753 static int
    754 indirectAlias (
    755     char	*alias,
    756     ARRAY8Ptr	clientAddress,
    757     CARD16	connectionType,
    758     ChooserFunc	function,
    759     char	*closure,
    760     int		depth,
    761     int		broadcast)
    762 {
    763     DisplayEntry    *d;
    764     int		    haveLocalhost = 0;
    765 
    766     if (depth == MAX_DEPTH)
    767 	return 0;
    768     for (d = database; d; d = d->next)
    769     {
    770 	if (d->type != DISPLAY_ALIAS || !patternMatch (alias, d->entry.aliasName))
    771 	    continue;
    772 	if (scanHostlist (d->hosts, clientAddress, connectionType,
    773 			  function, closure, depth + 1, broadcast))
    774 	{
    775 	    haveLocalhost = 1;
    776 	}
    777     }
    778     return haveLocalhost;
    779 }
    780 
    781 int ForEachMatchingIndirectHost (
    782     ARRAY8Ptr	clientAddress,
    783     CARD16	connectionType,
    784     ChooserFunc	function,
    785     char	*closure)
    786 {
    787     int		    haveLocalhost = 0;
    788     DisplayEntry    *d;
    789     char	    *clientName = NULL;
    790 
    791     for (d = database; d; d = d->next)
    792     {
    793 	switch (d->type) {
    794 	case DISPLAY_ALIAS:
    795 	case DISPLAY_LISTEN:
    796 	    continue;
    797 	case DISPLAY_PATTERN:
    798 	    if (!clientName)
    799 		clientName = NetworkAddressToHostname (connectionType,
    800 						       clientAddress);
    801 	    if (!patternMatch (clientName, d->entry.displayPattern))
    802 		continue;
    803 	    break;
    804 	case DISPLAY_ADDRESS:
    805 	    if (d->entry.displayAddress.connectionType != connectionType ||
    806 		!XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
    807 				  clientAddress))
    808 	    {
    809 		continue;
    810 	    }
    811 	    break;
    812 	}
    813 	if (!d->hosts)
    814 	    continue;
    815 	if (d->notAllowed)
    816 	    break;
    817 	if (d->chooser)
    818 	{
    819 	    ARRAY8Ptr	choice;
    820 
    821 	    choice = IndirectChoice (clientAddress, connectionType);
    822 	    if (!choice || XdmcpARRAY8Equal (getLocalAddress(), choice))
    823 		haveLocalhost = 1;
    824 	    else
    825 		(*function) (connectionType, choice, closure);
    826 	}
    827 	else if (scanHostlist (d->hosts, clientAddress, connectionType,
    828 			  function, closure, 0, FALSE))
    829 	{
    830 	    haveLocalhost = 1;
    831 	}
    832 	break;
    833     }
    834     free (clientName);
    835     return haveLocalhost;
    836 }
    837 
    838 int UseChooser (
    839     ARRAY8Ptr	clientAddress,
    840     CARD16	connectionType)
    841 {
    842     DisplayEntry    *d;
    843     char	    *clientName = NULL;
    844 
    845     for (d = database; d; d = d->next)
    846     {
    847 	switch (d->type) {
    848 	case DISPLAY_ALIAS:
    849 	case DISPLAY_LISTEN:
    850 	    continue;
    851 	case DISPLAY_PATTERN:
    852 	    if (!clientName)
    853 		clientName = NetworkAddressToHostname (connectionType,
    854 						       clientAddress);
    855 	    if (!patternMatch (clientName, d->entry.displayPattern))
    856 		continue;
    857 	    break;
    858 	case DISPLAY_ADDRESS:
    859 	    if (d->entry.displayAddress.connectionType != connectionType ||
    860 		!XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
    861 				  clientAddress))
    862 	    {
    863 		continue;
    864 	    }
    865 	    break;
    866 	}
    867 	if (!d->hosts)
    868 	    continue;
    869 	if (d->notAllowed)
    870 	    break;
    871 	if (d->chooser && !IndirectChoice (clientAddress, connectionType)) {
    872 	    free (clientName);
    873 	    return 1;
    874 	}
    875 	break;
    876     }
    877     free (clientName);
    878     return 0;
    879 }
    880 
    881 void ForEachChooserHost (
    882     ARRAY8Ptr	clientAddress,
    883     CARD16	connectionType,
    884     ChooserFunc	function,
    885     char	*closure)
    886 {
    887     int		    haveLocalhost = 0;
    888     DisplayEntry    *d;
    889     char	    *clientName = NULL;
    890 
    891     for (d = database; d; d = d->next)
    892     {
    893 	switch (d->type) {
    894 	case DISPLAY_ALIAS:
    895 	case DISPLAY_LISTEN:
    896 	    continue;
    897 	case DISPLAY_PATTERN:
    898 	    if (!clientName)
    899 		clientName = NetworkAddressToHostname (connectionType,
    900 						       clientAddress);
    901 	    if (!patternMatch (clientName, d->entry.displayPattern))
    902 		continue;
    903 	    break;
    904 	case DISPLAY_ADDRESS:
    905 	    if (d->entry.displayAddress.connectionType != connectionType ||
    906 		!XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
    907 				  clientAddress))
    908 	    {
    909 		continue;
    910 	    }
    911 	    break;
    912 	}
    913 	if (!d->hosts)
    914 	    continue;
    915 	if (d->notAllowed)
    916 	    break;
    917 	if (!d->chooser)
    918 	    break;
    919 	if (scanHostlist (d->hosts, clientAddress, connectionType,
    920 			  function, closure, 0, TRUE))
    921 	{
    922 	    haveLocalhost = 1;
    923 	}
    924 	break;
    925     }
    926     free (clientName);
    927     if (haveLocalhost)
    928 	(*function) (connectionType, getLocalAddress(), closure);
    929 }
    930 
    931 /*
    932  * returns TRUE if the given client is acceptable to the local host.  The
    933  * given display client is acceptable if it occurs without a host list.
    934  */
    935 
    936 int AcceptableDisplayAddress (
    937     ARRAY8Ptr	clientAddress,
    938     CARD16	connectionType,
    939     xdmOpCode	type)
    940 {
    941     DisplayEntry    *d;
    942     char	    *clientName = NULL;
    943 
    944     if (!*accessFile)
    945 	return 1;
    946     if (type == INDIRECT_QUERY)
    947 	return 1;
    948     for (d = database; d; d = d->next)
    949     {
    950 	if (d->hosts)
    951 	    continue;
    952 	switch (d->type) {
    953 	case DISPLAY_ALIAS:
    954 	case DISPLAY_LISTEN:
    955 	    continue;
    956 	case DISPLAY_PATTERN:
    957 	    if (!clientName)
    958 		clientName = NetworkAddressToHostname (connectionType,
    959 						       clientAddress);
    960 	    if (!patternMatch (clientName, d->entry.displayPattern))
    961 		continue;
    962 	    break;
    963 	case DISPLAY_ADDRESS:
    964 	    if (d->entry.displayAddress.connectionType != connectionType ||
    965 		!XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
    966 				  clientAddress))
    967 	    {
    968 		continue;
    969 	    }
    970 	    break;
    971 	}
    972 	break;
    973     }
    974     free (clientName);
    975     return (d != 0) && (d->notAllowed == 0)
    976 	&& (type == BROADCAST_QUERY ? d->notBroadcast == 0 : 1);
    977 }
    978 
    979 void ForEachListenAddr (
    980     ListenFunc	listenfunction,
    981     ListenFunc	mcastfunction,
    982     void	**closure)
    983 {
    984     DisplayEntry    *d;
    985     HostEntry	    *h;
    986     int		    listenFound = 0;
    987 
    988     for (d = database; d != NULL ; d = d->next)
    989     {
    990 	if (d->type == DISPLAY_LISTEN) {
    991 	    listenFound = 1;
    992 	    h = d->hosts;
    993 	    if (h != NULL) {
    994 		(*listenfunction) (&h->entry.hostAddress, closure);
    995 		for (h = h->next; h != NULL; h = h->next) {
    996 		    (*mcastfunction) (&h->entry.hostAddress, closure);
    997 		}
    998 	    }
    999 	}
   1000     }
   1001     if (!listenFound) {
   1002 	(*listenfunction) (NULL, closure);
   1003 # if defined(IPv6) && defined(XDM_DEFAULT_MCAST_ADDR6)
   1004 	{   /* Join default IPv6 Multicast Group */
   1005 
   1006 	    static ARRAY8	defaultMcastAddress;
   1007 
   1008 	    if (defaultMcastAddress.length == 0) {
   1009 		struct in6_addr addr6;
   1010 
   1011 		if (inet_pton(AF_INET6,XDM_DEFAULT_MCAST_ADDR6,&addr6) == 1) {
   1012 		    if (!XdmcpAllocARRAY8 (&defaultMcastAddress,
   1013 		      sizeof(struct in6_addr))) {
   1014 			LogOutOfMem ("ReadHostEntry\n");
   1015 			defaultMcastAddress.length = -1;
   1016 		    } else {
   1017 			memcpy(defaultMcastAddress.data, &addr6,
   1018 			  sizeof(struct in6_addr));
   1019 		    }
   1020 		} else {
   1021 		    defaultMcastAddress.length = -1;
   1022 		}
   1023 	    }
   1024 	    if ( defaultMcastAddress.length == sizeof(struct in6_addr) ) {
   1025 		(*mcastfunction) (&defaultMcastAddress, closure);
   1026 	    }
   1027 	}
   1028 # endif
   1029     }
   1030 }
   1031 
   1032 
   1033 #endif /* XDMCP */
   1034