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