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