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  * xdmcp.c - Support for XDMCP
     34  */
     35 
     36 #include "dm.h"
     37 #include "dm_auth.h"
     38 #include "dm_error.h"
     39 
     40 #ifdef XDMCP
     41 
     42 # include	<X11/X.h>
     43 # include	<X11/Xfuncs.h>
     44 # include	<sys/types.h>
     45 # include	<ctype.h>
     46 
     47 # include	"dm_socket.h"
     48 
     49 # include	<sys/un.h>
     50 # include	<netdb.h>
     51 # include	<arpa/inet.h>
     52 
     53 # include <time.h>
     54 # define Time_t time_t
     55 
     56 # define getString(name,len)	((name = malloc (len + 1)) ? 1 : 0)
     57 
     58 /*
     59  * misc externs
     60  */
     61 extern volatile int Rescan;
     62 extern int sourceAddress, ChildReady;
     63 
     64 /*
     65  * Forward reference
     66  */
     67 static void broadcast_respond (struct sockaddr *from, int fromlen, int length, int fd);
     68 static void forward_respond (struct sockaddr *from, int fromlen, int length, int fd);
     69 static void manage (struct sockaddr *from, int fromlen, int length, int fd);
     70 static void query_respond (struct sockaddr *from, int fromlen, int length, int fd);
     71 static void request_respond (struct sockaddr *from, int fromlen, int length, int fd);
     72 static void send_accept (struct sockaddr *to, int tolen, CARD32 sessionID, ARRAY8Ptr authenticationName, ARRAY8Ptr authenticationData, ARRAY8Ptr authorizationName, ARRAY8Ptr authorizationData, int fd);
     73 static void send_alive (struct sockaddr *from, int fromlen, int length, int fd);
     74 static void send_decline (struct sockaddr *to, int tolen, ARRAY8Ptr authenticationName, ARRAY8Ptr authenticationData, ARRAY8Ptr status, int fd);
     75 static void send_failed (struct sockaddr *from, int fromlen, const char *name, CARD32 sessionID, const char *reason, int fd);
     76 static void send_refuse (struct sockaddr *from, int fromlen, CARD32 sessionID, int fd);
     77 static void send_unwilling (struct sockaddr *from, int fromlen, ARRAY8Ptr authenticationName, ARRAY8Ptr status, int fd);
     78 static void send_willing (struct sockaddr *from, int fromlen, ARRAY8Ptr authenticationName, ARRAY8Ptr status, int fd);
     79 
     80 int	chooserFd = -1;
     81 # ifdef IPv6
     82 int	chooserFd6 = -1;
     83 # endif
     84 
     85 FD_TYPE	WellKnownSocketsMask;
     86 int	WellKnownSocketsMax;
     87 
     88 # define pS(s)	((s) ? ((char *) (s)) : "empty string")
     89 
     90 void
     91 DestroyWellKnownSockets (void)
     92 {
     93     if (chooserFd != -1)
     94     {
     95 	close (chooserFd);
     96 	FD_CLR(chooserFd, &WellKnownSocketsMask);
     97 	chooserFd = -1;
     98     }
     99 # ifdef IPv6
    100     if (chooserFd6 != -1)
    101     {
    102 	close (chooserFd6);
    103 	FD_CLR(chooserFd6, &WellKnownSocketsMask);
    104 	chooserFd6 = -1;
    105     }
    106 # endif
    107     CloseListenSockets();
    108 }
    109 
    110 static int
    111 FD_ANYSET(fd_set *fds)
    112 {
    113     int i;
    114     char *mask = (char *) fds;
    115 
    116     for (i = 0 ; i < sizeof(fds); i++) {
    117 	if (mask[i])
    118 	    return TRUE;
    119     }
    120     return FALSE;
    121 }
    122 
    123 int
    124 AnyWellKnownSockets (void)
    125 {
    126     return
    127 # ifdef IPv6
    128       chooserFd6 != -1 ||
    129 # endif
    130       chooserFd != -1 || FD_ANYSET(&WellKnownSocketsMask);
    131 }
    132 
    133 static XdmcpBuffer	buffer;
    134 
    135 /*ARGSUSED*/
    136 static void
    137 sendForward (
    138     CARD16	connectionType,
    139     ARRAY8Ptr	address,
    140     char	*closure)
    141 {
    142 # ifdef AF_INET
    143     struct sockaddr_in	    in_addr;
    144 # endif
    145 # ifdef IPv6
    146     struct sockaddr_in6	    in6_addr;
    147 # endif
    148     struct sockaddr	    *addr;
    149     int			    addrlen;
    150 
    151     switch (connectionType)
    152     {
    153 # ifdef AF_INET
    154     case FamilyInternet:
    155 	addr = (struct sockaddr *) &in_addr;
    156 	bzero ((char *) &in_addr, sizeof (in_addr));
    157 #  ifdef BSD44SOCKETS
    158 	in_addr.sin_len = sizeof(in_addr);
    159 #  endif
    160 	in_addr.sin_family = AF_INET;
    161 	in_addr.sin_port = htons ((short) XDM_UDP_PORT);
    162 	if (address->length != 4)
    163 	    return;
    164 	memcpy(&in_addr.sin_addr, address->data, address->length);
    165 	addrlen = sizeof (struct sockaddr_in);
    166 	break;
    167 # endif
    168 # ifdef IPv6
    169     case FamilyInternet6:
    170 	addr = (struct sockaddr *) &in6_addr;
    171 	bzero ((char *) &in6_addr, sizeof (in6_addr));
    172 #  ifdef SIN6_LEN
    173 	in6_addr.sin6_len = sizeof(in6_addr);
    174 #  endif
    175 	in6_addr.sin6_family = AF_INET6;
    176 	in6_addr.sin6_port = htons ((short) XDM_UDP_PORT);
    177 	if (address->length != 16)
    178 	    return;
    179 	memcpy(&in6_addr.sin6_addr, address->data, address->length);
    180 	addrlen = sizeof (struct sockaddr_in6);
    181 	break;
    182 # endif
    183     default:
    184 	return;
    185     }
    186     XdmcpFlush (*((int *) closure), &buffer, (XdmcpNetaddr) addr, addrlen);
    187     return;
    188 }
    189 
    190 static void
    191 ClientAddress (
    192     struct sockaddr *from,
    193     ARRAY8Ptr	    addr,	/* return */
    194     ARRAY8Ptr	    port,	/* return */
    195     CARD16	    *type)	/* return */
    196 {
    197     int length, family;
    198     char *data;
    199 
    200     data = NetaddrPort((XdmcpNetaddr) from, &length);
    201     XdmcpAllocARRAY8 (port, length);
    202     memcpy(port->data, data, length);
    203     port->length = length;
    204 
    205     family = ConvertAddr((XdmcpNetaddr) from, &length, &data);
    206     XdmcpAllocARRAY8 (addr, length);
    207     memcpy(addr->data, data, length);
    208     addr->length = length;
    209 
    210     *type = family;
    211 }
    212 
    213 static void
    214 all_query_respond (
    215     struct sockaddr	*from,
    216     int			fromlen,
    217     ARRAYofARRAY8Ptr	authenticationNames,
    218     xdmOpCode		type,
    219     int			fd)
    220 {
    221     ARRAY8Ptr	authenticationName;
    222     ARRAY8	status = {0, NULL};
    223     ARRAY8	addr  = {0, NULL};
    224     CARD16	connectionType;
    225     int		family;
    226     int		length;
    227     const char	*addrstring;
    228 # ifdef IPv6
    229     char	addrbuf[INET6_ADDRSTRLEN] = "";
    230 # elif defined(HAVE_INET_NTOP)
    231     char	addrbuf[INET_ADDRSTRLEN] = "";
    232 # endif
    233 
    234     family = ConvertAddr((XdmcpNetaddr) from, &length, (char **)&(addr.data));
    235     if (family < 0) {
    236 	Debug("all_query_respond: ConvertAddr failed: conntype=%d\n", family);
    237 	return;
    238     }
    239     addr.length = length;	/* convert int to short */
    240     if (debugLevel > 0) {
    241 # ifdef HAVE_INET_NTOP
    242 	void *ipaddr;
    243 	int af_type;
    244 #  ifdef IPv6
    245 	if (family == FamilyInternet6) {
    246 	    ipaddr = & ((struct sockaddr_in6 *) from)->sin6_addr;
    247 	    af_type = AF_INET6;
    248 	} else
    249 #  endif
    250 	{
    251 	    ipaddr = & ((struct sockaddr_in *) from)->sin_addr;
    252 	    af_type = AF_INET;
    253 	}
    254 	addrstring = inet_ntop(af_type, ipaddr, addrbuf, sizeof(addrbuf));
    255 # else
    256 	addrstring = inet_ntoa(((struct sockaddr_in *)from)->sin_addr);
    257 # endif
    258 	Debug("all_query_respond: conntype=%d, addr=%s, len=%d\n",
    259 	    family, addrstring, addr.length);
    260     }
    261     connectionType = family;
    262 
    263     if (type == INDIRECT_QUERY)
    264 	RememberIndirectClient (&addr, connectionType);
    265     else
    266 	ForgetIndirectClient (&addr, connectionType);
    267 
    268     authenticationName = ChooseAuthentication (authenticationNames);
    269     if (Willing (&addr, connectionType, authenticationName, &status, type))
    270 	send_willing (from, fromlen, authenticationName, &status, fd);
    271     else
    272 	if (type == QUERY)
    273 	    send_unwilling (from, fromlen, authenticationName, &status, fd);
    274     XdmcpDisposeARRAY8 (&status);
    275 }
    276 
    277 static void
    278 indirect_respond (
    279     struct sockaddr *from,
    280     int		    fromlen,
    281     int		    length,
    282     int		    fd)
    283 {
    284     ARRAYofARRAY8   queryAuthenticationNames = {0, NULL};
    285     ARRAY8	    clientAddress = {0, NULL};
    286     ARRAY8	    clientPort = {0, NULL};
    287     CARD16	    connectionType;
    288     int		    expectedLen;
    289     int		    i;
    290     XdmcpHeader	    header;
    291     int		    localHostAsWell;
    292 
    293     Debug ("Indirect respond %d\n", length);
    294     if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames))
    295 	return;
    296     expectedLen = 1;
    297     for (i = 0; i < (int)queryAuthenticationNames.length; i++)
    298 	expectedLen += 2 + queryAuthenticationNames.data[i].length;
    299     if (length == expectedLen)
    300     {
    301 	ClientAddress (from, &clientAddress, &clientPort, &connectionType);
    302 	/*
    303 	 * set up the forward query packet
    304 	 */
    305 	header.version = XDM_PROTOCOL_VERSION;
    306 	header.opcode = (CARD16) FORWARD_QUERY;
    307 	header.length = 0;
    308 	header.length += 2 + clientAddress.length;
    309 	header.length += 2 + clientPort.length;
    310 	header.length += 1;
    311 	for (i = 0; i < (int)queryAuthenticationNames.length; i++)
    312 	    header.length += 2 + queryAuthenticationNames.data[i].length;
    313 	XdmcpWriteHeader (&buffer, &header);
    314 	XdmcpWriteARRAY8 (&buffer, &clientAddress);
    315 	XdmcpWriteARRAY8 (&buffer, &clientPort);
    316 	XdmcpWriteARRAYofARRAY8 (&buffer, &queryAuthenticationNames);
    317 
    318 	localHostAsWell = ForEachMatchingIndirectHost (&clientAddress, connectionType, sendForward, (char *) &fd);
    319 
    320 	XdmcpDisposeARRAY8 (&clientAddress);
    321 	XdmcpDisposeARRAY8 (&clientPort);
    322 	if (localHostAsWell)
    323 	    all_query_respond (from, fromlen, &queryAuthenticationNames,
    324 			   INDIRECT_QUERY, fd);
    325     }
    326     else
    327     {
    328 	Debug ("Indirect length error got %d expect %d\n", length, expectedLen);
    329     }
    330     XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames);
    331 }
    332 
    333 void
    334 ProcessRequestSocket (int fd)
    335 {
    336     XdmcpHeader		header;
    337 # ifdef HAVE_STRUCT_SOCKADDR_STORAGE
    338     struct sockaddr_storage	addr;
    339 # else
    340     struct sockaddr	addr;
    341 # endif
    342     int			addrlen = sizeof addr;
    343 
    344     Debug ("ProcessRequestSocket\n");
    345     bzero ((char *) &addr, sizeof (addr));
    346     if (!XdmcpFill (fd, &buffer, (XdmcpNetaddr) &addr, &addrlen)) {
    347 	Debug ("XdmcpFill failed\n");
    348 	return;
    349     }
    350     if (!XdmcpReadHeader (&buffer, &header)) {
    351 	Debug ("XdmcpReadHeader failed\n");
    352 	return;
    353     }
    354     if (header.version != XDM_PROTOCOL_VERSION) {
    355 	Debug ("XDMCP header version read was %d, expected %d\n",
    356 	       header.version, XDM_PROTOCOL_VERSION);
    357 	return;
    358     }
    359     Debug ("header: %d %d %d\n", header.version, header.opcode, header.length);
    360     switch (header.opcode)
    361     {
    362     case BROADCAST_QUERY:
    363 	broadcast_respond ((struct sockaddr *) &addr, addrlen, header.length, fd);
    364 	break;
    365     case QUERY:
    366 	query_respond ((struct sockaddr *) &addr, addrlen, header.length, fd);
    367 	break;
    368     case INDIRECT_QUERY:
    369 	indirect_respond ((struct sockaddr *) &addr, addrlen, header.length, fd);
    370 	break;
    371     case FORWARD_QUERY:
    372 	forward_respond ((struct sockaddr *) &addr, addrlen, header.length, fd);
    373 	break;
    374     case REQUEST:
    375 	request_respond ((struct sockaddr *) &addr, addrlen, header.length, fd);
    376 	break;
    377     case MANAGE:
    378 	manage ((struct sockaddr *) &addr, addrlen, header.length, fd);
    379 	break;
    380     case KEEPALIVE:
    381 	send_alive ((struct sockaddr *) &addr, addrlen, header.length, fd);
    382 	break;
    383     }
    384 }
    385 
    386 void
    387 WaitForSomething (void)
    388 {
    389     FD_TYPE	reads;
    390     int	nready;
    391 
    392     Debug ("WaitForSomething\n");
    393     if (AnyWellKnownSockets () && !ChildReady) {
    394 	reads = WellKnownSocketsMask;
    395 	nready = select (WellKnownSocketsMax + 1, &reads, NULL, NULL, NULL);
    396 	Debug ("select returns %d.  Rescan: %d  ChildReady: %d\n",
    397 		nready, Rescan, ChildReady);
    398 	if (nready > 0)
    399 	{
    400 	    if (chooserFd >= 0 && FD_ISSET (chooserFd, &reads))
    401 	    {
    402 		ProcessChooserSocket (chooserFd);
    403 		FD_CLR(chooserFd, &reads);
    404 	    }
    405 # ifdef IPv6
    406 	    if (chooserFd6 >= 0 && FD_ISSET (chooserFd6, &reads))
    407 	    {
    408 		ProcessChooserSocket (chooserFd6);
    409 		FD_CLR(chooserFd6, &reads);
    410 	    }
    411 # endif
    412 	    ProcessListenSockets(&reads);
    413 	}
    414 	if (ChildReady)
    415 	{
    416 	    WaitForChild ();
    417 	}
    418     } else
    419 	WaitForChild ();
    420 }
    421 
    422 /*
    423  * respond to a request on the UDP socket.
    424  */
    425 
    426 static ARRAY8	Hostname;
    427 
    428 void
    429 registerHostname (
    430     char    *name,
    431     int	    namelen)
    432 {
    433     int	i;
    434 
    435     if (!XdmcpReallocARRAY8 (&Hostname, namelen))
    436 	return;
    437     for (i = 0; i < namelen; i++)
    438 	Hostname.data[i] = name[i];
    439 }
    440 
    441 static void
    442 direct_query_respond (
    443     struct sockaddr *from,
    444     int		    fromlen,
    445     int		    length,
    446     xdmOpCode	    type,
    447     int		    fd)
    448 {
    449     ARRAYofARRAY8   queryAuthenticationNames = {0, NULL};
    450     int		    expectedLen;
    451     int		    i;
    452 
    453     if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames))
    454 	return;
    455     expectedLen = 1;
    456     for (i = 0; i < (int)queryAuthenticationNames.length; i++)
    457 	expectedLen += 2 + queryAuthenticationNames.data[i].length;
    458     if (length == expectedLen)
    459 	all_query_respond (from, fromlen, &queryAuthenticationNames, type, fd);
    460     XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames);
    461 }
    462 
    463 static void
    464 query_respond (
    465     struct sockaddr *from,
    466     int		    fromlen,
    467     int		    length,
    468     int		    fd)
    469 {
    470     Debug ("Query respond %d\n", length);
    471     direct_query_respond (from, fromlen, length, QUERY, fd);
    472 }
    473 
    474 static void
    475 broadcast_respond (
    476     struct sockaddr *from,
    477     int		    fromlen,
    478     int		    length,
    479     int		    fd)
    480 {
    481     direct_query_respond (from, fromlen, length, BROADCAST_QUERY, fd);
    482 }
    483 
    484 /* computes an X display name */
    485 
    486 static char *
    487 NetworkAddressToName(
    488     CARD16	connectionType,
    489     ARRAY8Ptr   connectionAddress,
    490     struct sockaddr   *originalAddress,
    491     CARD16	displayNumber)
    492 {
    493     switch (connectionType)
    494     {
    495     case FamilyInternet:
    496 # if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_NTOP)
    497 #  ifdef IPv6
    498     case FamilyInternet6:
    499 #  endif
    500 	{
    501 	    CARD8		*data;
    502 	    struct hostent	*hostent;
    503 	    char 		*hostname = NULL;
    504 	    char		*name;
    505 	    char		*localhost;
    506 	    int			 multiHomed = 0;
    507 	    struct addrinfo	 hints, *ai = NULL, *nai;
    508 	    int 		 type;
    509 
    510 #  ifdef IPv6
    511 	    if (connectionType == FamilyInternet6)
    512 		type = AF_INET6;
    513 	    else
    514 #  endif
    515 		type = AF_INET;
    516 
    517 	    data = connectionAddress->data;
    518 	    hostent = gethostbyaddr ((char *)data,
    519 				     connectionAddress->length, type);
    520 	    if (hostent) {
    521 		if (sourceAddress) {
    522 		    bzero(&hints, sizeof(hints));
    523 		    hints.ai_flags = AI_CANONNAME;
    524 #  ifdef IPv6
    525 		    hints.ai_family = AF_UNSPEC;
    526 #  else
    527 		    hints.ai_family = AF_INET;
    528 #  endif
    529 		    if (getaddrinfo(hostent->h_name, NULL, &hints, &ai) == 0) {
    530 			hostname = ai->ai_canonname;
    531 			for (nai = ai->ai_next; nai!=NULL; nai=nai->ai_next) {
    532 			    if ((ai->ai_protocol == nai->ai_protocol) &&
    533 				(ai->ai_addrlen == nai->ai_addrlen) &&
    534 			        (memcmp(ai->ai_addr,nai->ai_addr,
    535 					ai->ai_addrlen) != 0) ) {
    536 				multiHomed = 1;
    537 			    }
    538 			}
    539 		    }
    540 		} else {
    541 		    hostname = hostent->h_name;
    542 		}
    543 	    }
    544 
    545 	    localhost = localHostname ();
    546 
    547 	    /*
    548 	     * protect against bogus host names
    549 	     */
    550 	    if (hostname && hostname[0] && (hostname[0] != '.')
    551 			&& !multiHomed)
    552 	    {
    553 		if (!strcmp (localhost, hostname))
    554 		{
    555 		    if (asprintf(&name, ":%d", displayNumber) < 0) {
    556 			if (ai)
    557 			    freeaddrinfo(ai);
    558 			return NULL;
    559 		    }
    560 		}
    561 		else
    562 		{
    563 		    if (removeDomainname)
    564 		    {
    565 			char    *localDot, *remoteDot;
    566 
    567 			/* check for a common domain name.  This
    568 			 * could reduce names by recognising common
    569 			 * super-domain names as well, but I don't think
    570 			 * this is as useful, and will confuse more
    571 			 * people
    572 			 */
    573 			if ((localDot = strchr(localhost, '.')) &&
    574 		            (remoteDot = strchr(hostname, '.')))
    575 			{
    576 			    /* smash the name in place; it won't
    577 			     * be needed later.
    578 			     */
    579 			    if (!strcmp (localDot+1, remoteDot+1))
    580 				*remoteDot = '\0';
    581 			}
    582 		    }
    583 
    584 		    if (asprintf (&name, "%s:%d",
    585 				  hostname, displayNumber) < 0) {
    586 			if (ai)
    587 			    freeaddrinfo(ai);
    588 			return NULL;
    589 		    }
    590 		}
    591 	    }
    592 	    else
    593 	    {
    594 		if (!getString (name, INET6_ADDRSTRLEN + 10)) {
    595 		    if (ai)
    596 			freeaddrinfo(ai);
    597 		    return NULL;
    598 		}
    599 		if (multiHomed) {
    600 		    if (connectionType == FamilyInternet) {
    601 			data = (CARD8 *)
    602 			  &((struct sockaddr_in *)originalAddress)->
    603 			  sin_addr;
    604 #  ifdef IPv6
    605 		    } else {
    606 			data = (CARD8 *)
    607 			  &((struct sockaddr_in6 *)originalAddress)->sin6_addr;
    608 #  endif
    609 		    }
    610 		}
    611 		if (inet_ntop(type, data, name, INET6_ADDRSTRLEN) == NULL) {
    612 		    free(name);
    613 		    if (ai)
    614 			freeaddrinfo(ai);
    615 		    return NULL;
    616 		}
    617 		snprintf(name + strlen(name), 10, ":%d", displayNumber);
    618 	    }
    619 	    if (ai)
    620 		freeaddrinfo(ai);
    621 	    return name;
    622 	}
    623 # else /* !HAVE_GETADDRINFO */
    624 	{
    625 	    CARD8		*data;
    626 	    struct hostent	*hostent;
    627 	    char		*name;
    628 	    char		*localhost;
    629 	    int			 multiHomed = 0;
    630 
    631 	    data = connectionAddress->data;
    632 	    hostent = gethostbyaddr ((char *)data,
    633 				     connectionAddress->length, AF_INET);
    634 	    if (sourceAddress && hostent) {
    635 		hostent = gethostbyname(hostent->h_name);
    636 		if (hostent)
    637 			multiHomed = hostent->h_addr_list[1] != NULL;
    638 	    }
    639 
    640 	    localhost = localHostname ();
    641 
    642 	    /*
    643 	     * protect against bogus host names
    644 	     */
    645 	    if (hostent && hostent->h_name && hostent->h_name[0]
    646 			&& (hostent->h_name[0] != '.')
    647 			&& !multiHomed)
    648 	    {
    649 		if (!strcmp (localhost, hostent->h_name))
    650 		{
    651 		    if (asprintf(&name, ":%d", displayNumber) < 0) {
    652 			return NULL;
    653 		    }
    654 		}
    655 		else
    656 		{
    657 		    if (removeDomainname)
    658 		    {
    659 			char    *localDot, *remoteDot;
    660 
    661 			/* check for a common domain name.  This
    662 			 * could reduce names by recognising common
    663 			 * super-domain names as well, but I don't think
    664 			 * this is as useful, and will confuse more
    665 			 * people
    666 			 */
    667 			if ((localDot = strchr(localhost, '.')) &&
    668 		            (remoteDot = strchr(hostent->h_name, '.')))
    669 			{
    670 			    /* smash the name in place; it won't
    671 			     * be needed later.
    672 			     */
    673 			    if (!strcmp (localDot+1, remoteDot+1))
    674 				*remoteDot = '\0';
    675 			}
    676 		    }
    677 
    678 		    if (asprintf(&name, "%s:%d",
    679 				 hostent->h_name, displayNumber) < 0) {
    680 			return NULL;
    681 		    }
    682 		}
    683 	    }
    684 	    else
    685 	    {
    686 		if (multiHomed)
    687 		    data = (CARD8 *) &((struct sockaddr_in *)originalAddress)->
    688 				sin_addr.s_addr;
    689 
    690 		if (asprintf(&name, "%d.%d.%d.%d:%d",
    691 			     data[0], data[1], data[2], data[3],
    692 			     displayNumber) < 0) {
    693 		    return NULL;
    694 		}
    695 	    }
    696 	    return name;
    697 	}
    698 # endif /* HAVE_GETADDRINFO */
    699     default:
    700 	return NULL;
    701     }
    702 }
    703 
    704 /*ARGSUSED*/
    705 static void
    706 forward_respond (
    707     struct sockaddr	*from,
    708     int			fromlen,
    709     int			length,
    710     int			fd)
    711 {
    712     ARRAY8	    clientAddress = {0, NULL};
    713     ARRAY8	    clientPort = {0, NULL};
    714     ARRAYofARRAY8   authenticationNames = {0, NULL};
    715     struct sockaddr *client;
    716     int		    clientlen;
    717     int		    expectedLen;
    718     int		    i;
    719 
    720     Debug ("Forward respond %d\n", length);
    721     if (XdmcpReadARRAY8 (&buffer, &clientAddress) &&
    722 	XdmcpReadARRAY8 (&buffer, &clientPort) &&
    723 	XdmcpReadARRAYofARRAY8 (&buffer, &authenticationNames))
    724     {
    725 	expectedLen = 0;
    726 	expectedLen += 2 + clientAddress.length;
    727 	expectedLen += 2 + clientPort.length;
    728 	expectedLen += 1;	    /* authenticationNames */
    729 	for (i = 0; i < (int)authenticationNames.length; i++)
    730 	    expectedLen += 2 + authenticationNames.data[i].length;
    731 	if (length == expectedLen)
    732 	{
    733 	    int	j;
    734 
    735 	    j = 0;
    736 	    for (i = 0; i < (int)clientPort.length; i++)
    737 		j = j * 256 + clientPort.data[i];
    738 	    Debug ("Forward client address (port %d)", j);
    739 	    for (i = 0; i < (int)clientAddress.length; i++)
    740 		Debug (" %d", clientAddress.data[i]);
    741 	    Debug ("\n");
    742 	    switch (from->sa_family)
    743 	    {
    744 # ifdef AF_INET
    745 	    case AF_INET:
    746 		{
    747 		    struct sockaddr_in	in_addr;
    748 
    749 		    if (clientAddress.length != 4 ||
    750 		        clientPort.length != 2)
    751 		    {
    752 			goto badAddress;
    753 		    }
    754 		    bzero ((char *) &in_addr, sizeof (in_addr));
    755 #  ifdef BSD44SOCKETS
    756 		    in_addr.sin_len = sizeof(in_addr);
    757 #  endif
    758 		    in_addr.sin_family = AF_INET;
    759 		    memcpy(&in_addr.sin_addr, clientAddress.data, 4);
    760 		    memcpy(&in_addr.sin_port, clientPort.data, 2);
    761 		    client = (struct sockaddr *) &in_addr;
    762 		    clientlen = sizeof (in_addr);
    763 		    all_query_respond (client, clientlen, &authenticationNames,
    764 			       FORWARD_QUERY, fd);
    765 		}
    766 		break;
    767 # endif
    768 # ifdef IPv6
    769 	    case AF_INET6:
    770 		{
    771 		    struct sockaddr_in6	in6_addr;
    772 
    773 		    if ((clientAddress.length != 16 && clientAddress.length != 4) ||
    774 		        (clientPort.length != 2))
    775 		    {
    776 			goto badAddress;
    777 		    }
    778 		    bzero ((char *) &in6_addr, sizeof (in6_addr));
    779 #  ifdef SIN6_LEN
    780 		    in6_addr.sin6_len = sizeof(in6_addr);
    781 #  endif
    782 		    in6_addr.sin6_family = AF_INET6;
    783 		    if (clientAddress.length == 16) {
    784 			memcpy(in6_addr.sin6_addr.s6_addr, clientAddress.data, 16);
    785 		    } else {
    786 			/* If the client wants to forward the xdm server to an
    787 			   ipv4 hosts it sends an ipv4 address in the forward
    788 			   packet. On dual-stack hosts the packet arrives as a
    789 			   ipv6 packet. To respond to the ipv4 host one has
    790 			   to create an ipv4-mapped address of the form
    791 
    792 			   ::ffff::xxx.xxx.xxx.xxx
    793 
    794 			   One example where this is necessary is an ipv4-only
    795 			   thin client that connects to a dual-stacked xdm.
    796 			*/
    797 			in6_addr.sin6_addr.s6_addr[10] = 0xff;
    798 			in6_addr.sin6_addr.s6_addr[11] = 0xff;
    799 			memcpy(in6_addr.sin6_addr.s6_addr + 12,
    800                                clientAddress.data, 4);
    801 		    }
    802 		    memcpy(&in6_addr.sin6_port, clientPort.data, 2);
    803 		    client = (struct sockaddr *) &in6_addr;
    804 		    clientlen = sizeof (in6_addr);
    805 		    all_query_respond (client, clientlen, &authenticationNames,
    806 			       FORWARD_QUERY, fd);
    807 		}
    808 		break;
    809 # endif
    810 # ifdef AF_UNIX
    811 	    case AF_UNIX:
    812 		{
    813 		    struct sockaddr_un	un_addr;
    814 
    815 		    if (clientAddress.length >= sizeof (un_addr.sun_path))
    816 			goto badAddress;
    817 		    bzero ((char *) &un_addr, sizeof (un_addr));
    818 		    un_addr.sun_family = AF_UNIX;
    819 		    memcpy(un_addr.sun_path, clientAddress.data,
    820                            clientAddress.length);
    821 		    un_addr.sun_path[clientAddress.length] = '\0';
    822 		    client = (struct sockaddr *) &un_addr;
    823 #  if defined(BSD44SOCKETS) && defined(UNIXCONN)
    824 		    un_addr.sun_len = strlen(un_addr.sun_path);
    825 		    clientlen = SUN_LEN(&un_addr);
    826 #  else
    827 		    clientlen = sizeof (un_addr);
    828 #  endif
    829 		    all_query_respond (client, clientlen, &authenticationNames,
    830 			       FORWARD_QUERY, fd);
    831 		}
    832 		break;
    833 # endif
    834 	    }
    835 	}
    836 	else
    837 	{
    838 	    Debug ("Forward length error got %d expect %d\n", length, expectedLen);
    839 	}
    840     }
    841 badAddress:
    842     XdmcpDisposeARRAY8 (&clientAddress);
    843     XdmcpDisposeARRAY8 (&clientPort);
    844     XdmcpDisposeARRAYofARRAY8 (&authenticationNames);
    845 }
    846 
    847 static void
    848 send_willing (
    849     struct sockaddr *from,
    850     int		    fromlen,
    851     ARRAY8Ptr	    authenticationName,
    852     ARRAY8Ptr	    status,
    853     int		    fd)
    854 {
    855     XdmcpHeader	header;
    856 
    857     Debug ("Send willing %*.*s %*.*s\n", authenticationName->length,
    858 					 authenticationName->length,
    859 					 pS(authenticationName->data),
    860 					 status->length,
    861 					 status->length,
    862 					 pS(status->data));
    863     header.version = XDM_PROTOCOL_VERSION;
    864     header.opcode = (CARD16) WILLING;
    865     header.length = 6 + authenticationName->length +
    866 		    Hostname.length + status->length;
    867     XdmcpWriteHeader (&buffer, &header);
    868     XdmcpWriteARRAY8 (&buffer, authenticationName);
    869     XdmcpWriteARRAY8 (&buffer, &Hostname);
    870     XdmcpWriteARRAY8 (&buffer, status);
    871     XdmcpFlush (fd, &buffer, (XdmcpNetaddr) from, fromlen);
    872 }
    873 
    874 static void
    875 send_unwilling (
    876     struct sockaddr *from,
    877     int		    fromlen,
    878     ARRAY8Ptr	    authenticationName,
    879     ARRAY8Ptr	    status,
    880     int		    fd)
    881 {
    882     XdmcpHeader	header;
    883 
    884     Debug ("Send unwilling %*.*s %*.*s\n", authenticationName->length,
    885 					 authenticationName->length,
    886 					 pS(authenticationName->data),
    887 					 status->length,
    888 					 status->length,
    889 					 pS(status->data));
    890     header.version = XDM_PROTOCOL_VERSION;
    891     header.opcode = (CARD16) UNWILLING;
    892     header.length = 4 + Hostname.length + status->length;
    893     XdmcpWriteHeader (&buffer, &header);
    894     XdmcpWriteARRAY8 (&buffer, &Hostname);
    895     XdmcpWriteARRAY8 (&buffer, status);
    896     XdmcpFlush (fd, &buffer, (XdmcpNetaddr) from, fromlen);
    897 }
    898 
    899 static unsigned long	globalSessionID;
    900 
    901 # define NextSessionID()    (++globalSessionID)
    902 
    903 void init_session_id(void)
    904 {
    905     /* Set randomly so we are unlikely to reuse id's from a previous
    906      * incarnation so we don't say "Alive" to those displays.
    907      * Start with low digits 0 to make debugging easier.
    908      */
    909     globalSessionID = (time((Time_t *)0)&0x7fff) * 16000;
    910 }
    911 
    912 static ARRAY8 outOfMemory = { (CARD16) 13, (CARD8Ptr) "Out of memory" };
    913 static ARRAY8 noValidAddr = { (CARD16) 16, (CARD8Ptr) "No valid address" };
    914 static ARRAY8 noValidAuth = { (CARD16) 22, (CARD8Ptr) "No valid authorization" };
    915 static ARRAY8 noAuthentic = { (CARD16) 29, (CARD8Ptr) "XDM has no authentication key" };
    916 
    917 static void
    918 request_respond (
    919     struct sockaddr *from,
    920     int		    fromlen,
    921     int		    length,
    922     int		    fd)
    923 {
    924     CARD16	    displayNumber;
    925     ARRAY16	    connectionTypes = {0, NULL};
    926     ARRAYofARRAY8   connectionAddresses = {0, NULL};
    927     ARRAY8	    authenticationName = {0, NULL};
    928     ARRAY8	    authenticationData = {0, NULL};
    929     ARRAYofARRAY8   authorizationNames = {0, NULL};
    930     ARRAY8	    manufacturerDisplayID = {0, NULL};
    931     ARRAY8Ptr	    reason = NULL;
    932     int		    expectlen;
    933     int		    i, j;
    934     struct protoDisplay  *pdpy = NULL;
    935     ARRAY8	    authorizationName = {0, NULL},
    936 		    authorizationData = {0, NULL};
    937     ARRAY8Ptr	    connectionAddress;
    938 
    939     Debug ("Request respond %d\n", length);
    940     if (XdmcpReadCARD16 (&buffer, &displayNumber) &&
    941 	XdmcpReadARRAY16 (&buffer, &connectionTypes) &&
    942 	XdmcpReadARRAYofARRAY8 (&buffer, &connectionAddresses) &&
    943 	XdmcpReadARRAY8 (&buffer, &authenticationName) &&
    944 	XdmcpReadARRAY8 (&buffer, &authenticationData) &&
    945 	XdmcpReadARRAYofARRAY8 (&buffer, &authorizationNames) &&
    946 	XdmcpReadARRAY8 (&buffer, &manufacturerDisplayID))
    947     {
    948 	expectlen = 0;
    949 	expectlen += 2;				    /* displayNumber */
    950 	expectlen += 1 + 2*connectionTypes.length;  /* connectionTypes */
    951 	expectlen += 1;				    /* connectionAddresses */
    952 	for (i = 0; i < (int)connectionAddresses.length; i++)
    953 	    expectlen += 2 + connectionAddresses.data[i].length;
    954 	expectlen += 2 + authenticationName.length; /* authenticationName */
    955 	expectlen += 2 + authenticationData.length; /* authenticationData */
    956 	expectlen += 1;				    /* authoriationNames */
    957 	for (i = 0; i < (int)authorizationNames.length; i++)
    958 	    expectlen += 2 + authorizationNames.data[i].length;
    959 	expectlen += 2 + manufacturerDisplayID.length;	/* displayID */
    960 	if (expectlen != length)
    961 	{
    962 	    Debug ("Request length error got %d expect %d\n", length, expectlen);
    963 	    goto abort;
    964 	}
    965 	if (connectionTypes.length == 0 ||
    966 	    connectionAddresses.length != connectionTypes.length)
    967 	{
    968 	    reason = &noValidAddr;
    969 	    goto decline;
    970 	}
    971 	pdpy = FindProtoDisplay ((XdmcpNetaddr) from, fromlen, displayNumber);
    972 	if (!pdpy) {
    973 
    974 	    /* Check this Display against the Manager's policy */
    975 	    reason = Accept (from, fromlen, displayNumber);
    976 	    if (reason)
    977 		goto decline;
    978 
    979 	    /* Check the Display's stream services against Manager's policy */
    980 	    i = SelectConnectionTypeIndex (&connectionTypes,
    981 					   &connectionAddresses);
    982 	    if (i < 0) {
    983 		reason = &noValidAddr;
    984 		goto decline;
    985 	    }
    986 
    987 	    /* The Manager considers this a new session */
    988 	    connectionAddress = &connectionAddresses.data[i];
    989 	    pdpy = NewProtoDisplay ((XdmcpNetaddr) from, fromlen, displayNumber,
    990 				    connectionTypes.data[i], connectionAddress,
    991 				    NextSessionID());
    992 	    Debug ("NewProtoDisplay %p\n", pdpy);
    993 	    if (!pdpy) {
    994 		reason = &outOfMemory;
    995 		goto decline;
    996 	    }
    997 	}
    998 	if (authorizationNames.length == 0)
    999 	    j = 0;
   1000 	else
   1001 	    j = SelectAuthorizationTypeIndex (&authenticationName,
   1002 					      &authorizationNames);
   1003 	if (j < 0)
   1004 	{
   1005 	    reason = &noValidAuth;
   1006 	    goto decline;
   1007 	}
   1008 	if (!CheckAuthentication (pdpy,
   1009 				  &manufacturerDisplayID,
   1010 				  &authenticationName,
   1011 				  &authenticationData))
   1012 	{
   1013 	    reason = &noAuthentic;
   1014 	    goto decline;
   1015 	}
   1016 	if (j < (int)authorizationNames.length)
   1017 	{
   1018 	    Xauth   *auth;
   1019 	    SetProtoDisplayAuthorization (pdpy,
   1020 		(unsigned short) authorizationNames.data[j].length,
   1021 		(char *) authorizationNames.data[j].data);
   1022 	    auth = pdpy->xdmcpAuthorization;
   1023 	    if (!auth)
   1024 		auth = pdpy->fileAuthorization;
   1025 	    if (auth)
   1026 	    {
   1027 		authorizationName.length = auth->name_length;
   1028 		authorizationName.data = (CARD8Ptr) auth->name;
   1029 		authorizationData.length = auth->data_length;
   1030 		authorizationData.data = (CARD8Ptr) auth->data;
   1031 	    }
   1032 	}
   1033 	if (pdpy)
   1034 	{
   1035 	    send_accept (from, fromlen, pdpy->sessionID,
   1036 				        &authenticationName,
   1037 					&authenticationData,
   1038 					&authorizationName,
   1039 					&authorizationData, fd);
   1040 	}
   1041 	else
   1042 	{
   1043 decline:    ;
   1044 	    send_decline (from, fromlen, &authenticationName,
   1045 				 &authenticationData,
   1046 				 reason, fd);
   1047             if (pdpy)
   1048 		DisposeProtoDisplay (pdpy);
   1049 	}
   1050     }
   1051 abort:
   1052     XdmcpDisposeARRAY16 (&connectionTypes);
   1053     XdmcpDisposeARRAYofARRAY8 (&connectionAddresses);
   1054     XdmcpDisposeARRAY8 (&authenticationName);
   1055     XdmcpDisposeARRAY8 (&authenticationData);
   1056     XdmcpDisposeARRAYofARRAY8 (&authorizationNames);
   1057     XdmcpDisposeARRAY8 (&manufacturerDisplayID);
   1058 }
   1059 
   1060 static void
   1061 send_accept (
   1062     struct sockaddr *to,
   1063     int		    tolen,
   1064     CARD32	    sessionID,
   1065     ARRAY8Ptr	    authenticationName,
   1066     ARRAY8Ptr	    authenticationData,
   1067     ARRAY8Ptr	    authorizationName,
   1068     ARRAY8Ptr	    authorizationData,
   1069     int		    fd)
   1070 {
   1071     XdmcpHeader	header;
   1072 
   1073     Debug ("Accept Session ID %ld\n", (long) sessionID);
   1074     header.version = XDM_PROTOCOL_VERSION;
   1075     header.opcode = (CARD16) ACCEPT;
   1076     header.length = 4;			    /* session ID */
   1077     header.length += 2 + authenticationName->length;
   1078     header.length += 2 + authenticationData->length;
   1079     header.length += 2 + authorizationName->length;
   1080     header.length += 2 + authorizationData->length;
   1081     XdmcpWriteHeader (&buffer, &header);
   1082     XdmcpWriteCARD32 (&buffer, sessionID);
   1083     XdmcpWriteARRAY8 (&buffer, authenticationName);
   1084     XdmcpWriteARRAY8 (&buffer, authenticationData);
   1085     XdmcpWriteARRAY8 (&buffer, authorizationName);
   1086     XdmcpWriteARRAY8 (&buffer, authorizationData);
   1087     XdmcpFlush (fd, &buffer, (XdmcpNetaddr) to, tolen);
   1088 }
   1089 
   1090 static void
   1091 send_decline (
   1092     struct sockaddr *to,
   1093     int		    tolen,
   1094     ARRAY8Ptr	    authenticationName,
   1095     ARRAY8Ptr	    authenticationData,
   1096     ARRAY8Ptr	    status,
   1097     int	       	    fd)
   1098 {
   1099     XdmcpHeader	header;
   1100 
   1101     Debug ("Decline %*.*s\n", status->length, status->length, pS(status->data));
   1102     header.version = XDM_PROTOCOL_VERSION;
   1103     header.opcode = (CARD16) DECLINE;
   1104     header.length = 0;
   1105     header.length += 2 + status->length;
   1106     header.length += 2 + authenticationName->length;
   1107     header.length += 2 + authenticationData->length;
   1108     XdmcpWriteHeader (&buffer, &header);
   1109     XdmcpWriteARRAY8 (&buffer, status);
   1110     XdmcpWriteARRAY8 (&buffer, authenticationName);
   1111     XdmcpWriteARRAY8 (&buffer, authenticationData);
   1112     XdmcpFlush (fd, &buffer, (XdmcpNetaddr) to, tolen);
   1113 }
   1114 
   1115 static void
   1116 manage (
   1117     struct sockaddr *from,
   1118     int		    fromlen,
   1119     int		    length,
   1120     int		    fd)
   1121 {
   1122     CARD32		sessionID;
   1123     CARD16		displayNumber;
   1124     ARRAY8		displayClass = {0, NULL};
   1125     int			expectlen;
   1126     struct protoDisplay	*pdpy;
   1127     struct display	*d;
   1128     char		*name = NULL;
   1129     char		*class = NULL;
   1130     XdmcpNetaddr	from_save;
   1131     ARRAY8		clientAddress = {0, NULL},
   1132 			clientPort = {0, NULL};
   1133     CARD16		connectionType;
   1134 
   1135     Debug ("Manage %d\n", length);
   1136     if (XdmcpReadCARD32 (&buffer, &sessionID) &&
   1137 	XdmcpReadCARD16 (&buffer, &displayNumber) &&
   1138 	XdmcpReadARRAY8 (&buffer, &displayClass))
   1139     {
   1140 	expectlen = 4 +				/* session ID */
   1141 		    2 +				/* displayNumber */
   1142 		    2 + displayClass.length;	/* displayClass */
   1143 	if (expectlen != length)
   1144 	{
   1145 	    Debug ("Manage length error got %d expect %d\n", length, expectlen);
   1146 	    goto abort;
   1147 	}
   1148 	pdpy = FindProtoDisplay ((XdmcpNetaddr) from, fromlen, displayNumber);
   1149 	Debug ("Manage Session ID %ld, pdpy %p\n", (long) sessionID, pdpy);
   1150 	if (!pdpy || pdpy->sessionID != sessionID)
   1151 	{
   1152 	    /*
   1153 	     * We may have already started a session for this display
   1154 	     * but it hasn't seen the response in the form of an
   1155 	     * XOpenDisplay() yet. So check if it is in the list of active
   1156 	     * displays, and if so check that the session id's match.
   1157 	     * If all this is true, then we have a duplicate request that
   1158 	     * can be ignored.
   1159 	     */
   1160 	    if (!pdpy
   1161 		&& (d = FindDisplayByAddress((XdmcpNetaddr) from, fromlen, displayNumber))
   1162 		&& d->sessionID == sessionID) {
   1163 		     Debug("manage: got duplicate pkt, ignoring\n");
   1164 		     goto abort;
   1165 	    }
   1166 	    Debug ("Session ID %ld refused\n", (long) sessionID);
   1167 	    if (pdpy)
   1168 		Debug ("Existing Session ID %ld\n", (long) pdpy->sessionID);
   1169 	    send_refuse (from, fromlen, sessionID, fd);
   1170 	}
   1171 	else
   1172 	{
   1173 	    name = NetworkAddressToName (pdpy->connectionType,
   1174 					 &pdpy->connectionAddress,
   1175 					 from,
   1176 					 pdpy->displayNumber);
   1177 	    Debug ("Computed display name: %s for: %s\n",
   1178 		   name, (char *)pdpy->connectionAddress.data);
   1179 	    if (!name)
   1180 	    {
   1181 		send_failed (from, fromlen, "(no name)", sessionID,
   1182 		  "out of memory", fd);
   1183 		goto abort;
   1184 	    }
   1185 	    d = FindDisplayByName (name);
   1186 	    if (d)
   1187 	    {
   1188 		Debug ("Terminating active session for %s\n", d->name);
   1189 		StopDisplay (d);
   1190 	    }
   1191 	    class = malloc (displayClass.length + 1);
   1192 	    if (!class)
   1193 	    {
   1194 		send_failed (from, fromlen, name, sessionID,
   1195 		  "out of memory", fd);
   1196 		goto abort;
   1197 	    }
   1198 	    if (displayClass.length)
   1199 	    {
   1200 		memcpy(class, displayClass.data, displayClass.length);
   1201 		class[displayClass.length] = '\0';
   1202 	    }
   1203 	    else
   1204 	    {
   1205 		free (class);
   1206 		class = (char *) NULL;
   1207 	    }
   1208 	    from_save = malloc (fromlen);
   1209 	    if (!from_save)
   1210 	    {
   1211 		send_failed (from, fromlen, name, sessionID,
   1212 		  "out of memory", fd);
   1213 		goto abort;
   1214 	    }
   1215 	    memcpy(from_save, from, fromlen);
   1216 	    d = NewDisplay (name, class);
   1217 	    if (!d)
   1218 	    {
   1219 		free (from_save);
   1220 		send_failed (from, fromlen, name, sessionID,
   1221 		  "out of memory", fd);
   1222 		goto abort;
   1223 	    }
   1224 	    d->displayType.location = Foreign;
   1225 	    d->displayType.lifetime = Transient;
   1226 	    d->displayType.origin = FromXDMCP;
   1227 	    d->sessionID = pdpy->sessionID;
   1228 	    d->from = from_save;
   1229 	    d->fromlen = fromlen;
   1230 	    d->displayNumber = pdpy->displayNumber;
   1231 	    ClientAddress (from, &clientAddress, &clientPort, &connectionType);
   1232 	    d->useChooser = 0;
   1233 	    d->xdmcpFd = fd;
   1234 	    if (IsIndirectClient (&clientAddress, connectionType))
   1235 	    {
   1236 		Debug ("IsIndirectClient\n");
   1237 		ForgetIndirectClient (&clientAddress, connectionType);
   1238 		if (UseChooser (&clientAddress, connectionType))
   1239 		{
   1240 		    d->useChooser = 1;
   1241 		    Debug ("Use chooser for %s\n", d->name);
   1242 		}
   1243 	    }
   1244 	    d->clientAddr = clientAddress;
   1245 	    d->connectionType = connectionType;
   1246 	    XdmcpDisposeARRAY8 (&clientPort);
   1247 	    if (pdpy->fileAuthorization)
   1248 	    {
   1249 		d->authorizations = malloc (sizeof (Xauth *));
   1250 		if (!d->authorizations)
   1251 		{
   1252 		    free (from_save);
   1253 		    free (d);
   1254 		    send_failed (from, fromlen, name, sessionID,
   1255 		      "out of memory", fd);
   1256 		    goto abort;
   1257 		}
   1258 		d->authorizations[0] = pdpy->fileAuthorization;
   1259 		d->authNum = 1;
   1260 		pdpy->fileAuthorization = NULL;
   1261 	    }
   1262 	    DisposeProtoDisplay (pdpy);
   1263 	    Debug ("Starting display %s,%s\n", d->name, d->class);
   1264 	    StartDisplay (d);
   1265 	}
   1266     }
   1267 abort:
   1268     XdmcpDisposeARRAY8 (&displayClass);
   1269     free (name);
   1270     free (class);
   1271 }
   1272 
   1273 void
   1274 SendFailed (
   1275     struct display  *d,
   1276     const char	    *reason)
   1277 {
   1278     Debug ("Display start failed, sending Failed\n");
   1279     send_failed ((struct sockaddr *)(d->from), d->fromlen, d->name,
   1280       d->sessionID, reason, d->xdmcpFd);
   1281 }
   1282 
   1283 static void
   1284 send_failed (
   1285     struct sockaddr *from,
   1286     int		    fromlen,
   1287     const char	    *name,
   1288     CARD32	    sessionID,
   1289     const char	    *reason,
   1290     int		    fd)
   1291 {
   1292     static char	buf[256];
   1293     XdmcpHeader	header;
   1294     ARRAY8	status;
   1295 
   1296     snprintf (buf, sizeof(buf), "Session %ld failed for display %.100s: %s",
   1297 	      (long) sessionID, name, reason);
   1298     Debug ("Send failed %ld %s\n", (long) sessionID, buf);
   1299     status.length = strlen (buf);
   1300     status.data = (CARD8Ptr) buf;
   1301     header.version = XDM_PROTOCOL_VERSION;
   1302     header.opcode = (CARD16) FAILED;
   1303     header.length = 6 + status.length;
   1304     XdmcpWriteHeader (&buffer, &header);
   1305     XdmcpWriteCARD32 (&buffer, sessionID);
   1306     XdmcpWriteARRAY8 (&buffer, &status);
   1307     XdmcpFlush (fd, &buffer, (XdmcpNetaddr) from, fromlen);
   1308 }
   1309 
   1310 static void
   1311 send_refuse (
   1312     struct sockaddr *from,
   1313     int		    fromlen,
   1314     CARD32	    sessionID,
   1315     int		    fd)
   1316 {
   1317     XdmcpHeader	header;
   1318 
   1319     Debug ("Send refuse %ld\n", (long) sessionID);
   1320     header.version = XDM_PROTOCOL_VERSION;
   1321     header.opcode = (CARD16) REFUSE;
   1322     header.length = 4;
   1323     XdmcpWriteHeader (&buffer, &header);
   1324     XdmcpWriteCARD32 (&buffer, sessionID);
   1325     XdmcpFlush (fd, &buffer, (XdmcpNetaddr) from, fromlen);
   1326 }
   1327 
   1328 static void
   1329 send_alive (
   1330     struct sockaddr *from,
   1331     int		    fromlen,
   1332     int		    length,
   1333     int		    fd)
   1334 {
   1335     CARD32		sessionID;
   1336     CARD16		displayNumber;
   1337     struct display	*d;
   1338     XdmcpHeader		header;
   1339     CARD8		sendRunning;
   1340     CARD32		sendSessionID;
   1341 
   1342     Debug ("Send alive\n");
   1343     if (XdmcpReadCARD16 (&buffer, &displayNumber) &&
   1344 	XdmcpReadCARD32 (&buffer, &sessionID))
   1345     {
   1346 	if (length == 6)
   1347 	{
   1348 	    d = FindDisplayBySessionID (sessionID);
   1349 	    if (!d) {
   1350 		d = FindDisplayByAddress ((XdmcpNetaddr) from, fromlen, displayNumber);
   1351 	    }
   1352 	    sendRunning = 0;
   1353 	    sendSessionID = 0;
   1354 	    if (d && d->status == running)
   1355 	    {
   1356 		if (d->sessionID == sessionID)
   1357 		    sendRunning = 1;
   1358 		sendSessionID = d->sessionID;
   1359 	    }
   1360 	    header.version = XDM_PROTOCOL_VERSION;
   1361 	    header.opcode = (CARD16) ALIVE;
   1362 	    header.length = 5;
   1363 	    Debug ("alive: %d %ld\n", sendRunning, (long) sendSessionID);
   1364 	    XdmcpWriteHeader (&buffer, &header);
   1365 	    XdmcpWriteCARD8 (&buffer, sendRunning);
   1366 	    XdmcpWriteCARD32 (&buffer, sendSessionID);
   1367 	    XdmcpFlush (fd, &buffer, (XdmcpNetaddr) from, fromlen);
   1368 	}
   1369     }
   1370 }
   1371 
   1372 char *
   1373 NetworkAddressToHostname (
   1374     CARD16	connectionType,
   1375     ARRAY8Ptr   connectionAddress)
   1376 {
   1377     char    *name = NULL;
   1378 
   1379     switch (connectionType)
   1380     {
   1381     case FamilyInternet:
   1382 # ifdef IPv6
   1383     case FamilyInternet6:
   1384 # endif
   1385 	{
   1386 	    struct hostent	*hostent = NULL;
   1387 # ifdef IPv6
   1388 	    char dotted[INET6_ADDRSTRLEN];
   1389 # else
   1390 	    char dotted[20];
   1391 # endif
   1392 	    const char *local_name = "";
   1393 	    int af_type;
   1394 
   1395 # ifdef IPv6
   1396 	    if (connectionType == FamilyInternet6)
   1397 		af_type = AF_INET6;
   1398 	    else
   1399 # endif
   1400 		af_type = AF_INET;
   1401 
   1402 	    hostent = gethostbyaddr ((char *)connectionAddress->data,
   1403 				      connectionAddress->length, af_type);
   1404 
   1405 	    if (hostent) {
   1406 		/* check for DNS spoofing */
   1407 # if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_NTOP)
   1408 		struct addrinfo	*ai = NULL, *nai;
   1409 		if (getaddrinfo(hostent->h_name, NULL, NULL, &ai) == 0) {
   1410 		    for (nai = ai; nai != NULL; nai = nai->ai_next) {
   1411 			if ((af_type == nai->ai_family) && (
   1412 			  ((nai->ai_family == AF_INET) &&
   1413 			    (connectionAddress->length == sizeof(struct in_addr)) &&
   1414 			    (memcmp(connectionAddress->data,
   1415 				    &((struct sockaddr_in *)nai->ai_addr)->sin_addr,
   1416 				    connectionAddress->length) == 0))
   1417 #  ifdef IPv6
   1418 			  || ((nai->ai_family == AF_INET6) &&
   1419                               (connectionAddress->length ==
   1420                                sizeof(struct in6_addr)) &&
   1421                               (memcmp(connectionAddress->data,
   1422                                       &((struct sockaddr_in6 *)nai->ai_addr)->sin6_addr,
   1423                                       connectionAddress->length) == 0))
   1424 #  endif
   1425                                 ))
   1426 			    break;
   1427 		    }
   1428 		    if (nai == NULL) {
   1429 			inet_ntop(af_type, connectionAddress->data,
   1430 			  dotted, sizeof(dotted));
   1431 
   1432 			LogError("Possible DNS spoof attempt %s->%s.\n", dotted,
   1433 			  hostent->h_name);
   1434 			hostent = NULL;
   1435 		    } else {
   1436 		      local_name = hostent->h_name;
   1437 		    }
   1438 		    freeaddrinfo(ai);
   1439 		} else {
   1440 		    hostent = NULL;
   1441 		}
   1442 # else /* !HAVE_GETADDRINFO */
   1443 		char *s = strdup(hostent->h_name); /* fscking non-reentrancy of getXXX() */
   1444 		if ((hostent = gethostbyname(s))) {
   1445 			if (memcmp((char*)connectionAddress->data, hostent->h_addr,
   1446 			    hostent->h_length) != 0) {
   1447 				LogError("Possible DNS spoof attempt.\n");
   1448 				hostent = NULL; /* so it enters next if() */
   1449 			} else {
   1450 				local_name = hostent->h_name;
   1451 			}
   1452 		}
   1453 		free(s);
   1454 # endif
   1455 	    }
   1456 
   1457 	    if (!hostent) {
   1458 		/* can't get name, so use emergency fallback */
   1459 # ifdef HAVE_INET_NTOP
   1460 		inet_ntop(af_type, connectionAddress->data,
   1461 			  dotted, sizeof(dotted));
   1462 # else
   1463 		snprintf(dotted, sizeof(dotted), "%d.%d.%d.%d",
   1464 			 connectionAddress->data[0],
   1465 			 connectionAddress->data[1],
   1466 			 connectionAddress->data[2],
   1467 			 connectionAddress->data[3]);
   1468 # endif
   1469 		local_name = dotted;
   1470 		LogError ("Cannot convert Internet address %s to host name\n",
   1471 			  dotted);
   1472 	    }
   1473 	    name = strdup (local_name);
   1474 	    break;
   1475 	}
   1476     default:
   1477 	break;
   1478     }
   1479     return name;
   1480 }
   1481 
   1482 #endif /* XDMCP */
   1483