1/*
2 * Copyright 1989 Network Computing Devices, Inc., Mountain View, California.
3 *
4 * Permission to use, copy, modify, and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of N.C.D. not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  N.C.D. makes no representations about the
11 * suitability of this software for any purpose.  It is provided "as is"
12 * without express or implied warranty.
13 *
14 */
15
16#ifdef HAVE_DIX_CONFIG_H
17#include <dix-config.h>
18#endif
19
20#ifdef WIN32
21#include <X11/Xwinsock.h>
22#endif
23
24#include <X11/Xos.h>
25
26#if !defined(WIN32)
27#include <sys/param.h>
28#include <sys/socket.h>
29#include <netinet/in.h>
30#include <netdb.h>
31#endif
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <X11/X.h>
36#include <X11/Xmd.h>
37#include "misc.h"
38#include <X11/Xpoll.h>
39#include "osdep.h"
40#include "input.h"
41#include "dixstruct.h"
42#include "opaque.h"
43#include "site.h"
44
45#ifdef STREAMSCONN
46#include <tiuser.h>
47#include <netconfig.h>
48#include <netdir.h>
49#endif
50
51#ifdef XDMCP
52#undef REQUEST
53
54#ifdef XDMCP_NO_IPV6
55#undef IPv6
56#endif
57
58#include <X11/Xdmcp.h>
59
60#define X_INCLUDE_NETDB_H
61#include <X11/Xos_r.h>
62
63static char *defaultDisplayClass = COMPILEDDISPLAYCLASS;
64
65static int		    xdmcpSocket, sessionSocket;
66static xdmcp_states	    state;
67#if defined(IPv6) && defined(AF_INET6)
68static int		    xdmcpSocket6;
69static struct sockaddr_storage req_sockaddr;
70#else
71static struct sockaddr_in   req_sockaddr;
72#endif
73static int		    req_socklen;
74static CARD32		    SessionID;
75static CARD32		    timeOutTime;
76static int		    timeOutRtx;
77static CARD32		    defaultKeepaliveDormancy = XDM_DEF_DORMANCY;
78static CARD32		    keepaliveDormancy = XDM_DEF_DORMANCY;
79static CARD16		    DisplayNumber;
80static xdmcp_states	    XDM_INIT_STATE = XDM_OFF;
81#ifdef HASXDMAUTH
82static char		    *xdmAuthCookie;
83#endif
84
85static XdmcpBuffer	    buffer;
86
87#if defined(IPv6) && defined(AF_INET6)
88
89static struct addrinfo *mgrAddr;
90static struct addrinfo *mgrAddrFirst;
91
92#define SOCKADDR_TYPE		struct sockaddr_storage
93#define SOCKADDR_FAMILY(s)	((struct sockaddr *)&(s))->sa_family
94
95#ifdef BSD44SOCKETS
96#define SOCKLEN_FIELD(s)	((struct sockaddr *)&(s))->sa_len
97#define SOCKLEN_TYPE 		unsigned char
98#else
99#define SOCKLEN_TYPE 		unsigned int
100#endif
101
102#else
103
104#define SOCKADDR_TYPE		struct sockaddr_in
105#define SOCKADDR_FAMILY(s)	(s).sin_family
106
107#ifdef BSD44SOCKETS
108#define SOCKLEN_FIELD(s)	(s).sin_len
109#define SOCKLEN_TYPE		unsigned char
110#else
111#define SOCKLEN_TYPE		size_t
112#endif
113
114#endif
115
116static SOCKADDR_TYPE		ManagerAddress;
117static SOCKADDR_TYPE		FromAddress;
118
119#ifdef SOCKLEN_FIELD
120#define ManagerAddressLen	SOCKLEN_FIELD(ManagerAddress)
121#define FromAddressLen		SOCKLEN_FIELD(FromAddress)
122#else
123static SOCKLEN_TYPE ManagerAddressLen, FromAddressLen;
124#endif
125
126#if defined(IPv6) && defined(AF_INET6)
127static struct multicastinfo {
128    struct multicastinfo	*next;
129    struct addrinfo		*ai;
130    int				 hops;
131} *mcastlist;
132#endif
133
134static void XdmcpAddHost(
135    const struct sockaddr    *from,
136    int			fromlen,
137    ARRAY8Ptr		AuthenticationName,
138    ARRAY8Ptr		hostname,
139    ARRAY8Ptr		status);
140
141static void XdmcpSelectHost(
142    const struct sockaddr *host_sockaddr,
143    int			host_len,
144    ARRAY8Ptr		AuthenticationName);
145
146static void get_xdmcp_sock(void);
147
148static void send_query_msg(void);
149
150static void recv_willing_msg(
151    struct sockaddr * /*from*/,
152    int /*fromlen*/,
153    unsigned /*length*/);
154
155static void send_request_msg(void);
156
157static void recv_accept_msg(unsigned /*length*/);
158
159static void recv_decline_msg(unsigned /*length*/);
160
161static void send_manage_msg(void);
162
163static void recv_refuse_msg(unsigned /*length*/);
164
165static void recv_failed_msg(unsigned /*length*/);
166
167static void send_keepalive_msg(void);
168
169static void recv_alive_msg(unsigned /*length*/);
170
171static void XdmcpFatal(
172    const char * /*type*/,
173    ARRAY8Ptr /*status*/);
174
175static void XdmcpWarning(const char * /*str*/);
176
177static void get_manager_by_name(
178    int /*argc*/,
179    char ** /*argv*/,
180    int /*i*/);
181
182static void get_fromaddr_by_name(int /*argc*/, char ** /*argv*/, int /*i*/);
183
184#if defined(IPv6) && defined(AF_INET6)
185static int get_mcast_options(int /*argc*/, char ** /*argv*/, int /*i*/);
186#endif
187
188static void receive_packet(int /*socketfd*/);
189
190static void send_packet(void);
191
192static void timeout(void);
193
194static void restart(void);
195
196static void XdmcpBlockHandler(
197    pointer /*data*/,
198    struct timeval ** /*wt*/,
199    pointer /*LastSelectMask*/);
200
201static void XdmcpWakeupHandler(
202    pointer /*data*/,
203    int /*i*/,
204    pointer /*LastSelectMask*/);
205
206/*
207 * Register the Manufacturer display ID
208 */
209
210static ARRAY8 ManufacturerDisplayID;
211
212static void
213XdmcpRegisterManufacturerDisplayID (const char *name, int length)
214{
215    int	    i;
216
217    XdmcpDisposeARRAY8 (&ManufacturerDisplayID);
218    if (!XdmcpAllocARRAY8 (&ManufacturerDisplayID, length))
219	return;
220    for (i = 0; i < length; i++)
221	ManufacturerDisplayID.data[i] = (CARD8) name[i];
222}
223
224static unsigned short	xdm_udp_port = XDM_UDP_PORT;
225static Bool	OneSession = FALSE;
226static const char 	*xdm_from = NULL;
227
228void
229XdmcpUseMsg (void)
230{
231    ErrorF("-query host-name       contact named host for XDMCP\n");
232    ErrorF("-broadcast             broadcast for XDMCP\n");
233#if defined(IPv6) && defined(AF_INET6)
234    ErrorF("-multicast [addr [hops]] IPv6 multicast for XDMCP\n");
235#endif
236    ErrorF("-indirect host-name    contact named host for indirect XDMCP\n");
237    ErrorF("-port port-num         UDP port number to send messages to\n");
238    ErrorF("-from local-address    specify the local address to connect from\n");
239    ErrorF("-once                  Terminate server after one session\n");
240    ErrorF("-class display-class   specify display class to send in manage\n");
241#ifdef HASXDMAUTH
242    ErrorF("-cookie xdm-auth-bits  specify the magic cookie for XDMCP\n");
243#endif
244    ErrorF("-displayID display-id  manufacturer display ID for request\n");
245}
246
247int
248XdmcpOptions(int argc, char **argv, int i)
249{
250    if (strcmp(argv[i], "-query") == 0) {
251	get_manager_by_name(argc, argv, i++);
252	XDM_INIT_STATE = XDM_QUERY;
253	AccessUsingXdmcp ();
254	return i + 1;
255    }
256    if (strcmp(argv[i], "-broadcast") == 0) {
257	XDM_INIT_STATE = XDM_BROADCAST;
258	AccessUsingXdmcp ();
259	return i + 1;
260    }
261#if defined(IPv6) && defined(AF_INET6)
262    if (strcmp(argv[i], "-multicast") == 0) {
263	i = get_mcast_options(argc, argv, ++i);
264	XDM_INIT_STATE = XDM_MULTICAST;
265	AccessUsingXdmcp ();
266	return i + 1;
267    }
268#endif
269    if (strcmp(argv[i], "-indirect") == 0) {
270	get_manager_by_name(argc, argv, i++);
271	XDM_INIT_STATE = XDM_INDIRECT;
272	AccessUsingXdmcp ();
273	return i + 1;
274    }
275    if (strcmp(argv[i], "-port") == 0) {
276        if (++i == argc)  {
277	    FatalError("Xserver: missing port number in command line\n");
278	}
279	xdm_udp_port = (unsigned short) atoi(argv[i]);
280	return i + 1;
281    }
282    if (strcmp(argv[i], "-from") == 0) {
283	get_fromaddr_by_name(argc, argv, ++i);
284	return i + 1;
285    }
286    if (strcmp(argv[i], "-once") == 0) {
287	OneSession = TRUE;
288	return i + 1;
289    }
290    if (strcmp(argv[i], "-class") == 0) {
291        if (++i == argc)  {
292	    FatalError("Xserver: missing class name in command line\n");
293	}
294	defaultDisplayClass = argv[i];
295	return i + 1;
296    }
297#ifdef HASXDMAUTH
298    if (strcmp(argv[i], "-cookie") == 0) {
299        if (++i == argc)  {
300	    FatalError("Xserver: missing cookie data in command line\n");
301	}
302	xdmAuthCookie = argv[i];
303	return i + 1;
304    }
305#endif
306    if (strcmp(argv[i], "-displayID") == 0) {
307        if (++i == argc)  {
308	    FatalError("Xserver: missing displayID in command line\n");
309	}
310	XdmcpRegisterManufacturerDisplayID (argv[i], strlen (argv[i]));
311	return i + 1;
312    }
313    return i;
314}
315
316/*
317 * This section is a collection of routines for
318 * registering server-specific data with the XDMCP
319 * state machine.
320 */
321
322
323/*
324 * Save all broadcast addresses away so BroadcastQuery
325 * packets get sent everywhere
326 */
327
328#define MAX_BROADCAST	10
329
330/* This stays sockaddr_in since IPv6 doesn't support broadcast */
331static struct sockaddr_in   BroadcastAddresses[MAX_BROADCAST];
332static int		    NumBroadcastAddresses;
333
334void
335XdmcpRegisterBroadcastAddress (const struct sockaddr_in *addr)
336{
337    struct sockaddr_in	*bcast;
338    if (NumBroadcastAddresses >= MAX_BROADCAST)
339	return;
340    bcast = &BroadcastAddresses[NumBroadcastAddresses++];
341    memset(bcast, 0, sizeof (struct sockaddr_in));
342#ifdef BSD44SOCKETS
343    bcast->sin_len = addr->sin_len;
344#endif
345    bcast->sin_family = addr->sin_family;
346    bcast->sin_port = htons (xdm_udp_port);
347    bcast->sin_addr = addr->sin_addr;
348}
349
350/*
351 * Each authentication type is registered here; Validator
352 * will be called to check all access attempts using
353 * the specified authentication type
354 */
355
356static ARRAYofARRAY8	AuthenticationNames, AuthenticationDatas;
357typedef struct _AuthenticationFuncs {
358    ValidatorFunc    Validator;
359    GeneratorFunc    Generator;
360    AddAuthorFunc    AddAuth;
361} AuthenticationFuncsRec, *AuthenticationFuncsPtr;
362
363static AuthenticationFuncsPtr	AuthenticationFuncsList;
364
365void
366XdmcpRegisterAuthentication (
367    const char    *name,
368    int	    namelen,
369    const char    *data,
370    int	    datalen,
371    ValidatorFunc Validator,
372    GeneratorFunc Generator,
373    AddAuthorFunc AddAuth)
374{
375    int	    i;
376    ARRAY8  AuthenticationName, AuthenticationData;
377    static AuthenticationFuncsPtr	newFuncs;
378
379    if (!XdmcpAllocARRAY8 (&AuthenticationName, namelen))
380	return;
381    if (!XdmcpAllocARRAY8 (&AuthenticationData, datalen))
382    {
383	XdmcpDisposeARRAY8 (&AuthenticationName);
384	return;
385    }
386    for (i = 0; i < namelen; i++)
387	AuthenticationName.data[i] = name[i];
388    for (i = 0; i < datalen; i++)
389	AuthenticationData.data[i] = data[i];
390    if (!(XdmcpReallocARRAYofARRAY8 (&AuthenticationNames,
391				     AuthenticationNames.length + 1) &&
392	  XdmcpReallocARRAYofARRAY8 (&AuthenticationDatas,
393				     AuthenticationDatas.length + 1) &&
394	  (newFuncs = malloc((AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec)))))
395    {
396	XdmcpDisposeARRAY8 (&AuthenticationName);
397	XdmcpDisposeARRAY8 (&AuthenticationData);
398	return;
399    }
400    for (i = 0; i < AuthenticationNames.length - 1; i++)
401	newFuncs[i] = AuthenticationFuncsList[i];
402    newFuncs[AuthenticationNames.length-1].Validator = Validator;
403    newFuncs[AuthenticationNames.length-1].Generator = Generator;
404    newFuncs[AuthenticationNames.length-1].AddAuth = AddAuth;
405    free(AuthenticationFuncsList);
406    AuthenticationFuncsList = newFuncs;
407    AuthenticationNames.data[AuthenticationNames.length-1] = AuthenticationName;
408    AuthenticationDatas.data[AuthenticationDatas.length-1] = AuthenticationData;
409}
410
411/*
412 * Select the authentication type to be used; this is
413 * set by the manager of the host to be connected to.
414 */
415
416static ARRAY8		noAuthenticationName = {(CARD16) 0, (CARD8Ptr) 0};
417static ARRAY8		noAuthenticationData = {(CARD16) 0, (CARD8Ptr) 0};
418static ARRAY8Ptr	AuthenticationName = &noAuthenticationName;
419static ARRAY8Ptr	AuthenticationData = &noAuthenticationData;
420static AuthenticationFuncsPtr	AuthenticationFuncs;
421
422static void
423XdmcpSetAuthentication (const ARRAY8Ptr name)
424{
425    int	i;
426
427    for (i = 0; i < AuthenticationNames.length; i++)
428	if (XdmcpARRAY8Equal (&AuthenticationNames.data[i], name))
429	{
430	    AuthenticationName = &AuthenticationNames.data[i];
431	    AuthenticationData = &AuthenticationDatas.data[i];
432	    AuthenticationFuncs = &AuthenticationFuncsList[i];
433	    break;
434	}
435}
436
437/*
438 * Register the host address for the display
439 */
440
441static ARRAY16		ConnectionTypes;
442static ARRAYofARRAY8	ConnectionAddresses;
443static long		xdmcpGeneration;
444
445void
446XdmcpRegisterConnection (
447    int	    type,
448    const char    *address,
449    int	    addrlen)
450{
451    int	    i;
452    CARD8   *newAddress;
453
454    if (xdmcpGeneration != serverGeneration)
455    {
456	XdmcpDisposeARRAY16 (&ConnectionTypes);
457	XdmcpDisposeARRAYofARRAY8 (&ConnectionAddresses);
458	xdmcpGeneration = serverGeneration;
459    }
460    if (xdm_from != NULL) {	/* Only register the requested address */
461	const void *regAddr = address;
462	const void *fromAddr = NULL;
463	int regAddrlen = addrlen;
464
465	if (addrlen == sizeof(struct in_addr)) {
466	    if (SOCKADDR_FAMILY(FromAddress) == AF_INET) {
467		fromAddr = &((struct sockaddr_in *)&FromAddress)->sin_addr;
468	    }
469#if defined(IPv6) && defined(AF_INET6)
470	    else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET6) &&
471	      IN6_IS_ADDR_V4MAPPED(
472		  &((struct sockaddr_in6 *)&FromAddress)->sin6_addr)) {
473		fromAddr = &((struct sockaddr_in6 *)&FromAddress)->sin6_addr.s6_addr[12];
474	    }
475#endif
476	}
477#if defined(IPv6) && defined(AF_INET6)
478	else if (addrlen == sizeof(struct in6_addr)) {
479	    if (SOCKADDR_FAMILY(FromAddress) == AF_INET6) {
480		fromAddr = &((struct sockaddr_in6 *)&FromAddress)->sin6_addr;
481	    } else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET) &&
482	      IN6_IS_ADDR_V4MAPPED((struct in6_addr *) address)) {
483		fromAddr = &((struct sockaddr_in *)&FromAddress)->sin_addr;
484		regAddr = &((struct sockaddr_in6 *)&address)->sin6_addr.s6_addr[12];
485		regAddrlen = sizeof(struct in_addr);
486	    }
487	}
488#endif
489	if (fromAddr && memcmp(regAddr, fromAddr, regAddrlen) != 0) {
490	    return;
491	}
492    }
493    if (ConnectionAddresses.length + 1 == 256)
494	return;
495    newAddress = malloc(addrlen * sizeof (CARD8));
496    if (!newAddress)
497	return;
498    if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1))
499    {
500	free(newAddress);
501	return;
502    }
503    if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses,
504				    ConnectionAddresses.length +  1))
505    {
506	free(newAddress);
507	return;
508    }
509    ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type;
510    for (i = 0; i < addrlen; i++)
511	newAddress[i] = address[i];
512    ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress;
513    ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen;
514}
515
516/*
517 * Register an Authorization Name.  XDMCP advertises this list
518 * to the manager.
519 */
520
521static ARRAYofARRAY8	AuthorizationNames;
522
523void
524XdmcpRegisterAuthorizations (void)
525{
526    XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames);
527    RegisterAuthorizations ();
528}
529
530void
531XdmcpRegisterAuthorization (const char *name, int namelen)
532{
533    ARRAY8  authName;
534    int	    i;
535
536    authName.data = malloc(namelen * sizeof (CARD8));
537    if (!authName.data)
538	return;
539    if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1))
540    {
541	free(authName.data);
542	return;
543    }
544    for (i = 0; i < namelen; i++)
545	authName.data[i] = (CARD8) name[i];
546    authName.length = namelen;
547    AuthorizationNames.data[AuthorizationNames.length-1] = authName;
548}
549
550/*
551 * Register the DisplayClass string
552 */
553
554static ARRAY8	DisplayClass;
555
556static void
557XdmcpRegisterDisplayClass (const char *name, int length)
558{
559    int	    i;
560
561    XdmcpDisposeARRAY8 (&DisplayClass);
562    if (!XdmcpAllocARRAY8 (&DisplayClass, length))
563	return;
564    for (i = 0; i < length; i++)
565	DisplayClass.data[i] = (CARD8) name[i];
566}
567
568/*
569 * initialize XDMCP; create the socket, compute the display
570 * number, set up the state machine
571 */
572
573void
574XdmcpInit(void)
575{
576    state = XDM_INIT_STATE;
577#ifdef HASXDMAUTH
578    if (xdmAuthCookie)
579	XdmAuthenticationInit (xdmAuthCookie, strlen (xdmAuthCookie));
580#endif
581    if (state != XDM_OFF)
582    {
583	XdmcpRegisterAuthorizations();
584	XdmcpRegisterDisplayClass (defaultDisplayClass, strlen (defaultDisplayClass));
585	AccessUsingXdmcp();
586	RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
587				        (pointer) 0);
588    	timeOutRtx = 0;
589    	DisplayNumber = (CARD16) atoi(display);
590    	get_xdmcp_sock();
591    	send_packet();
592    }
593}
594
595void
596XdmcpReset (void)
597{
598    state = XDM_INIT_STATE;
599    if (state != XDM_OFF)
600    {
601	RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
602				        (pointer) 0);
603    	timeOutRtx = 0;
604    	send_packet();
605    }
606}
607
608/*
609 * Called whenever a new connection is created; notices the
610 * first connection and saves it to terminate the session
611 * when it is closed
612 */
613
614void
615XdmcpOpenDisplay(int sock)
616{
617    if (state != XDM_AWAIT_MANAGE_RESPONSE)
618	return;
619    state = XDM_RUN_SESSION;
620    sessionSocket = sock;
621}
622
623void
624XdmcpCloseDisplay(int sock)
625{
626    if ((state != XDM_RUN_SESSION && state != XDM_AWAIT_ALIVE_RESPONSE)
627	|| sessionSocket != sock)
628	    return;
629    state = XDM_INIT_STATE;
630    if (OneSession)
631	dispatchException |= DE_TERMINATE;
632    else
633	dispatchException |= DE_RESET;
634    isItTimeToYield = TRUE;
635}
636
637/*
638 * called before going to sleep, this routine
639 * may modify the timeout value about to be sent
640 * to select; in this way XDMCP can do appropriate things
641 * dynamically while starting up
642 */
643
644/*ARGSUSED*/
645static void
646XdmcpBlockHandler(
647    pointer	    data,   /* unused */
648    struct timeval  **wt,
649    pointer	    pReadmask)
650{
651    fd_set *LastSelectMask = (fd_set*)pReadmask;
652    CARD32 millisToGo;
653
654    if (state == XDM_OFF)
655	return;
656    FD_SET(xdmcpSocket, LastSelectMask);
657#if defined(IPv6) && defined(AF_INET6)
658    if (xdmcpSocket6 >= 0)
659	FD_SET(xdmcpSocket6, LastSelectMask);
660#endif
661    if (timeOutTime == 0)
662	return;
663    millisToGo = timeOutTime - GetTimeInMillis();
664    if ((int) millisToGo < 0)
665	millisToGo = 0;
666    AdjustWaitForDelay (wt, millisToGo);
667}
668
669/*
670 * called after select returns; this routine will
671 * recognise when XDMCP packets await and
672 * process them appropriately
673 */
674
675/*ARGSUSED*/
676static void
677XdmcpWakeupHandler(
678    pointer data,   /* unused */
679    int	    i,
680    pointer pReadmask)
681{
682    fd_set* LastSelectMask = (fd_set*)pReadmask;
683    fd_set   devicesReadable;
684
685    if (state == XDM_OFF)
686	return;
687    if (i > 0)
688    {
689	if (FD_ISSET(xdmcpSocket, LastSelectMask))
690	{
691	    receive_packet(xdmcpSocket);
692	    FD_CLR(xdmcpSocket, LastSelectMask);
693	}
694#if defined(IPv6) && defined(AF_INET6)
695	if (xdmcpSocket6 >= 0 && FD_ISSET(xdmcpSocket6, LastSelectMask))
696	{
697	    receive_packet(xdmcpSocket6);
698	    FD_CLR(xdmcpSocket6, LastSelectMask);
699	}
700#endif
701	XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices);
702	if (XFD_ANYSET(&devicesReadable))
703	{
704	    if (state == XDM_AWAIT_USER_INPUT)
705		restart();
706	    else if (state == XDM_RUN_SESSION)
707		keepaliveDormancy = defaultKeepaliveDormancy;
708	}
709	if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION)
710	    timeOutTime = GetTimeInMillis() +  keepaliveDormancy * 1000;
711    }
712    else if (timeOutTime && (int) (GetTimeInMillis() - timeOutTime) >= 0)
713    {
714    	if (state == XDM_RUN_SESSION)
715    	{
716	    state = XDM_KEEPALIVE;
717	    send_packet();
718    	}
719    	else
720	    timeout();
721    }
722}
723
724/*
725 * This routine should be called from the routine that drives the
726 * user's host menu when the user selects a host
727 */
728
729static void
730XdmcpSelectHost(
731    const struct sockaddr	*host_sockaddr,
732    int			host_len,
733    ARRAY8Ptr		AuthenticationName)
734{
735    state = XDM_START_CONNECTION;
736    memmove(&req_sockaddr, host_sockaddr, host_len);
737    req_socklen = host_len;
738    XdmcpSetAuthentication (AuthenticationName);
739    send_packet();
740}
741
742/*
743 * !!! this routine should be replaced by a routine that adds
744 * the host to the user's host menu. the current version just
745 * selects the first host to respond with willing message.
746 */
747
748/*ARGSUSED*/
749static void
750XdmcpAddHost(
751    const struct sockaddr    *from,
752    int			fromlen,
753    ARRAY8Ptr		AuthenticationName,
754    ARRAY8Ptr		hostname,
755    ARRAY8Ptr		status)
756{
757    XdmcpSelectHost(from, fromlen, AuthenticationName);
758}
759
760/*
761 * A message is queued on the socket; read it and
762 * do the appropriate thing
763 */
764
765static ARRAY8	UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" };
766
767static void
768receive_packet(int socketfd)
769{
770#if defined(IPv6) && defined(AF_INET6)
771    struct sockaddr_storage from;
772#else
773    struct sockaddr_in from;
774#endif
775    int fromlen = sizeof(from);
776    XdmcpHeader	header;
777
778    /* read message off socket */
779    if (!XdmcpFill (socketfd, &buffer, (XdmcpNetaddr) &from, &fromlen))
780	return;
781
782    /* reset retransmission backoff */
783    timeOutRtx = 0;
784
785    if (!XdmcpReadHeader (&buffer, &header))
786	return;
787
788    if (header.version != XDM_PROTOCOL_VERSION)
789	return;
790
791    switch (header.opcode) {
792    case WILLING:
793	recv_willing_msg((struct sockaddr *) &from, fromlen, header.length);
794	break;
795    case UNWILLING:
796	XdmcpFatal("Manager unwilling", &UnwillingMessage);
797	break;
798    case ACCEPT:
799	recv_accept_msg(header.length);
800	break;
801    case DECLINE:
802	recv_decline_msg(header.length);
803	break;
804    case REFUSE:
805	recv_refuse_msg(header.length);
806	break;
807    case FAILED:
808	recv_failed_msg(header.length);
809	break;
810    case ALIVE:
811	recv_alive_msg(header.length);
812	break;
813    }
814}
815
816/*
817 * send the appropriate message given the current state
818 */
819
820static void
821send_packet(void)
822{
823    int rtx;
824    switch (state) {
825    case XDM_QUERY:
826    case XDM_BROADCAST:
827    case XDM_INDIRECT:
828#if defined(IPv6)  && defined(AF_INET6)
829    case XDM_MULTICAST:
830#endif
831	send_query_msg();
832	break;
833    case XDM_START_CONNECTION:
834	send_request_msg();
835	break;
836    case XDM_MANAGE:
837	send_manage_msg();
838	break;
839    case XDM_KEEPALIVE:
840	send_keepalive_msg();
841	break;
842    default:
843	break;
844    }
845    rtx = (XDM_MIN_RTX << timeOutRtx);
846    if (rtx > XDM_MAX_RTX)
847	rtx = XDM_MAX_RTX;
848    timeOutTime = GetTimeInMillis() + rtx * 1000;
849}
850
851/*
852 * The session is declared dead for some reason; too many
853 * timeouts, or Keepalive failure.
854 */
855
856static void
857XdmcpDeadSession (const char *reason)
858{
859    ErrorF ("XDM: %s, declaring session dead\n", reason);
860    state = XDM_INIT_STATE;
861    isItTimeToYield = TRUE;
862    dispatchException |= DE_RESET;
863    timeOutTime = 0;
864    timeOutRtx = 0;
865    send_packet();
866}
867
868/*
869 * Timeout waiting for an XDMCP response.
870 */
871
872static void
873timeout(void)
874{
875    timeOutRtx++;
876    if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT )
877    {
878	XdmcpDeadSession ("too many keepalive retransmissions");
879	return;
880    }
881    else if (timeOutRtx >= XDM_RTX_LIMIT)
882    {
883	/* Quit if "-once" specified, otherwise reset and try again. */
884        if (OneSession) {
885	    dispatchException |= DE_TERMINATE;
886	    ErrorF("XDM: too many retransmissions\n");
887	} else {
888	    XdmcpDeadSession("too many retransmissions");
889	}
890	return;
891    }
892
893#if defined(IPv6) && defined(AF_INET6)
894    if (state == XDM_COLLECT_QUERY || state == XDM_COLLECT_INDIRECT_QUERY) {
895	/* Try next address */
896	for (mgrAddr = mgrAddr->ai_next; ; mgrAddr = mgrAddr->ai_next) {
897	    if (mgrAddr == NULL) {
898		mgrAddr = mgrAddrFirst;
899	    }
900	    if (mgrAddr->ai_family == AF_INET
901	      || mgrAddr->ai_family == AF_INET6)
902		break;
903	}
904#ifndef SIN6_LEN
905	ManagerAddressLen = mgrAddr->ai_addrlen;
906#endif
907	memcpy(&ManagerAddress, mgrAddr->ai_addr, mgrAddr->ai_addrlen);
908    }
909#endif
910
911    switch (state) {
912    case XDM_COLLECT_QUERY:
913	state = XDM_QUERY;
914	break;
915    case XDM_COLLECT_BROADCAST_QUERY:
916	state = XDM_BROADCAST;
917	break;
918#if defined(IPv6) && defined(AF_INET6)
919    case XDM_COLLECT_MULTICAST_QUERY:
920	state = XDM_MULTICAST;
921	break;
922#endif
923    case XDM_COLLECT_INDIRECT_QUERY:
924	state = XDM_INDIRECT;
925	break;
926    case XDM_AWAIT_REQUEST_RESPONSE:
927	state = XDM_START_CONNECTION;
928	break;
929    case XDM_AWAIT_MANAGE_RESPONSE:
930	state = XDM_MANAGE;
931	break;
932    case XDM_AWAIT_ALIVE_RESPONSE:
933	state = XDM_KEEPALIVE;
934	break;
935    default:
936	break;
937    }
938    send_packet();
939}
940
941static void
942restart(void)
943{
944    state = XDM_INIT_STATE;
945    timeOutRtx = 0;
946    send_packet();
947}
948
949static int
950XdmcpCheckAuthentication (ARRAY8Ptr Name, ARRAY8Ptr Data, int packet_type)
951{
952    return (XdmcpARRAY8Equal (Name, AuthenticationName) &&
953	    (AuthenticationName->length == 0 ||
954	     (*AuthenticationFuncs->Validator) (AuthenticationData, Data, packet_type)));
955}
956
957static int
958XdmcpAddAuthorization (ARRAY8Ptr name, ARRAY8Ptr data)
959{
960    AddAuthorFunc AddAuth;
961
962    if (AuthenticationFuncs && AuthenticationFuncs->AddAuth)
963	AddAuth = AuthenticationFuncs->AddAuth;
964    else
965	AddAuth = AddAuthorization;
966    return (*AddAuth) ((unsigned short)name->length,
967		       (char *)name->data,
968		       (unsigned short)data->length,
969		       (char *)data->data);
970}
971
972/*
973 * from here to the end of this file are routines private
974 * to the state machine.
975 */
976
977static void
978get_xdmcp_sock(void)
979{
980#ifdef STREAMSCONN
981    struct netconfig *nconf;
982
983    if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) {
984	XdmcpWarning("t_open() of /dev/udp failed");
985	return;
986    }
987
988    if( t_bind(xdmcpSocket,NULL,NULL) < 0 ) {
989	XdmcpWarning("UDP socket creation failed");
990	t_error("t_bind(xdmcpSocket) failed" );
991	t_close(xdmcpSocket);
992	return;
993    }
994
995    /*
996     * This part of the code looks contrived. It will actually fit in nicely
997     * when the CLTS part of Xtrans is implemented.
998     */
999
1000    if( (nconf=getnetconfigent("udp")) == NULL ) {
1001	XdmcpWarning("UDP socket creation failed: getnetconfigent()");
1002	t_unbind(xdmcpSocket);
1003	t_close(xdmcpSocket);
1004	return;
1005    }
1006
1007    if( netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL) ) {
1008	XdmcpWarning("UDP set broadcast option failed: netdir_options()");
1009	freenetconfigent(nconf);
1010	t_unbind(xdmcpSocket);
1011	t_close(xdmcpSocket);
1012	return;
1013    }
1014
1015    freenetconfigent(nconf);
1016#else
1017    int soopts = 1;
1018
1019#if defined(IPv6) && defined(AF_INET6)
1020    if ((xdmcpSocket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1021	XdmcpWarning("INET6 UDP socket creation failed");
1022#endif
1023    if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1024	XdmcpWarning("UDP socket creation failed");
1025#ifdef SO_BROADCAST
1026    else if (setsockopt(xdmcpSocket, SOL_SOCKET, SO_BROADCAST, (char *)&soopts,
1027	sizeof(soopts)) < 0)
1028	    XdmcpWarning("UDP set broadcast socket-option failed");
1029#endif /* SO_BROADCAST */
1030    if (xdmcpSocket >= 0 && xdm_from != NULL) {
1031	if (bind(xdmcpSocket, (struct sockaddr *)&FromAddress,
1032		 FromAddressLen) < 0) {
1033	    FatalError("Xserver: failed to bind to -from address: %s\n", xdm_from);
1034	}
1035    }
1036#endif /* STREAMSCONN */
1037}
1038
1039static void
1040send_query_msg(void)
1041{
1042    XdmcpHeader	header;
1043    Bool	broadcast = FALSE;
1044#if defined(IPv6) && defined(AF_INET6)
1045    Bool	multicast = FALSE;
1046#endif
1047    int		i;
1048    int 	socketfd = xdmcpSocket;
1049
1050    header.version = XDM_PROTOCOL_VERSION;
1051    switch(state){
1052    case XDM_QUERY:
1053	header.opcode = (CARD16) QUERY;
1054	state = XDM_COLLECT_QUERY;
1055	break;
1056    case XDM_BROADCAST:
1057	header.opcode = (CARD16) BROADCAST_QUERY;
1058	state = XDM_COLLECT_BROADCAST_QUERY;
1059	broadcast = TRUE;
1060	break;
1061#if defined(IPv6) && defined(AF_INET6)
1062    case XDM_MULTICAST:
1063	header.opcode = (CARD16) BROADCAST_QUERY;
1064	state = XDM_COLLECT_MULTICAST_QUERY;
1065	multicast = TRUE;
1066	break;
1067#endif
1068    case XDM_INDIRECT:
1069	header.opcode = (CARD16) INDIRECT_QUERY;
1070	state = XDM_COLLECT_INDIRECT_QUERY;
1071	break;
1072    default:
1073	break;
1074    }
1075    header.length = 1;
1076    for (i = 0; i < AuthenticationNames.length; i++)
1077	header.length += 2 + AuthenticationNames.data[i].length;
1078
1079    XdmcpWriteHeader (&buffer, &header);
1080    XdmcpWriteARRAYofARRAY8 (&buffer, &AuthenticationNames);
1081    if (broadcast)
1082    {
1083	int i;
1084
1085	for (i = 0; i < NumBroadcastAddresses; i++)
1086	    XdmcpFlush (xdmcpSocket, &buffer, (XdmcpNetaddr) &BroadcastAddresses[i],
1087			sizeof (struct sockaddr_in));
1088    }
1089#if defined(IPv6) && defined(AF_INET6)
1090    else if (multicast)
1091    {
1092	struct multicastinfo *mcl;
1093	struct addrinfo *ai;
1094
1095	for (mcl = mcastlist; mcl != NULL; mcl = mcl->next) {
1096	    for (ai = mcl->ai ; ai != NULL; ai = ai->ai_next) {
1097		if (ai->ai_family == AF_INET) {
1098		    unsigned char hopflag = (unsigned char) mcl->hops;
1099		    socketfd = xdmcpSocket;
1100		    setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL,
1101		      &hopflag, sizeof(hopflag));
1102		} else if (ai->ai_family == AF_INET6) {
1103		    int hopflag6 = mcl->hops;
1104		    socketfd = xdmcpSocket6;
1105		    setsockopt(socketfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1106		      &hopflag6, sizeof(hopflag6));
1107		} else {
1108		    continue;
1109		}
1110		XdmcpFlush (socketfd, &buffer,
1111		  	    (XdmcpNetaddr) ai->ai_addr, ai->ai_addrlen);
1112		break;
1113	    }
1114	}
1115    }
1116#endif
1117    else
1118    {
1119#if defined(IPv6) && defined(AF_INET6)
1120	if (SOCKADDR_FAMILY(ManagerAddress) == AF_INET6)
1121	    socketfd = xdmcpSocket6;
1122#endif
1123	XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &ManagerAddress,
1124		    ManagerAddressLen);
1125    }
1126}
1127
1128static void
1129recv_willing_msg(
1130    struct sockaddr	*from,
1131    int			fromlen,
1132    unsigned		length)
1133{
1134    ARRAY8	authenticationName;
1135    ARRAY8	hostname;
1136    ARRAY8	status;
1137
1138    authenticationName.data = 0;
1139    hostname.data = 0;
1140    status.data = 0;
1141    if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
1142	XdmcpReadARRAY8 (&buffer, &hostname) &&
1143	XdmcpReadARRAY8 (&buffer, &status))
1144    {
1145    	if (length == 6 + authenticationName.length +
1146		      hostname.length + status.length)
1147    	{
1148	    switch (state)
1149	    {
1150	    case XDM_COLLECT_QUERY:
1151	    	XdmcpSelectHost(from, fromlen, &authenticationName);
1152	    	break;
1153	    case XDM_COLLECT_BROADCAST_QUERY:
1154#if defined(IPv6) && defined(AF_INET6)
1155	    case XDM_COLLECT_MULTICAST_QUERY:
1156#endif
1157	    case XDM_COLLECT_INDIRECT_QUERY:
1158	    	XdmcpAddHost(from, fromlen, &authenticationName, &hostname, &status);
1159	    	break;
1160	    default:
1161		break;
1162    	    }
1163    	}
1164    }
1165    XdmcpDisposeARRAY8 (&authenticationName);
1166    XdmcpDisposeARRAY8 (&hostname);
1167    XdmcpDisposeARRAY8 (&status);
1168}
1169
1170static void
1171send_request_msg(void)
1172{
1173    XdmcpHeader	    header;
1174    int		    length;
1175    int		    i;
1176    CARD16	    XdmcpConnectionType;
1177    ARRAY8	    authenticationData;
1178    int		    socketfd = xdmcpSocket;
1179
1180    switch (SOCKADDR_FAMILY(ManagerAddress))
1181    {
1182    case AF_INET:	XdmcpConnectionType=FamilyInternet; break;
1183#if defined(IPv6) && defined(AF_INET6)
1184    case AF_INET6:	XdmcpConnectionType=FamilyInternet6; break;
1185#endif
1186    default:		XdmcpConnectionType=0xffff; break;
1187    }
1188
1189    header.version = XDM_PROTOCOL_VERSION;
1190    header.opcode = (CARD16) REQUEST;
1191
1192    length = 2;					    /* display number */
1193    length += 1 + 2 * ConnectionTypes.length;	    /* connection types */
1194    length += 1;				    /* connection addresses */
1195    for (i = 0; i < ConnectionAddresses.length; i++)
1196	length += 2 + ConnectionAddresses.data[i].length;
1197    authenticationData.length = 0;
1198    authenticationData.data = 0;
1199    if (AuthenticationFuncs)
1200    {
1201	(*AuthenticationFuncs->Generator) (AuthenticationData,
1202					   &authenticationData,
1203 					   REQUEST);
1204    }
1205    length += 2 + AuthenticationName->length;	    /* authentication name */
1206    length += 2 + authenticationData.length;	    /* authentication data */
1207    length += 1;				    /* authorization names */
1208    for (i = 0; i < AuthorizationNames.length; i++)
1209	length += 2 + AuthorizationNames.data[i].length;
1210    length += 2 + ManufacturerDisplayID.length;	    /* display ID */
1211    header.length = length;
1212
1213    if (!XdmcpWriteHeader (&buffer, &header))
1214    {
1215	XdmcpDisposeARRAY8 (&authenticationData);
1216	return;
1217    }
1218    XdmcpWriteCARD16 (&buffer, DisplayNumber);
1219    XdmcpWriteCARD8 (&buffer, ConnectionTypes.length);
1220
1221    /* The connection array is send reordered, so that connections of	*/
1222    /* the same address type as the XDMCP manager connection are send	*/
1223    /* first. This works around a bug in xdm. mario@klebsch.de 		*/
1224    for (i = 0; i < (int)ConnectionTypes.length; i++)
1225	if (ConnectionTypes.data[i]==XdmcpConnectionType)
1226	    XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]);
1227    for (i = 0; i < (int)ConnectionTypes.length; i++)
1228	if (ConnectionTypes.data[i]!=XdmcpConnectionType)
1229	    XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]);
1230
1231    XdmcpWriteCARD8 (&buffer, ConnectionAddresses.length);
1232    for (i = 0; i < (int)ConnectionAddresses.length; i++)
1233	if ( (i<ConnectionTypes.length) &&
1234	     (ConnectionTypes.data[i]==XdmcpConnectionType) )
1235	    XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]);
1236    for (i = 0; i < (int)ConnectionAddresses.length; i++)
1237	if ( (i>=ConnectionTypes.length) ||
1238	     (ConnectionTypes.data[i]!=XdmcpConnectionType) )
1239	    XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]);
1240
1241    XdmcpWriteARRAY8 (&buffer, AuthenticationName);
1242    XdmcpWriteARRAY8 (&buffer, &authenticationData);
1243    XdmcpDisposeARRAY8 (&authenticationData);
1244    XdmcpWriteARRAYofARRAY8 (&buffer, &AuthorizationNames);
1245    XdmcpWriteARRAY8 (&buffer, &ManufacturerDisplayID);
1246#if defined(IPv6) && defined(AF_INET6)
1247    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
1248	socketfd = xdmcpSocket6;
1249#endif
1250    if (XdmcpFlush (socketfd, &buffer,
1251			(XdmcpNetaddr) &req_sockaddr, req_socklen))
1252	state = XDM_AWAIT_REQUEST_RESPONSE;
1253}
1254
1255static void
1256recv_accept_msg(unsigned length)
1257{
1258    CARD32  AcceptSessionID;
1259    ARRAY8  AcceptAuthenticationName, AcceptAuthenticationData;
1260    ARRAY8  AcceptAuthorizationName, AcceptAuthorizationData;
1261
1262    if (state != XDM_AWAIT_REQUEST_RESPONSE)
1263	return;
1264    AcceptAuthenticationName.data = 0;
1265    AcceptAuthenticationData.data = 0;
1266    AcceptAuthorizationName.data = 0;
1267    AcceptAuthorizationData.data = 0;
1268    if (XdmcpReadCARD32 (&buffer, &AcceptSessionID) &&
1269	XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationName) &&
1270	XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationData) &&
1271	XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationName) &&
1272	XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationData))
1273    {
1274    	if (length == 12 + AcceptAuthenticationName.length +
1275		      	   AcceptAuthenticationData.length +
1276		      	   AcceptAuthorizationName.length +
1277 		      	   AcceptAuthorizationData.length)
1278    	{
1279	    if (!XdmcpCheckAuthentication (&AcceptAuthenticationName,
1280				      &AcceptAuthenticationData, ACCEPT))
1281	    {
1282		XdmcpFatal ("Authentication Failure", &AcceptAuthenticationName);
1283	    }
1284	    /* permit access control manipulations from this host */
1285	    AugmentSelf (&req_sockaddr, req_socklen);
1286	    /* if the authorization specified in the packet fails
1287	     * to be acceptable, enable the local addresses
1288	     */
1289	    if (!XdmcpAddAuthorization (&AcceptAuthorizationName,
1290					&AcceptAuthorizationData))
1291	    {
1292		AddLocalHosts ();
1293	    }
1294	    SessionID = AcceptSessionID;
1295    	    state = XDM_MANAGE;
1296    	    send_packet();
1297    	}
1298    }
1299    XdmcpDisposeARRAY8 (&AcceptAuthenticationName);
1300    XdmcpDisposeARRAY8 (&AcceptAuthenticationData);
1301    XdmcpDisposeARRAY8 (&AcceptAuthorizationName);
1302    XdmcpDisposeARRAY8 (&AcceptAuthorizationData);
1303}
1304
1305static void
1306recv_decline_msg(unsigned length)
1307{
1308    ARRAY8  status, DeclineAuthenticationName, DeclineAuthenticationData;
1309
1310    status.data = 0;
1311    DeclineAuthenticationName.data = 0;
1312    DeclineAuthenticationData.data = 0;
1313    if (XdmcpReadARRAY8 (&buffer, &status) &&
1314	XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationName) &&
1315	XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationData))
1316    {
1317    	if (length == 6 + status.length +
1318		      	  DeclineAuthenticationName.length +
1319 		      	  DeclineAuthenticationData.length &&
1320	    XdmcpCheckAuthentication (&DeclineAuthenticationName,
1321				      &DeclineAuthenticationData, DECLINE))
1322    	{
1323	    XdmcpFatal ("Session declined", &status);
1324    	}
1325    }
1326    XdmcpDisposeARRAY8 (&status);
1327    XdmcpDisposeARRAY8 (&DeclineAuthenticationName);
1328    XdmcpDisposeARRAY8 (&DeclineAuthenticationData);
1329}
1330
1331static void
1332send_manage_msg(void)
1333{
1334    XdmcpHeader	header;
1335    int socketfd = xdmcpSocket;
1336
1337    header.version = XDM_PROTOCOL_VERSION;
1338    header.opcode = (CARD16) MANAGE;
1339    header.length = 8 + DisplayClass.length;
1340
1341    if (!XdmcpWriteHeader (&buffer, &header))
1342	return;
1343    XdmcpWriteCARD32 (&buffer, SessionID);
1344    XdmcpWriteCARD16 (&buffer, DisplayNumber);
1345    XdmcpWriteARRAY8 (&buffer, &DisplayClass);
1346    state = XDM_AWAIT_MANAGE_RESPONSE;
1347#if defined(IPv6) && defined(AF_INET6)
1348    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
1349	socketfd = xdmcpSocket6;
1350#endif
1351    XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen);
1352}
1353
1354static void
1355recv_refuse_msg(unsigned length)
1356{
1357    CARD32  RefusedSessionID;
1358
1359    if (state != XDM_AWAIT_MANAGE_RESPONSE)
1360	return;
1361    if (length != 4)
1362	return;
1363    if (XdmcpReadCARD32 (&buffer, &RefusedSessionID))
1364    {
1365	if (RefusedSessionID == SessionID)
1366	{
1367    	    state = XDM_START_CONNECTION;
1368    	    send_packet();
1369	}
1370    }
1371}
1372
1373static void
1374recv_failed_msg(unsigned length)
1375{
1376    CARD32  FailedSessionID;
1377    ARRAY8  status;
1378
1379    if (state != XDM_AWAIT_MANAGE_RESPONSE)
1380	return;
1381    status.data = 0;
1382    if (XdmcpReadCARD32 (&buffer, &FailedSessionID) &&
1383	XdmcpReadARRAY8 (&buffer, &status))
1384    {
1385    	if (length == 6 + status.length &&
1386	    SessionID == FailedSessionID)
1387	{
1388	    XdmcpFatal ("Session failed", &status);
1389	}
1390    }
1391    XdmcpDisposeARRAY8 (&status);
1392}
1393
1394static void
1395send_keepalive_msg(void)
1396{
1397    XdmcpHeader	header;
1398    int socketfd = xdmcpSocket;
1399
1400    header.version = XDM_PROTOCOL_VERSION;
1401    header.opcode = (CARD16) KEEPALIVE;
1402    header.length = 6;
1403
1404    XdmcpWriteHeader (&buffer, &header);
1405    XdmcpWriteCARD16 (&buffer, DisplayNumber);
1406    XdmcpWriteCARD32 (&buffer, SessionID);
1407
1408    state = XDM_AWAIT_ALIVE_RESPONSE;
1409#if defined(IPv6) && defined(AF_INET6)
1410    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
1411	socketfd = xdmcpSocket6;
1412#endif
1413    XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen);
1414}
1415
1416static void
1417recv_alive_msg (unsigned length)
1418{
1419    CARD8   SessionRunning;
1420    CARD32  AliveSessionID;
1421
1422    if (state != XDM_AWAIT_ALIVE_RESPONSE)
1423	return;
1424    if (length != 5)
1425	return;
1426    if (XdmcpReadCARD8 (&buffer, &SessionRunning) &&
1427	XdmcpReadCARD32 (&buffer, &AliveSessionID))
1428    {
1429    	if (SessionRunning && AliveSessionID == SessionID)
1430    	{
1431	    /* backoff dormancy period */
1432	    state = XDM_RUN_SESSION;
1433	    if ((GetTimeInMillis() - lastDeviceEventTime.milliseconds) >
1434		keepaliveDormancy * 1000)
1435	    {
1436		keepaliveDormancy <<= 1;
1437		if (keepaliveDormancy > XDM_MAX_DORMANCY)
1438		    keepaliveDormancy = XDM_MAX_DORMANCY;
1439	    }
1440	    timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
1441    	}
1442	else
1443    	{
1444	    XdmcpDeadSession ("Alive response indicates session dead");
1445    	}
1446    }
1447}
1448
1449static  void
1450XdmcpFatal (
1451    const char	*type,
1452    ARRAY8Ptr	status)
1453{
1454    FatalError ("XDMCP fatal error: %s %*.*s\n", type,
1455	   status->length, status->length, status->data);
1456}
1457
1458static  void
1459XdmcpWarning(const char *str)
1460{
1461    ErrorF("XDMCP warning: %s\n", str);
1462}
1463
1464static void
1465get_addr_by_name(
1466    const char *argtype,
1467    const char *namestr,
1468    int		port,
1469    int		socktype,
1470    SOCKADDR_TYPE *addr,
1471    SOCKLEN_TYPE *addrlen
1472#if defined(IPv6) && defined(AF_INET6)
1473      ,
1474    struct addrinfo **aip,
1475    struct addrinfo **aifirstp
1476#endif
1477    )
1478{
1479#if defined(IPv6) && defined(AF_INET6)
1480    struct addrinfo *ai;
1481    struct addrinfo hints;
1482    char portstr[6];
1483    char *pport = portstr;
1484    int gaierr;
1485
1486    memset(&hints, 0, sizeof(hints));
1487    hints.ai_socktype = socktype;
1488
1489    if (port == 0) {
1490	pport = NULL;
1491    } else if (port > 0 && port < 65535) {
1492	sprintf(portstr, "%d", port);
1493    } else {
1494	FatalError("Xserver: port out of range: %d\n", port);
1495    }
1496
1497    if (*aifirstp != NULL) {
1498	freeaddrinfo(*aifirstp);
1499	*aifirstp = NULL;
1500    }
1501
1502    if ((gaierr = getaddrinfo(namestr, pport, &hints, aifirstp)) == 0) {
1503	for (ai = *aifirstp; ai != NULL; ai = ai->ai_next) {
1504	    if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6)
1505		break;
1506	}
1507	if ((ai == NULL) || (ai->ai_addrlen > sizeof(SOCKADDR_TYPE))) {
1508	    FatalError ("Xserver: %s host %s not on supported network type\n",
1509	      argtype, namestr);
1510	} else {
1511	    *aip = ai;
1512	    *addrlen = ai->ai_addrlen;
1513	    memcpy(addr, ai->ai_addr, ai->ai_addrlen);
1514	}
1515    } else {
1516	FatalError("Xserver: %s: %s %s\n", gai_strerror(gaierr), argtype, namestr);
1517    }
1518#else
1519    struct hostent *hep;
1520#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1521    _Xgethostbynameparams hparams;
1522#endif
1523#if defined(WIN32) && defined(TCPCONN)
1524    _XSERVTransWSAStartup();
1525#endif
1526    if (!(hep = _XGethostbyname(namestr, hparams)))
1527    {
1528	FatalError("Xserver: %s unknown host: %s\n", argtype, namestr);
1529    }
1530    if (hep->h_length == sizeof (struct in_addr))
1531    {
1532	memmove(&addr->sin_addr, hep->h_addr, hep->h_length);
1533	*addrlen = sizeof(struct sockaddr_in);
1534	addr->sin_family = AF_INET;
1535	addr->sin_port = htons (port);
1536    }
1537    else
1538    {
1539	FatalError("Xserver: %s host on strange network %s\n", argtype, namestr);
1540    }
1541#endif
1542}
1543
1544static void
1545get_manager_by_name(
1546    int	    argc,
1547    char    **argv,
1548    int	    i)
1549{
1550
1551    if ((i + 1) == argc)
1552    {
1553	FatalError("Xserver: missing %s host name in command line\n", argv[i]);
1554    }
1555
1556    get_addr_by_name(argv[i], argv[i+1], xdm_udp_port, SOCK_DGRAM,
1557      &ManagerAddress, &ManagerAddressLen
1558#if defined(IPv6) && defined(AF_INET6)
1559      , &mgrAddr, &mgrAddrFirst
1560#endif
1561	);
1562}
1563
1564
1565static void
1566get_fromaddr_by_name(
1567    int	    argc,
1568    char    **argv,
1569    int	    i)
1570{
1571#if defined(IPv6) && defined(AF_INET6)
1572    struct addrinfo *ai = NULL;
1573    struct addrinfo *aifirst = NULL;
1574#endif
1575    if (i == argc)
1576    {
1577	FatalError("Xserver: missing -from host name in command line\n");
1578    }
1579    get_addr_by_name("-from", argv[i], 0, 0, &FromAddress, &FromAddressLen
1580#if defined(IPv6) && defined(AF_INET6)
1581      , &ai, &aifirst
1582#endif
1583	);
1584#if defined(IPv6) && defined(AF_INET6)
1585    if (aifirst != NULL)
1586	freeaddrinfo(aifirst);
1587#endif
1588    xdm_from = argv[i];
1589}
1590
1591
1592#if defined(IPv6) && defined(AF_INET6)
1593static int
1594get_mcast_options(int argc, char **argv, int i)
1595{
1596    char *address = XDM_DEFAULT_MCAST_ADDR6;
1597    int hopcount = 1;
1598    struct addrinfo hints;
1599    char portstr[6];
1600    int gaierr;
1601    struct addrinfo *ai, *firstai;
1602
1603    if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) {
1604	address = argv[i++];
1605	if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) {
1606	    hopcount = strtol(argv[i++], NULL, 10);
1607	    if ((hopcount < 1) || (hopcount > 255)) {
1608		FatalError("Xserver: multicast hop count out of range: %d\n",
1609		  hopcount);
1610	    }
1611	}
1612    }
1613
1614    if (xdm_udp_port > 0 && xdm_udp_port < 65535) {
1615	sprintf(portstr, "%d", xdm_udp_port);
1616    } else {
1617	FatalError("Xserver: port out of range: %d\n", xdm_udp_port);
1618    }
1619    memset(&hints, 0, sizeof(hints));
1620    hints.ai_socktype = SOCK_DGRAM;
1621
1622    if ((gaierr = getaddrinfo(address, portstr, &hints, &firstai)) == 0) {
1623	for (ai = firstai; ai != NULL; ai = ai->ai_next) {
1624	    if (((ai->ai_family == AF_INET) &&
1625	      	IN_MULTICAST(((struct sockaddr_in *) ai->ai_addr)
1626							  ->sin_addr.s_addr))
1627		|| ((ai->ai_family == AF_INET6) &&
1628		  IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *) ai->ai_addr)
1629							    ->sin6_addr)))
1630		break;
1631	}
1632	if (ai == NULL) {
1633	    FatalError ("Xserver: address not supported multicast type %s\n",
1634	      address);
1635	} else {
1636	    struct multicastinfo	*mcastinfo, *mcl;
1637
1638	    mcastinfo = malloc(sizeof(struct multicastinfo));
1639	    mcastinfo->next = NULL;
1640	    mcastinfo->ai = firstai;
1641	    mcastinfo->hops = hopcount;
1642
1643	    if (mcastlist == NULL) {
1644		mcastlist = mcastinfo;
1645	    } else {
1646		for (mcl = mcastlist; mcl->next != NULL; mcl = mcl->next) {
1647		    /* Do nothing  - just find end of list */
1648		}
1649		mcl->next = mcastinfo;
1650	    }
1651	}
1652    } else {
1653	FatalError("Xserver: %s: %s\n", gai_strerror(gaierr), address);
1654    }
1655    return i;
1656}
1657#endif
1658
1659#else
1660static int xdmcp_non_empty; /* avoid complaint by ranlib */
1661#endif /* XDMCP */
1662