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