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