2 * Copyright 1989 Network Computing Devices, Inc., Mountain View, California.
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.
16 #ifdef HAVE_DIX_CONFIG_H
17 #include <dix-config.h>
21 #include <X11/Xwinsock.h>
27 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
38 #include <X11/Xpoll.h>
41 #include "dixstruct.h"
47 #include <netconfig.h>
58 #include <X11/Xdmcp.h>
60 #define X_INCLUDE_NETDB_H
61 #include <X11/Xos_r.h>
63 static const char *defaultDisplayClass = COMPILEDDISPLAYCLASS;
65 static int xdmcpSocket, sessionSocket;
66 static xdmcp_states state;
68 #if defined(IPv6) && defined(AF_INET6)
69 static int xdmcpSocket6;
70 static struct sockaddr_storage req_sockaddr;
72 static struct sockaddr_in req_sockaddr;
74 static int req_socklen;
75 static CARD32 SessionID;
76 static CARD32 timeOutTime;
77 static int timeOutRtx;
78 static CARD32 defaultKeepaliveDormancy = XDM_DEF_DORMANCY;
79 static CARD32 keepaliveDormancy = XDM_DEF_DORMANCY;
80 static CARD16 DisplayNumber;
81 static xdmcp_states XDM_INIT_STATE = XDM_OFF;
84 static char *xdmAuthCookie;
87 static XdmcpBuffer buffer;
89 #if defined(IPv6) && defined(AF_INET6)
91 static struct addrinfo *mgrAddr;
92 static struct addrinfo *mgrAddrFirst;
94 #define SOCKADDR_TYPE struct sockaddr_storage
95 #define SOCKADDR_FAMILY(s) ((struct sockaddr *)&(s))->sa_family
98 #define SOCKLEN_FIELD(s) ((struct sockaddr *)&(s))->sa_len
99 #define SOCKLEN_TYPE unsigned char
101 #define SOCKLEN_TYPE unsigned int
106 #define SOCKADDR_TYPE struct sockaddr_in
107 #define SOCKADDR_FAMILY(s) (s).sin_family
110 #define SOCKLEN_FIELD(s) (s).sin_len
111 #define SOCKLEN_TYPE unsigned char
113 #define SOCKLEN_TYPE size_t
118 static SOCKADDR_TYPE ManagerAddress;
119 static SOCKADDR_TYPE FromAddress;
122 #define ManagerAddressLen SOCKLEN_FIELD(ManagerAddress)
123 #define FromAddressLen SOCKLEN_FIELD(FromAddress)
125 static SOCKLEN_TYPE ManagerAddressLen, FromAddressLen;
128 #if defined(IPv6) && defined(AF_INET6)
129 static struct multicastinfo {
130 struct multicastinfo *next;
136 static void XdmcpAddHost(const struct sockaddr *from,
138 ARRAY8Ptr AuthenticationName,
139 ARRAY8Ptr hostname, ARRAY8Ptr status);
141 static void XdmcpSelectHost(const struct sockaddr *host_sockaddr,
142 int host_len, ARRAY8Ptr AuthenticationName);
144 static void get_xdmcp_sock(void);
146 static void send_query_msg(void);
148 static void recv_willing_msg(struct sockaddr * /*from */ ,
150 unsigned /*length */ );
152 static void send_request_msg(void);
154 static void recv_accept_msg(unsigned /*length */ );
156 static void recv_decline_msg(unsigned /*length */ );
158 static void send_manage_msg(void);
160 static void recv_refuse_msg(unsigned /*length */ );
162 static void recv_failed_msg(unsigned /*length */ );
164 static void send_keepalive_msg(void);
166 static void recv_alive_msg(unsigned /*length */ );
168 static void XdmcpFatal(const char * /*type */ ,
169 ARRAY8Ptr /*status */ );
171 static void XdmcpWarning(const char * /*str */ );
173 static void get_manager_by_name(int /*argc */ ,
177 static void get_fromaddr_by_name(int /*argc */ , char ** /*argv */ ,
180 #if defined(IPv6) && defined(AF_INET6)
181 static int get_mcast_options(int /*argc */ , char ** /*argv */ , int /*i */ );
184 static void receive_packet(int /*socketfd */ );
186 static void send_packet(void);
188 static void timeout(void);
190 static void restart(void);
192 static void XdmcpBlockHandler(pointer /*data */ ,
193 struct timeval ** /*wt */ ,
194 pointer /*LastSelectMask */ );
196 static void XdmcpWakeupHandler(pointer /*data */ ,
198 pointer /*LastSelectMask */ );
201 * Register the Manufacturer display ID
204 static ARRAY8 ManufacturerDisplayID;
207 XdmcpRegisterManufacturerDisplayID(const char *name, int length)
211 XdmcpDisposeARRAY8(&ManufacturerDisplayID);
212 if (!XdmcpAllocARRAY8(&ManufacturerDisplayID, length))
214 for (i = 0; i < length; i++)
215 ManufacturerDisplayID.data[i] = (CARD8) name[i];
218 static unsigned short xdm_udp_port = XDM_UDP_PORT;
219 static Bool OneSession = FALSE;
220 static const char *xdm_from = NULL;
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");
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");
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");
237 ErrorF("-cookie xdm-auth-bits specify the magic cookie for XDMCP\n");
239 ErrorF("-displayID display-id manufacturer display ID for request\n");
243 XdmcpOptions(int argc, char **argv, int i)
245 if (strcmp(argv[i], "-query") == 0) {
246 get_manager_by_name(argc, argv, i++);
247 XDM_INIT_STATE = XDM_QUERY;
251 if (strcmp(argv[i], "-broadcast") == 0) {
252 XDM_INIT_STATE = XDM_BROADCAST;
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;
264 if (strcmp(argv[i], "-indirect") == 0) {
265 get_manager_by_name(argc, argv, i++);
266 XDM_INIT_STATE = XDM_INDIRECT;
270 if (strcmp(argv[i], "-port") == 0) {
272 FatalError("Xserver: missing port number in command line\n");
274 xdm_udp_port = (unsigned short) atoi(argv[i]);
277 if (strcmp(argv[i], "-from") == 0) {
278 get_fromaddr_by_name(argc, argv, ++i);
281 if (strcmp(argv[i], "-once") == 0) {
285 if (strcmp(argv[i], "-class") == 0) {
287 FatalError("Xserver: missing class name in command line\n");
289 defaultDisplayClass = argv[i];
293 if (strcmp(argv[i], "-cookie") == 0) {
295 FatalError("Xserver: missing cookie data in command line\n");
297 xdmAuthCookie = argv[i];
301 if (strcmp(argv[i], "-displayID") == 0) {
303 FatalError("Xserver: missing displayID in command line\n");
305 XdmcpRegisterManufacturerDisplayID(argv[i], strlen(argv[i]));
312 * This section is a collection of routines for
313 * registering server-specific data with the XDMCP
318 * Save all broadcast addresses away so BroadcastQuery
319 * packets get sent everywhere
322 #define MAX_BROADCAST 10
324 /* This stays sockaddr_in since IPv6 doesn't support broadcast */
325 static struct sockaddr_in BroadcastAddresses[MAX_BROADCAST];
326 static int NumBroadcastAddresses;
329 XdmcpRegisterBroadcastAddress(const struct sockaddr_in *addr)
331 struct sockaddr_in *bcast;
333 if (NumBroadcastAddresses >= MAX_BROADCAST)
335 bcast = &BroadcastAddresses[NumBroadcastAddresses++];
336 memset(bcast, 0, sizeof(struct sockaddr_in));
338 bcast->sin_len = addr->sin_len;
340 bcast->sin_family = addr->sin_family;
341 bcast->sin_port = htons(xdm_udp_port);
342 bcast->sin_addr = addr->sin_addr;
346 * Each authentication type is registered here; Validator
347 * will be called to check all access attempts using
348 * the specified authentication type
351 static ARRAYofARRAY8 AuthenticationNames, AuthenticationDatas;
352 typedef struct _AuthenticationFuncs {
353 ValidatorFunc Validator;
354 GeneratorFunc Generator;
355 AddAuthorFunc AddAuth;
356 } AuthenticationFuncsRec, *AuthenticationFuncsPtr;
358 static AuthenticationFuncsPtr AuthenticationFuncsList;
361 XdmcpRegisterAuthentication(const char *name,
365 ValidatorFunc Validator,
366 GeneratorFunc Generator, AddAuthorFunc AddAuth)
369 ARRAY8 AuthenticationName, AuthenticationData;
370 static AuthenticationFuncsPtr newFuncs;
372 if (!XdmcpAllocARRAY8(&AuthenticationName, namelen))
374 if (!XdmcpAllocARRAY8(&AuthenticationData, datalen)) {
375 XdmcpDisposeARRAY8(&AuthenticationName);
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) &&
387 malloc((AuthenticationNames.length +
388 1) * sizeof(AuthenticationFuncsRec))))) {
389 XdmcpDisposeARRAY8(&AuthenticationName);
390 XdmcpDisposeARRAY8(&AuthenticationData);
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] =
402 AuthenticationDatas.data[AuthenticationDatas.length - 1] =
407 * Select the authentication type to be used; this is
408 * set by the manager of the host to be connected to.
411 static ARRAY8 noAuthenticationName = { (CARD16) 0, (CARD8Ptr) 0 };
412 static ARRAY8 noAuthenticationData = { (CARD16) 0, (CARD8Ptr) 0 };
414 static ARRAY8Ptr AuthenticationName = &noAuthenticationName;
415 static ARRAY8Ptr AuthenticationData = &noAuthenticationData;
416 static AuthenticationFuncsPtr AuthenticationFuncs;
419 XdmcpSetAuthentication(const ARRAY8Ptr name)
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];
433 * Register the host address for the display
436 static ARRAY16 ConnectionTypes;
437 static ARRAYofARRAY8 ConnectionAddresses;
438 static long xdmcpGeneration;
441 XdmcpRegisterConnection(int type, const char *address, int addrlen)
446 if (xdmcpGeneration != serverGeneration) {
447 XdmcpDisposeARRAY16(&ConnectionTypes);
448 XdmcpDisposeARRAYofARRAY8(&ConnectionAddresses);
449 xdmcpGeneration = serverGeneration;
451 if (xdm_from != NULL) { /* Only register the requested address */
452 const void *regAddr = address;
453 const void *fromAddr = NULL;
454 int regAddrlen = addrlen;
456 if (addrlen == sizeof(struct in_addr)) {
457 if (SOCKADDR_FAMILY(FromAddress) == AF_INET) {
458 fromAddr = &((struct sockaddr_in *) &FromAddress)->sin_addr;
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)) {
466 &((struct sockaddr_in6 *) &FromAddress)->sin6_addr.
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;
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;
480 &((struct sockaddr_in6 *) &address)->sin6_addr.s6_addr[12];
481 regAddrlen = sizeof(struct in_addr);
485 if (!fromAddr || memcmp(regAddr, fromAddr, regAddrlen) != 0) {
489 if (ConnectionAddresses.length + 1 == 256)
491 newAddress = malloc(addrlen * sizeof(CARD8));
494 if (!XdmcpReallocARRAY16(&ConnectionTypes, ConnectionTypes.length + 1)) {
498 if (!XdmcpReallocARRAYofARRAY8(&ConnectionAddresses,
499 ConnectionAddresses.length + 1)) {
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;
511 * Register an Authorization Name. XDMCP advertises this list
515 static ARRAYofARRAY8 AuthorizationNames;
518 XdmcpRegisterAuthorizations(void)
520 XdmcpDisposeARRAYofARRAY8(&AuthorizationNames);
521 RegisterAuthorizations();
525 XdmcpRegisterAuthorization(const char *name, int namelen)
530 authName.data = malloc(namelen * sizeof(CARD8));
533 if (!XdmcpReallocARRAYofARRAY8
534 (&AuthorizationNames, AuthorizationNames.length + 1)) {
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;
545 * Register the DisplayClass string
548 static ARRAY8 DisplayClass;
551 XdmcpRegisterDisplayClass(const char *name, int length)
555 XdmcpDisposeARRAY8(&DisplayClass);
556 if (!XdmcpAllocARRAY8(&DisplayClass, length))
558 for (i = 0; i < length; i++)
559 DisplayClass.data[i] = (CARD8) name[i];
563 * initialize XDMCP; create the socket, compute the display
564 * number, set up the state machine
570 state = XDM_INIT_STATE;
573 XdmAuthenticationInit(xdmAuthCookie, strlen(xdmAuthCookie));
575 if (state != XDM_OFF) {
576 XdmcpRegisterAuthorizations();
577 XdmcpRegisterDisplayClass(defaultDisplayClass,
578 strlen(defaultDisplayClass));
580 RegisterBlockAndWakeupHandlers(XdmcpBlockHandler, XdmcpWakeupHandler,
583 DisplayNumber = (CARD16) atoi(display);
592 state = XDM_INIT_STATE;
593 if (state != XDM_OFF) {
594 RegisterBlockAndWakeupHandlers(XdmcpBlockHandler, XdmcpWakeupHandler,
602 * Called whenever a new connection is created; notices the
603 * first connection and saves it to terminate the session
608 XdmcpOpenDisplay(int sock)
610 if (state != XDM_AWAIT_MANAGE_RESPONSE)
612 state = XDM_RUN_SESSION;
613 sessionSocket = sock;
617 XdmcpCloseDisplay(int sock)
619 if ((state != XDM_RUN_SESSION && state != XDM_AWAIT_ALIVE_RESPONSE)
620 || sessionSocket != sock)
622 state = XDM_INIT_STATE;
624 dispatchException |= DE_TERMINATE;
626 dispatchException |= DE_RESET;
627 isItTimeToYield = TRUE;
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
637 /*ARGSUSED*/ static void
638 XdmcpBlockHandler(pointer data, /* unused */
639 struct timeval **wt, pointer pReadmask)
641 fd_set *LastSelectMask = (fd_set *) pReadmask;
644 if (state == XDM_OFF)
646 FD_SET(xdmcpSocket, LastSelectMask);
647 #if defined(IPv6) && defined(AF_INET6)
648 if (xdmcpSocket6 >= 0)
649 FD_SET(xdmcpSocket6, LastSelectMask);
651 if (timeOutTime == 0)
653 millisToGo = timeOutTime - GetTimeInMillis();
654 if ((int) millisToGo < 0)
656 AdjustWaitForDelay(wt, millisToGo);
660 * called after select returns; this routine will
661 * recognise when XDMCP packets await and
662 * process them appropriately
665 /*ARGSUSED*/ static void
666 XdmcpWakeupHandler(pointer data, /* unused */
667 int i, pointer pReadmask)
669 fd_set *LastSelectMask = (fd_set *) pReadmask;
670 fd_set devicesReadable;
672 if (state == XDM_OFF)
675 if (FD_ISSET(xdmcpSocket, LastSelectMask)) {
676 receive_packet(xdmcpSocket);
677 FD_CLR(xdmcpSocket, LastSelectMask);
679 #if defined(IPv6) && defined(AF_INET6)
680 if (xdmcpSocket6 >= 0 && FD_ISSET(xdmcpSocket6, LastSelectMask)) {
681 receive_packet(xdmcpSocket6);
682 FD_CLR(xdmcpSocket6, LastSelectMask);
685 XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices);
686 if (XFD_ANYSET(&devicesReadable)) {
687 if (state == XDM_AWAIT_USER_INPUT)
689 else if (state == XDM_RUN_SESSION)
690 keepaliveDormancy = defaultKeepaliveDormancy;
692 if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION)
693 timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
695 else if (timeOutTime && (int) (GetTimeInMillis() - timeOutTime) >= 0) {
696 if (state == XDM_RUN_SESSION) {
697 state = XDM_KEEPALIVE;
706 * This routine should be called from the routine that drives the
707 * user's host menu when the user selects a host
711 XdmcpSelectHost(const struct sockaddr *host_sockaddr,
712 int host_len, ARRAY8Ptr AuthenticationName)
714 state = XDM_START_CONNECTION;
715 memmove(&req_sockaddr, host_sockaddr, host_len);
716 req_socklen = host_len;
717 XdmcpSetAuthentication(AuthenticationName);
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.
727 /*ARGSUSED*/ static void
728 XdmcpAddHost(const struct sockaddr *from,
730 ARRAY8Ptr AuthenticationName, ARRAY8Ptr hostname, ARRAY8Ptr status)
732 XdmcpSelectHost(from, fromlen, AuthenticationName);
736 * A message is queued on the socket; read it and
737 * do the appropriate thing
740 static ARRAY8 UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" };
743 receive_packet(int socketfd)
745 #if defined(IPv6) && defined(AF_INET6)
746 struct sockaddr_storage from;
748 struct sockaddr_in from;
750 int fromlen = sizeof(from);
753 /* read message off socket */
754 if (!XdmcpFill(socketfd, &buffer, (XdmcpNetaddr) & from, &fromlen))
757 /* reset retransmission backoff */
760 if (!XdmcpReadHeader(&buffer, &header))
763 if (header.version != XDM_PROTOCOL_VERSION)
766 switch (header.opcode) {
768 recv_willing_msg((struct sockaddr *) &from, fromlen, header.length);
771 XdmcpFatal("Manager unwilling", &UnwillingMessage);
774 recv_accept_msg(header.length);
777 recv_decline_msg(header.length);
780 recv_refuse_msg(header.length);
783 recv_failed_msg(header.length);
786 recv_alive_msg(header.length);
792 * send the appropriate message given the current state
804 #if defined(IPv6) && defined(AF_INET6)
809 case XDM_START_CONNECTION:
816 send_keepalive_msg();
821 rtx = (XDM_MIN_RTX << timeOutRtx);
822 if (rtx > XDM_MAX_RTX)
824 timeOutTime = GetTimeInMillis() + rtx * 1000;
828 * The session is declared dead for some reason; too many
829 * timeouts, or Keepalive failure.
833 XdmcpDeadSession(const char *reason)
835 ErrorF("XDM: %s, declaring session dead\n", reason);
836 state = XDM_INIT_STATE;
837 isItTimeToYield = TRUE;
838 dispatchException |= DE_RESET;
845 * Timeout waiting for an XDMCP response.
852 if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT) {
853 XdmcpDeadSession("too many keepalive retransmissions");
856 else if (timeOutRtx >= XDM_RTX_LIMIT) {
857 /* Quit if "-once" specified, otherwise reset and try again. */
859 dispatchException |= DE_TERMINATE;
860 ErrorF("XDM: too many retransmissions\n");
863 XdmcpDeadSession("too many retransmissions");
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;
875 if (mgrAddr->ai_family == AF_INET || mgrAddr->ai_family == AF_INET6)
879 ManagerAddressLen = mgrAddr->ai_addrlen;
881 memcpy(&ManagerAddress, mgrAddr->ai_addr, mgrAddr->ai_addrlen);
886 case XDM_COLLECT_QUERY:
889 case XDM_COLLECT_BROADCAST_QUERY:
890 state = XDM_BROADCAST;
892 #if defined(IPv6) && defined(AF_INET6)
893 case XDM_COLLECT_MULTICAST_QUERY:
894 state = XDM_MULTICAST;
897 case XDM_COLLECT_INDIRECT_QUERY:
898 state = XDM_INDIRECT;
900 case XDM_AWAIT_REQUEST_RESPONSE:
901 state = XDM_START_CONNECTION;
903 case XDM_AWAIT_MANAGE_RESPONSE:
906 case XDM_AWAIT_ALIVE_RESPONSE:
907 state = XDM_KEEPALIVE;
918 state = XDM_INIT_STATE;
924 XdmcpCheckAuthentication(ARRAY8Ptr Name, ARRAY8Ptr Data, int packet_type)
926 return (XdmcpARRAY8Equal(Name, AuthenticationName) &&
927 (AuthenticationName->length == 0 ||
928 (*AuthenticationFuncs->Validator) (AuthenticationData, Data,
933 XdmcpAddAuthorization(ARRAY8Ptr name, ARRAY8Ptr data)
935 AddAuthorFunc AddAuth;
937 if (AuthenticationFuncs && AuthenticationFuncs->AddAuth)
938 AddAuth = AuthenticationFuncs->AddAuth;
940 AddAuth = AddAuthorization;
941 return (*AddAuth) ((unsigned short) name->length,
943 (unsigned short) data->length, (char *) data->data);
947 * from here to the end of this file are routines private
948 * to the state machine.
955 struct netconfig *nconf;
957 if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) {
958 XdmcpWarning("t_open() of /dev/udp failed");
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);
970 * This part of the code looks contrived. It will actually fit in nicely
971 * when the CLTS part of Xtrans is implemented.
974 if ((nconf = getnetconfigent("udp")) == NULL) {
975 XdmcpWarning("UDP socket creation failed: getnetconfigent()");
976 t_unbind(xdmcpSocket);
977 t_close(xdmcpSocket);
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);
989 freenetconfigent(nconf);
993 #if defined(IPv6) && defined(AF_INET6)
994 if ((xdmcpSocket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
995 XdmcpWarning("INET6 UDP socket creation failed");
997 if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
998 XdmcpWarning("UDP socket creation failed");
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",
1011 #endif /* STREAMSCONN */
1015 send_query_msg(void)
1018 Bool broadcast = FALSE;
1020 #if defined(IPv6) && defined(AF_INET6)
1021 Bool multicast = FALSE;
1024 int socketfd = xdmcpSocket;
1026 header.version = XDM_PROTOCOL_VERSION;
1029 header.opcode = (CARD16) QUERY;
1030 state = XDM_COLLECT_QUERY;
1033 header.opcode = (CARD16) BROADCAST_QUERY;
1034 state = XDM_COLLECT_BROADCAST_QUERY;
1037 #if defined(IPv6) && defined(AF_INET6)
1039 header.opcode = (CARD16) BROADCAST_QUERY;
1040 state = XDM_COLLECT_MULTICAST_QUERY;
1045 header.opcode = (CARD16) INDIRECT_QUERY;
1046 state = XDM_COLLECT_INDIRECT_QUERY;
1052 for (i = 0; i < AuthenticationNames.length; i++)
1053 header.length += 2 + AuthenticationNames.data[i].length;
1055 XdmcpWriteHeader(&buffer, &header);
1056 XdmcpWriteARRAYofARRAY8(&buffer, &AuthenticationNames);
1060 for (i = 0; i < NumBroadcastAddresses; i++)
1061 XdmcpFlush(xdmcpSocket, &buffer,
1062 (XdmcpNetaddr) & BroadcastAddresses[i],
1063 sizeof(struct sockaddr_in));
1065 #if defined(IPv6) && defined(AF_INET6)
1066 else if (multicast) {
1067 struct multicastinfo *mcl;
1068 struct addrinfo *ai;
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;
1075 socketfd = xdmcpSocket;
1076 setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL,
1077 &hopflag, sizeof(hopflag));
1079 else if (ai->ai_family == AF_INET6) {
1080 int hopflag6 = mcl->hops;
1082 socketfd = xdmcpSocket6;
1083 setsockopt(socketfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
1084 &hopflag6, sizeof(hopflag6));
1089 XdmcpFlush(socketfd, &buffer,
1090 (XdmcpNetaddr) ai->ai_addr, ai->ai_addrlen);
1097 #if defined(IPv6) && defined(AF_INET6)
1098 if (SOCKADDR_FAMILY(ManagerAddress) == AF_INET6)
1099 socketfd = xdmcpSocket6;
1101 XdmcpFlush(socketfd, &buffer, (XdmcpNetaddr) & ManagerAddress,
1107 recv_willing_msg(struct sockaddr *from, int fromlen, unsigned length)
1109 ARRAY8 authenticationName;
1113 authenticationName.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) {
1122 case XDM_COLLECT_QUERY:
1123 XdmcpSelectHost(from, fromlen, &authenticationName);
1125 case XDM_COLLECT_BROADCAST_QUERY:
1126 #if defined(IPv6) && defined(AF_INET6)
1127 case XDM_COLLECT_MULTICAST_QUERY:
1129 case XDM_COLLECT_INDIRECT_QUERY:
1130 XdmcpAddHost(from, fromlen, &authenticationName, &hostname,
1138 XdmcpDisposeARRAY8(&authenticationName);
1139 XdmcpDisposeARRAY8(&hostname);
1140 XdmcpDisposeARRAY8(&status);
1144 send_request_msg(void)
1149 CARD16 XdmcpConnectionType;
1150 ARRAY8 authenticationData;
1151 int socketfd = xdmcpSocket;
1153 switch (SOCKADDR_FAMILY(ManagerAddress)) {
1155 XdmcpConnectionType = FamilyInternet;
1157 #if defined(IPv6) && defined(AF_INET6)
1159 XdmcpConnectionType = FamilyInternet6;
1163 XdmcpConnectionType = 0xffff;
1167 header.version = XDM_PROTOCOL_VERSION;
1168 header.opcode = (CARD16) REQUEST;
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);
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;
1189 if (!XdmcpWriteHeader(&buffer, &header)) {
1190 XdmcpDisposeARRAY8(&authenticationData);
1193 XdmcpWriteCARD16(&buffer, DisplayNumber);
1194 XdmcpWriteCARD8(&buffer, ConnectionTypes.length);
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]);
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]);
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;
1225 if (XdmcpFlush(socketfd, &buffer,
1226 (XdmcpNetaddr) & req_sockaddr, req_socklen))
1227 state = XDM_AWAIT_REQUEST_RESPONSE;
1231 recv_accept_msg(unsigned length)
1233 CARD32 AcceptSessionID;
1234 ARRAY8 AcceptAuthenticationName, AcceptAuthenticationData;
1235 ARRAY8 AcceptAuthorizationName, AcceptAuthorizationData;
1237 if (state != XDM_AWAIT_REQUEST_RESPONSE)
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);
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
1260 if (!XdmcpAddAuthorization(&AcceptAuthorizationName,
1261 &AcceptAuthorizationData)) {
1264 SessionID = AcceptSessionID;
1269 XdmcpDisposeARRAY8(&AcceptAuthenticationName);
1270 XdmcpDisposeARRAY8(&AcceptAuthenticationData);
1271 XdmcpDisposeARRAY8(&AcceptAuthorizationName);
1272 XdmcpDisposeARRAY8(&AcceptAuthorizationData);
1276 recv_decline_msg(unsigned length)
1278 ARRAY8 status, DeclineAuthenticationName, DeclineAuthenticationData;
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);
1294 XdmcpDisposeARRAY8(&status);
1295 XdmcpDisposeARRAY8(&DeclineAuthenticationName);
1296 XdmcpDisposeARRAY8(&DeclineAuthenticationData);
1300 send_manage_msg(void)
1303 int socketfd = xdmcpSocket;
1305 header.version = XDM_PROTOCOL_VERSION;
1306 header.opcode = (CARD16) MANAGE;
1307 header.length = 8 + DisplayClass.length;
1309 if (!XdmcpWriteHeader(&buffer, &header))
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;
1319 XdmcpFlush(socketfd, &buffer, (XdmcpNetaddr) & req_sockaddr, req_socklen);
1323 recv_refuse_msg(unsigned length)
1325 CARD32 RefusedSessionID;
1327 if (state != XDM_AWAIT_MANAGE_RESPONSE)
1331 if (XdmcpReadCARD32(&buffer, &RefusedSessionID)) {
1332 if (RefusedSessionID == SessionID) {
1333 state = XDM_START_CONNECTION;
1340 recv_failed_msg(unsigned length)
1342 CARD32 FailedSessionID;
1345 if (state != XDM_AWAIT_MANAGE_RESPONSE)
1348 if (XdmcpReadCARD32(&buffer, &FailedSessionID) &&
1349 XdmcpReadARRAY8(&buffer, &status)) {
1350 if (length == 6 + status.length && SessionID == FailedSessionID) {
1351 XdmcpFatal("Session failed", &status);
1354 XdmcpDisposeARRAY8(&status);
1358 send_keepalive_msg(void)
1361 int socketfd = xdmcpSocket;
1363 header.version = XDM_PROTOCOL_VERSION;
1364 header.opcode = (CARD16) KEEPALIVE;
1367 XdmcpWriteHeader(&buffer, &header);
1368 XdmcpWriteCARD16(&buffer, DisplayNumber);
1369 XdmcpWriteCARD32(&buffer, SessionID);
1371 state = XDM_AWAIT_ALIVE_RESPONSE;
1372 #if defined(IPv6) && defined(AF_INET6)
1373 if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
1374 socketfd = xdmcpSocket6;
1376 XdmcpFlush(socketfd, &buffer, (XdmcpNetaddr) & req_sockaddr, req_socklen);
1380 recv_alive_msg(unsigned length)
1382 CARD8 SessionRunning;
1383 CARD32 AliveSessionID;
1385 if (state != XDM_AWAIT_ALIVE_RESPONSE)
1389 if (XdmcpReadCARD8(&buffer, &SessionRunning) &&
1390 XdmcpReadCARD32(&buffer, &AliveSessionID)) {
1391 if (SessionRunning && AliveSessionID == SessionID) {
1392 /* backoff dormancy period */
1393 state = XDM_RUN_SESSION;
1394 if ((GetTimeInMillis() - lastDeviceEventTime[XIAllDevices].milliseconds) >
1395 keepaliveDormancy * 1000) {
1396 keepaliveDormancy <<= 1;
1397 if (keepaliveDormancy > XDM_MAX_DORMANCY)
1398 keepaliveDormancy = XDM_MAX_DORMANCY;
1400 timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
1403 XdmcpDeadSession("Alive response indicates session dead");
1409 XdmcpFatal(const char *type, ARRAY8Ptr status)
1411 FatalError("XDMCP fatal error: %s %*.*s\n", type,
1412 status->length, status->length, status->data);
1416 XdmcpWarning(const char *str)
1418 ErrorF("XDMCP warning: %s\n", str);
1422 get_addr_by_name(const char *argtype,
1423 const char *namestr,
1425 int socktype, SOCKADDR_TYPE * addr, SOCKLEN_TYPE * addrlen
1426 #if defined(IPv6) && defined(AF_INET6)
1427 , struct addrinfo **aip, struct addrinfo **aifirstp
1431 #if defined(IPv6) && defined(AF_INET6)
1432 struct addrinfo *ai;
1433 struct addrinfo hints;
1435 char *pport = portstr;
1438 memset(&hints, 0, sizeof(hints));
1439 hints.ai_socktype = socktype;
1444 else if (port > 0 && port < 65535) {
1445 snprintf(portstr, sizeof(portstr), "%d", port);
1448 FatalError("Xserver: port out of range: %d\n", port);
1451 if (*aifirstp != NULL) {
1452 freeaddrinfo(*aifirstp);
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)
1461 if ((ai == NULL) || (ai->ai_addrlen > sizeof(SOCKADDR_TYPE))) {
1462 FatalError("Xserver: %s host %s not on supported network type\n",
1467 *addrlen = ai->ai_addrlen;
1468 memcpy(addr, ai->ai_addr, ai->ai_addrlen);
1472 FatalError("Xserver: %s: %s %s\n", gai_strerror(gaierr), argtype,
1476 struct hostent *hep;
1478 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1479 _Xgethostbynameparams hparams;
1481 #if defined(WIN32) && defined(TCPCONN)
1482 _XSERVTransWSAStartup();
1484 if (!(hep = _XGethostbyname(namestr, hparams))) {
1485 FatalError("Xserver: %s unknown host: %s\n", argtype, namestr);
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);
1494 FatalError("Xserver: %s host on strange network %s\n", argtype,
1501 get_manager_by_name(int argc, char **argv, int i)
1504 if ((i + 1) == argc) {
1505 FatalError("Xserver: missing %s host name in command line\n", argv[i]);
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
1517 get_fromaddr_by_name(int argc, char **argv, int i)
1519 #if defined(IPv6) && defined(AF_INET6)
1520 struct addrinfo *ai = NULL;
1521 struct addrinfo *aifirst = NULL;
1524 FatalError("Xserver: missing -from host name in command line\n");
1526 get_addr_by_name("-from", argv[i], 0, 0, &FromAddress, &FromAddressLen
1527 #if defined(IPv6) && defined(AF_INET6)
1531 #if defined(IPv6) && defined(AF_INET6)
1532 if (aifirst != NULL)
1533 freeaddrinfo(aifirst);
1538 #if defined(IPv6) && defined(AF_INET6)
1540 get_mcast_options(int argc, char **argv, int i)
1542 const char *address = XDM_DEFAULT_MCAST_ADDR6;
1544 struct addrinfo hints;
1547 struct addrinfo *ai, *firstai;
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",
1560 if (xdm_udp_port > 0 && xdm_udp_port < 65535) {
1561 snprintf(portstr, sizeof(portstr), "%d", xdm_udp_port);
1564 FatalError("Xserver: port out of range: %d\n", xdm_udp_port);
1566 memset(&hints, 0, sizeof(hints));
1567 hints.ai_socktype = SOCK_DGRAM;
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)
1574 || ((ai->ai_family == AF_INET6) &&
1575 IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *) ai->ai_addr)
1580 FatalError("Xserver: address not supported multicast type %s\n",
1584 struct multicastinfo *mcastinfo, *mcl;
1586 mcastinfo = malloc(sizeof(struct multicastinfo));
1587 mcastinfo->next = NULL;
1588 mcastinfo->ai = firstai;
1589 mcastinfo->hops = hopcount;
1591 if (mcastlist == NULL) {
1592 mcastlist = mcastinfo;
1595 for (mcl = mcastlist; mcl->next != NULL; mcl = mcl->next) {
1596 /* Do nothing - just find end of list */
1598 mcl->next = mcastinfo;
1603 FatalError("Xserver: %s: %s\n", gai_strerror(gaierr), address);
1610 static int xdmcp_non_empty; /* avoid complaint by ranlib */