]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/os/xdmcp.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / os / xdmcp.c
1 /* $XConsortium: xdmcp.c /main/34 1996/12/02 10:23:29 lehors $ */
2 /* $XFree86: xc/programs/Xserver/os/xdmcp.c,v 3.9 1997/01/18 06:58:04 dawes Exp $ */
3 /*
4  * Copyright 1989 Network Computing Devices, Inc., Mountain View, California.
5  *
6  * Permission to use, copy, modify, and distribute this software and its
7  * documentation for any purpose and without fee is hereby granted, provided
8  * that the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of N.C.D. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  N.C.D. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  */
17
18 #ifdef WIN32
19 /* avoid conflicting definitions */
20 #define BOOL wBOOL
21 #define ATOM wATOM
22 #define FreeResource wFreeResource
23 #include <winsock.h>
24 #undef BOOL
25 #undef ATOM
26 #undef FreeResource
27 #undef CreateWindowA
28 #undef RT_FONT
29 #undef RT_CURSOR
30 #endif
31 #include "Xos.h"
32 #if !defined(MINIX) && !defined(WIN32)
33 #ifndef Lynx
34 #include <sys/param.h>
35 #include <sys/socket.h>
36 #else
37 #include <socket.h>
38 #endif
39 #include <netinet/in.h>
40 #include <netdb.h>
41 #else
42 #if defined(MINIX)
43 #include <net/hton.h>
44 #include <net/netlib.h>
45 #include <net/gen/netdb.h>
46 #include <net/gen/udp.h>
47 #include <net/gen/udp_io.h>
48 #include <sys/nbio.h>
49 #include <sys/ioctl.h>
50 #endif
51 #endif
52 #include <stdio.h>
53 #include "X.h"
54 #include "Xmd.h"
55 #include "misc.h"
56 #include "Xpoll.h"
57 #include "osdep.h"
58 #include "input.h"
59 #include "dixstruct.h"
60 #include "opaque.h"
61
62 #ifdef STREAMSCONN
63 #include <tiuser.h>
64 #include <netconfig.h>
65 #include <netdir.h>
66 #endif
67
68 #ifdef XDMCP
69 #undef REQUEST
70 #include "Xdmcp.h"
71
72 extern char *display;
73 extern fd_set EnabledDevices;
74 extern fd_set AllClients;
75 extern char *defaultDisplayClass;
76
77 static int                  xdmcpSocket, sessionSocket;
78 static xdmcp_states         state;
79 static struct sockaddr_in   req_sockaddr;
80 static int                  req_socklen;
81 static CARD32               SessionID;
82 static CARD32               timeOutTime;
83 static int                  timeOutRtx;
84 static CARD32               defaultKeepaliveDormancy = XDM_DEF_DORMANCY;
85 static CARD32               keepaliveDormancy = XDM_DEF_DORMANCY;
86 static CARD16               DisplayNumber;
87 static xdmcp_states         XDM_INIT_STATE = XDM_OFF;
88 #ifdef HASXDMAUTH
89 static char                 *xdmAuthCookie;
90 #endif
91
92 static XdmcpBuffer          buffer;
93
94 static struct sockaddr_in   ManagerAddress;
95
96 static void get_xdmcp_sock(
97 #if NeedFunctionPrototypes
98     void
99 #endif
100 );
101
102 static void send_query_msg(
103 #if NeedFunctionPrototypes
104     void
105 #endif
106 );
107
108 static void recv_willing_msg(
109 #if NeedFunctionPrototypes
110     struct sockaddr_in */*from*/,
111     int /*fromlen*/,
112     unsigned /*length*/
113 #endif
114 );
115
116 static void send_request_msg(
117 #if NeedFunctionPrototypes
118     void
119 #endif
120 );
121
122 static void recv_accept_msg(
123 #if NeedFunctionPrototypes
124     unsigned /*length*/
125 #endif
126 );
127
128 static void recv_decline_msg(
129 #if NeedFunctionPrototypes
130     unsigned /*length*/
131 #endif
132 );
133
134 static void send_manage_msg(
135 #if NeedFunctionPrototypes
136     void
137 #endif
138 );
139
140 static void recv_refuse_msg(
141 #if NeedFunctionPrototypes
142     unsigned /*length*/
143 #endif
144 );
145
146 static void recv_failed_msg(
147 #if NeedFunctionPrototypes
148     unsigned /*length*/
149 #endif
150 );
151
152 static void send_keepalive_msg(
153 #if NeedFunctionPrototypes
154     void
155 #endif
156 );
157
158 static void recv_alive_msg(
159 #if NeedFunctionPrototypes
160     unsigned /*length*/
161 #endif
162 );
163
164 static XdmcpFatal(
165 #if NeedFunctionPrototypes
166     char */*type*/,
167     ARRAY8Ptr /*status*/
168 #endif
169 );
170
171 static XdmcpWarning(
172 #if NeedFunctionPrototypes
173     char */*str*/
174 #endif
175 );
176
177 static get_manager_by_name(
178 #if NeedFunctionPrototypes
179     int /*argc*/,
180     char **/*argv*/,
181     int /*i*/
182 #endif
183 );
184
185 static void receive_packet(
186 #if NeedFunctionPrototypes
187     void
188 #endif
189 );
190
191 static send_packet(
192 #if NeedFunctionPrototypes
193     void
194 #endif
195 );
196
197 extern int XdmcpDeadSession(
198 #if NeedFunctionPrototypes
199     char */*reason*/
200 #endif
201 );
202
203 static void timeout(
204 #if NeedFunctionPrototypes
205     void
206 #endif
207 );
208
209 static restart(
210 #if NeedFunctionPrototypes
211     void
212 #endif
213 );
214
215 static void XdmcpBlockHandler(
216 #if NeedFunctionPrototypes
217     pointer /*data*/,
218     struct timeval **/*wt*/,
219     pointer /*LastSelectMask*/
220 #endif
221 );
222
223 static void XdmcpWakeupHandler(
224 #if NeedFunctionPrototypes
225     pointer /*data*/,
226     int /*i*/,
227     pointer /*LastSelectMask*/
228 #endif
229 );
230
231 void XdmcpRegisterManufacturerDisplayID(
232 #if NeedFunctionPrototypes
233     char    * /*name*/,
234     int     /*length*/
235 #endif
236 );
237
238 #ifdef MINIX
239 static void read_cb(
240 #if NeedFunctionPrototypes
241     nbio_ref_t  /*ref*/,
242     int         /*res*/,
243     int         /*err*/
244 #endif
245 );
246 #endif
247
248 static short    xdm_udp_port = XDM_UDP_PORT;
249 static Bool     OneSession = FALSE;
250
251 XdmcpUseMsg ()
252 {
253     ErrorF("-query host-name       contact named host for XDMCP\n");
254     ErrorF("-broadcast             broadcast for XDMCP\n");
255     ErrorF("-indirect host-name    contact named host for indirect XDMCP\n");
256     ErrorF("-port port-num         UDP port number to send messages to\n");
257     ErrorF("-once                  Terminate server after one session\n");
258     ErrorF("-class display-class   specify display class to send in manage\n");
259 #ifdef HASXDMAUTH
260     ErrorF("-cookie xdm-auth-bits  specify the magic cookie for XDMCP\n");
261 #endif
262     ErrorF("-displayID display-id  manufacturer display ID for request\n");
263 }
264
265 int 
266 XdmcpOptions(argc, argv, i)
267     int     argc, i;
268     char    **argv;
269 {
270     if (strcmp(argv[i], "-query") == 0) {
271         get_manager_by_name(argc, argv, ++i);
272         XDM_INIT_STATE = XDM_QUERY;
273         AccessUsingXdmcp ();
274         return (i + 1);
275     }
276     if (strcmp(argv[i], "-broadcast") == 0) {
277         XDM_INIT_STATE = XDM_BROADCAST;
278         AccessUsingXdmcp ();
279         return (i + 1);
280     }
281     if (strcmp(argv[i], "-indirect") == 0) {
282         get_manager_by_name(argc, argv, ++i);
283         XDM_INIT_STATE = XDM_INDIRECT;
284         AccessUsingXdmcp ();
285         return (i + 1);
286     }
287     if (strcmp(argv[i], "-port") == 0) {
288         ++i;
289         xdm_udp_port = atoi(argv[i]);
290         return (i + 1);
291     }
292     if (strcmp(argv[i], "-once") == 0) {
293         OneSession = TRUE;
294         return (i + 1);
295     }
296     if (strcmp(argv[i], "-class") == 0) {
297         ++i;
298         defaultDisplayClass = argv[i];
299         return (i + 1);
300     }
301 #ifdef HASXDMAUTH
302     if (strcmp(argv[i], "-cookie") == 0) {
303         ++i;
304         xdmAuthCookie = argv[i];
305         return (i + 1);
306     }
307 #endif
308     if (strcmp(argv[i], "-displayID") == 0) {
309         ++i;
310         XdmcpRegisterManufacturerDisplayID (argv[i], strlen (argv[i]));
311         return (i + 1);
312     }
313     return (i);
314 }
315
316 /*
317  * This section is a collection of routines for
318  * registering server-specific data with the XDMCP
319  * state machine.
320  */
321
322
323 /*
324  * Save all broadcast addresses away so BroadcastQuery
325  * packets get sent everywhere
326  */
327
328 #define MAX_BROADCAST   10
329
330 static struct sockaddr_in   BroadcastAddresses[MAX_BROADCAST];
331 static int                  NumBroadcastAddresses;
332
333 void
334 XdmcpRegisterBroadcastAddress (addr)
335     struct sockaddr_in  *addr;
336 {
337     struct sockaddr_in  *bcast;
338     if (NumBroadcastAddresses >= MAX_BROADCAST)
339         return;
340     bcast = &BroadcastAddresses[NumBroadcastAddresses++];
341     bzero (bcast, sizeof (struct sockaddr_in));
342 #ifdef BSD44SOCKETS
343     bcast->sin_len = addr->sin_len;
344 #endif
345     bcast->sin_family = addr->sin_family;
346     bcast->sin_port = htons (xdm_udp_port);
347     bcast->sin_addr = addr->sin_addr;
348 }
349
350 /*
351  * Each authentication type is registered here; Validator
352  * will be called to check all access attempts using
353  * the specified authentication type
354  */
355
356 static ARRAYofARRAY8    AuthenticationNames, AuthenticationDatas;
357 typedef struct _AuthenticationFuncs {
358     Bool    (*Validator)();
359     Bool    (*Generator)();
360     Bool    (*AddAuth)();
361 } AuthenticationFuncsRec, *AuthenticationFuncsPtr;
362
363 static AuthenticationFuncsPtr   AuthenticationFuncsList;
364
365 void
366 XdmcpRegisterAuthentication (name, namelen, data, datalen, Validator, Generator, AddAuth)
367     char    *name;
368     int     namelen;
369     char    *data;
370     int     datalen;
371     Bool    (*Validator)();
372     Bool    (*Generator)();
373     Bool    (*AddAuth)();
374 {
375     int     i;
376     ARRAY8  AuthenticationName, AuthenticationData;
377     static AuthenticationFuncsPtr       newFuncs;
378
379     if (!XdmcpAllocARRAY8 (&AuthenticationName, namelen))
380         return;
381     if (!XdmcpAllocARRAY8 (&AuthenticationData, datalen))
382     {
383         XdmcpDisposeARRAY8 (&AuthenticationName);
384         return;
385     }
386     for (i = 0; i < namelen; i++)
387         AuthenticationName.data[i] = name[i];
388     for (i = 0; i < datalen; i++)
389         AuthenticationData.data[i] = data[i];
390     if (!(XdmcpReallocARRAYofARRAY8 (&AuthenticationNames,
391                                      AuthenticationNames.length + 1) &&
392           XdmcpReallocARRAYofARRAY8 (&AuthenticationDatas,
393                                      AuthenticationDatas.length + 1) &&
394           (newFuncs = (AuthenticationFuncsPtr) xalloc (
395                         (AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec)))))
396     {
397         XdmcpDisposeARRAY8 (&AuthenticationName);
398         XdmcpDisposeARRAY8 (&AuthenticationData);
399         return;
400     }
401     for (i = 0; i < AuthenticationNames.length - 1; i++)
402         newFuncs[i] = AuthenticationFuncsList[i];
403     newFuncs[AuthenticationNames.length-1].Validator = Validator;
404     newFuncs[AuthenticationNames.length-1].Generator = Generator;
405     newFuncs[AuthenticationNames.length-1].AddAuth = AddAuth;
406     xfree (AuthenticationFuncsList);
407     AuthenticationFuncsList = newFuncs;
408     AuthenticationNames.data[AuthenticationNames.length-1] = AuthenticationName;
409     AuthenticationDatas.data[AuthenticationDatas.length-1] = AuthenticationData;
410 }
411
412 /*
413  * Select the authentication type to be used; this is
414  * set by the manager of the host to be connected to.
415  */
416
417 ARRAY8          noAuthenticationName = {(CARD16) 0, (CARD8Ptr) 0};
418 ARRAY8          noAuthenticationData = {(CARD16) 0, (CARD8Ptr) 0};
419 ARRAY8Ptr       AuthenticationName = &noAuthenticationName;
420 ARRAY8Ptr       AuthenticationData = &noAuthenticationData;
421 AuthenticationFuncsPtr  AuthenticationFuncs;
422
423 void
424 XdmcpSetAuthentication (name)
425     ARRAY8Ptr   name;
426 {
427     int i;
428
429     for (i = 0; i < AuthenticationNames.length; i++)
430         if (XdmcpARRAY8Equal (&AuthenticationNames.data[i], name))
431         {
432             AuthenticationName = &AuthenticationNames.data[i];
433             AuthenticationData = &AuthenticationDatas.data[i];
434             AuthenticationFuncs = &AuthenticationFuncsList[i];
435             break;
436         }
437 }
438
439 /*
440  * Register the host address for the display
441  */
442
443 static ARRAY16          ConnectionTypes;
444 static ARRAYofARRAY8    ConnectionAddresses;
445 static long             xdmcpGeneration;
446
447 void
448 XdmcpRegisterConnection (type, address, addrlen)
449     int     type;
450     char    *address;
451     int     addrlen;
452 {
453     int     i;
454     CARD8   *newAddress;
455
456     if (xdmcpGeneration != serverGeneration)
457     {
458         XdmcpDisposeARRAY16 (&ConnectionTypes);
459         XdmcpDisposeARRAYofARRAY8 (&ConnectionAddresses);
460         xdmcpGeneration = serverGeneration;
461     }
462     newAddress = (CARD8 *) xalloc (addrlen * sizeof (CARD8));
463     if (!newAddress)
464         return;
465     if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1))
466     {
467         xfree (newAddress);
468         return;
469     }
470     if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses,
471                                     ConnectionAddresses.length +  1))
472     {
473         xfree (newAddress);
474         return;
475     }
476     ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type;
477     for (i = 0; i < addrlen; i++)
478         newAddress[i] = address[i];
479     ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress;
480     ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen;
481 }
482
483 /*
484  * Register an Authorization Name.  XDMCP advertises this list
485  * to the manager.
486  */
487
488 static ARRAYofARRAY8    AuthorizationNames;
489
490 void
491 XdmcpRegisterAuthorizations ()
492 {
493     XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames);
494     RegisterAuthorizations ();
495 }
496
497 void
498 XdmcpRegisterAuthorization (name, namelen)
499     char    *name;
500     int     namelen;
501 {
502     ARRAY8  authName;
503     int     i;
504
505     authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8));
506     if (!authName.data)
507         return;
508     if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1))
509     {
510         xfree (authName.data);
511         return;
512     }
513     for (i = 0; i < namelen; i++)
514         authName.data[i] = (CARD8) name[i];
515     authName.length = namelen;
516     AuthorizationNames.data[AuthorizationNames.length-1] = authName;
517 }
518
519 /*
520  * Register the DisplayClass string
521  */
522
523 ARRAY8  DisplayClass;
524
525 void
526 XdmcpRegisterDisplayClass (name, length)
527     char    *name;
528     int     length;
529 {
530     int     i;
531
532     XdmcpDisposeARRAY8 (&DisplayClass);
533     if (!XdmcpAllocARRAY8 (&DisplayClass, length))
534         return;
535     for (i = 0; i < length; i++)
536         DisplayClass.data[i] = (CARD8) name[i];
537 }
538
539 /*
540  * Register the Manufacturer display ID
541  */
542
543 ARRAY8 ManufacturerDisplayID;
544
545 void
546 XdmcpRegisterManufacturerDisplayID (name, length)
547     char    *name;
548     int     length;
549 {
550     int     i;
551
552     XdmcpDisposeARRAY8 (&ManufacturerDisplayID);
553     if (!XdmcpAllocARRAY8 (&ManufacturerDisplayID, length))
554         return;
555     for (i = 0; i < length; i++)
556         ManufacturerDisplayID.data[i] = (CARD8) name[i];
557 }
558
559 /* 
560  * initialize XDMCP; create the socket, compute the display
561  * number, set up the state machine
562  */
563
564 void 
565 XdmcpInit()
566 {
567     state = XDM_INIT_STATE;
568 #ifdef HASXDMAUTH
569     if (xdmAuthCookie)
570         XdmAuthenticationInit (xdmAuthCookie, strlen (xdmAuthCookie));
571 #endif
572     if (state != XDM_OFF)
573     {
574         XdmcpRegisterAuthorizations();
575         XdmcpRegisterDisplayClass (defaultDisplayClass, strlen (defaultDisplayClass));
576         AccessUsingXdmcp();
577         RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
578                                         (pointer) 0);
579         timeOutRtx = 0;
580         DisplayNumber = (CARD16) atoi(display);
581         get_xdmcp_sock();
582         send_packet();
583     }
584 }
585
586 void
587 XdmcpReset ()
588 {
589     state = XDM_INIT_STATE;
590     if (state != XDM_OFF)
591     {
592         RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
593                                         (pointer) 0);
594         timeOutRtx = 0;
595         send_packet();
596     }
597 }
598
599 /*
600  * Called whenever a new connection is created; notices the
601  * first connection and saves it to terminate the session
602  * when it is closed
603  */
604
605 void
606 XdmcpOpenDisplay(sock)
607     int sock;
608 {
609     if (state != XDM_AWAIT_MANAGE_RESPONSE)
610         return;
611     state = XDM_RUN_SESSION;
612     sessionSocket = sock;
613 }
614
615 void 
616 XdmcpCloseDisplay(sock)
617     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*/
638 static void
639 XdmcpBlockHandler(data, wt, pReadmask)
640     pointer         data;   /* unused */
641     struct timeval  **wt;
642     pointer         pReadmask;
643 {
644     fd_set *LastSelectMask = (fd_set*)pReadmask;
645     CARD32 millisToGo, wtMillis;
646     static struct timeval waittime;
647
648     if (state == XDM_OFF)
649         return;
650     FD_SET(xdmcpSocket, LastSelectMask);
651     if (timeOutTime == 0)
652         return;
653     millisToGo = GetTimeInMillis();
654     if (millisToGo < timeOutTime)
655         millisToGo = timeOutTime - millisToGo;
656     else
657         millisToGo = 0;
658     if (*wt == NULL)
659     {
660         waittime.tv_sec = (millisToGo) / 1000;
661         waittime.tv_usec = 1000 * (millisToGo % 1000);
662         *wt = &waittime;
663     }
664     else
665     {
666         wtMillis = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000;
667         if (millisToGo < wtMillis)
668         {
669             (*wt)->tv_sec = (millisToGo) / 1000;
670             (*wt)->tv_usec = 1000 * (millisToGo % 1000);
671         }
672     }
673 }
674
675 /*
676  * called after select returns; this routine will
677  * recognise when XDMCP packets await and
678  * process them appropriately
679  */
680
681 /*ARGSUSED*/
682 static void
683 XdmcpWakeupHandler(data, i, pReadmask)
684     pointer data;   /* unused */
685     int     i;
686     pointer pReadmask;
687 {
688     fd_set* LastSelectMask = (fd_set*)pReadmask;
689     fd_set   devicesReadable;
690
691     if (state == XDM_OFF)
692         return;
693     if (i > 0)
694     {
695         if (FD_ISSET(xdmcpSocket, LastSelectMask))
696         {
697             receive_packet();
698             FD_CLR(xdmcpSocket, LastSelectMask);
699         } 
700         XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices);
701         if (XFD_ANYSET(&devicesReadable))
702         {
703             if (state == XDM_AWAIT_USER_INPUT)
704                 restart();
705             else if (state == XDM_RUN_SESSION)
706                 keepaliveDormancy = defaultKeepaliveDormancy;
707         }
708         if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION)
709             timeOutTime = GetTimeInMillis() +  keepaliveDormancy * 1000;
710     }
711     else if (timeOutTime && GetTimeInMillis() >= timeOutTime)
712     {
713         if (state == XDM_RUN_SESSION)
714         {
715             state = XDM_KEEPALIVE;
716             send_packet();
717         }
718         else
719             timeout();
720     }
721 }
722
723 /*
724  * This routine should be called from the routine that drives the
725  * user's host menu when the user selects a host
726  */
727
728 XdmcpSelectHost(host_sockaddr, host_len, AuthenticationName)
729     struct sockaddr_in  *host_sockaddr;
730     int                 host_len;
731     ARRAY8Ptr           AuthenticationName;
732 {
733     state = XDM_START_CONNECTION;
734     memmove(&req_sockaddr, host_sockaddr, host_len);
735     req_socklen = host_len;
736     XdmcpSetAuthentication (AuthenticationName);
737     send_packet();
738 }
739
740 /*
741  * !!! this routine should be replaced by a routine that adds
742  * the host to the user's host menu. the current version just
743  * selects the first host to respond with willing message.
744  */
745
746 /*ARGSUSED*/
747 XdmcpAddHost(from, fromlen, AuthenticationName, hostname, status)
748     struct sockaddr_in  *from;
749     ARRAY8Ptr           AuthenticationName, hostname, status;
750 {
751     XdmcpSelectHost(from, fromlen, AuthenticationName);
752 }
753
754 /*
755  * A message is queued on the socket; read it and
756  * do the appropriate thing
757  */
758
759 ARRAY8  UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" };
760
761 static void
762 receive_packet()
763 {
764     struct sockaddr_in from;
765     int fromlen = sizeof(struct sockaddr_in);
766     XdmcpHeader header;
767
768     /* read message off socket */
769     if (!XdmcpFill (xdmcpSocket, &buffer, (struct sockaddr *) &from, &fromlen))
770         return;
771
772     /* reset retransmission backoff */
773     timeOutRtx = 0;
774
775     if (!XdmcpReadHeader (&buffer, &header))
776         return;
777
778     if (header.version != XDM_PROTOCOL_VERSION)
779         return;
780
781     switch (header.opcode) {
782     case WILLING:
783         recv_willing_msg(&from, fromlen, header.length);
784         break;
785     case UNWILLING:
786         XdmcpFatal("Manager unwilling", &UnwillingMessage);
787         break;
788     case ACCEPT:
789         recv_accept_msg(header.length);
790         break;
791     case DECLINE:
792         recv_decline_msg(header.length);
793         break;
794     case REFUSE:
795         recv_refuse_msg(header.length);
796         break;
797     case FAILED:
798         recv_failed_msg(header.length);
799         break;
800     case ALIVE:
801         recv_alive_msg(header.length);
802         break;
803     }
804 }
805
806 /*
807  * send the appropriate message given the current state
808  */
809
810 static
811 send_packet()
812 {
813     int rtx;
814     switch (state) {
815     case XDM_QUERY:
816     case XDM_BROADCAST:
817     case XDM_INDIRECT:
818         send_query_msg();
819         break;
820     case XDM_START_CONNECTION:
821         send_request_msg();
822         break;
823     case XDM_MANAGE:
824         send_manage_msg();
825         break;
826     case XDM_KEEPALIVE:
827         send_keepalive_msg();
828         break;
829     }
830     rtx = (XDM_MIN_RTX << timeOutRtx);
831     if (rtx > XDM_MAX_RTX)
832         rtx = XDM_MAX_RTX;
833     timeOutTime = GetTimeInMillis() + rtx * 1000;
834 }
835
836 /*
837  * The session is declared dead for some reason; too many
838  * timeouts, or Keepalive failure.
839  */
840
841 XdmcpDeadSession (reason)
842     char *reason;
843 {
844     ErrorF ("XDM: %s, declaring session dead\n", reason);
845     state = XDM_INIT_STATE;
846     isItTimeToYield = TRUE;
847     dispatchException |= DE_RESET;
848     timeOutTime = 0;
849     timeOutRtx = 0;
850     send_packet();
851 }
852
853 /*
854  * Timeout waiting for an XDMCP response.
855  */
856
857 static void
858 timeout()
859 {
860     timeOutRtx++;
861     if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT )
862     {
863         XdmcpDeadSession ("too many keepalive retransmissions");
864         return;
865     }
866     else if (timeOutRtx >= XDM_RTX_LIMIT)
867     {
868         ErrorF("XDM: too many retransmissions\n");
869         state = XDM_AWAIT_USER_INPUT;
870         timeOutTime = 0;
871         timeOutRtx = 0;
872         return;
873     }
874
875     switch (state) {
876     case XDM_COLLECT_QUERY:
877         state = XDM_QUERY;
878         break;
879     case XDM_COLLECT_BROADCAST_QUERY:
880         state = XDM_BROADCAST;
881         break;
882     case XDM_COLLECT_INDIRECT_QUERY:
883         state = XDM_INDIRECT;
884         break;
885     case XDM_AWAIT_REQUEST_RESPONSE:
886         state = XDM_START_CONNECTION;
887         break;
888     case XDM_AWAIT_MANAGE_RESPONSE:
889         state = XDM_MANAGE;
890         break;
891     case XDM_AWAIT_ALIVE_RESPONSE:
892         state = XDM_KEEPALIVE;
893         break;
894     }
895     send_packet();
896 }
897
898 static
899 restart()
900 {
901     state = XDM_INIT_STATE;
902     timeOutRtx = 0;
903     send_packet();
904 }
905
906 XdmcpCheckAuthentication (Name, Data, packet_type)
907     ARRAY8Ptr   Name, Data;
908     int packet_type;
909 {
910     return (XdmcpARRAY8Equal (Name, AuthenticationName) &&
911             (AuthenticationName->length == 0 ||
912              (*AuthenticationFuncs->Validator) (AuthenticationData, Data, packet_type)));
913 }
914
915 XdmcpAddAuthorization (name, data)
916     ARRAY8Ptr   name, data;
917 {
918     Bool    (*AddAuth)(), AddAuthorization();
919
920     if (AuthenticationFuncs && AuthenticationFuncs->AddAuth)
921         AddAuth = AuthenticationFuncs->AddAuth;
922     else
923         AddAuth = AddAuthorization;
924     return (*AddAuth) ((unsigned short)name->length,
925                        (char *)name->data,
926                        (unsigned short)data->length,
927                        (char *)data->data);
928 }
929
930 /*
931  * from here to the end of this file are routines private
932  * to the state machine.
933  */
934
935 static void
936 get_xdmcp_sock()
937 {
938 #ifdef STREAMSCONN
939     struct netconfig *nconf;
940
941     if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) {
942         XdmcpWarning("t_open() of /dev/udp failed");
943         return;
944     }
945
946     if( t_bind(xdmcpSocket,NULL,NULL) < 0 ) {
947         XdmcpWarning("UDP socket creation failed");
948         t_error("t_bind(xdmcpSocket) failed" );
949         t_close(xdmcpSocket);
950         return;
951     }
952
953     /*
954      * This part of the code looks contrived. It will actually fit in nicely
955      * when the CLTS part of Xtrans is implemented.
956      */
957  
958     if( (nconf=getnetconfigent("udp")) == NULL ) {
959         XdmcpWarning("UDP socket creation failed: getnetconfigent()");
960         t_unbind(xdmcpSocket);
961         t_close(xdmcpSocket);
962         return;
963     }
964  
965     if( netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL) ) {
966         XdmcpWarning("UDP set broadcast option failed: netdir_options()");
967         freenetconfigent(nconf);
968         t_unbind(xdmcpSocket);
969         t_close(xdmcpSocket);
970         return;
971     }
972  
973     freenetconfigent(nconf);
974 #else
975 #ifndef _MINIX
976     int soopts = 1;
977
978     if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
979 #else /* MINIX */
980     char *udp_device;
981     int r, s_errno;
982     nwio_udpopt_t udpopt;
983     nbio_ref_t ref;
984
985     udp_device= getenv("UDP_DEVICE");
986     if (udp_device == NULL)
987         udp_device= UDP_DEVICE;
988     xdmcpSocket= open(udp_device, O_RDWR);
989     if (xdmcpSocket != -1)
990     {
991         udpopt.nwuo_flags= NWUO_COPY | NWUO_LP_SEL | NWUO_EN_LOC | 
992                 NWUO_DI_BROAD | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL |
993                 NWUO_DI_IPOPT;
994         r= ioctl(xdmcpSocket, NWIOSUDPOPT, &udpopt);
995         if (r == -1)
996         {
997                 s_errno= errno;
998                 close(xdmcpSocket);
999                 xdmcpSocket= -1;
1000                 errno= s_errno;
1001         }
1002         ioctl(xdmcpSocket, NWIOGUDPOPT, &udpopt);
1003         ErrorF("0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", 
1004                 udpopt.nwuo_flags,
1005                 udpopt.nwuo_locport,
1006                 udpopt.nwuo_remport,
1007                 udpopt.nwuo_locaddr,
1008                 udpopt.nwuo_remaddr);
1009     }
1010     if (xdmcpSocket != -1)
1011     {
1012         fcntl(xdmcpSocket, F_SETFD, fcntl(xdmcpSocket, F_GETFD) | 
1013                                                                 FD_ASYNCHIO);
1014         nbio_register(xdmcpSocket);
1015         ref.ref_int= xdmcpSocket;
1016         nbio_setcallback(xdmcpSocket, ASIO_READ, read_cb, ref);
1017     }
1018     if (xdmcpSocket == -1)
1019 #endif /* !MINIX */
1020         XdmcpWarning("UDP socket creation failed");
1021 #ifdef SO_BROADCAST
1022     else if (setsockopt(xdmcpSocket, SOL_SOCKET, SO_BROADCAST, (char *)&soopts,
1023         sizeof(soopts)) < 0)
1024             XdmcpWarning("UDP set broadcast socket-option failed");
1025 #endif /* SO_BROADCAST */
1026 #endif /* STREAMSCONN */
1027 }
1028
1029 static void
1030 send_query_msg()
1031 {
1032     XdmcpHeader header;
1033     Bool        broadcast = FALSE;
1034     int         i;
1035
1036     header.version = XDM_PROTOCOL_VERSION;
1037     switch(state){
1038     case XDM_QUERY:
1039         header.opcode = (CARD16) QUERY; 
1040         state = XDM_COLLECT_QUERY;
1041         break;
1042     case XDM_BROADCAST:
1043         header.opcode = (CARD16) BROADCAST_QUERY;
1044         state = XDM_COLLECT_BROADCAST_QUERY;
1045         broadcast = TRUE;
1046         break;
1047     case XDM_INDIRECT:
1048         header.opcode = (CARD16) INDIRECT_QUERY;
1049         state = XDM_COLLECT_INDIRECT_QUERY;
1050         break;
1051     }
1052     header.length = 1;
1053     for (i = 0; i < AuthenticationNames.length; i++)
1054         header.length += 2 + AuthenticationNames.data[i].length;
1055
1056     XdmcpWriteHeader (&buffer, &header);
1057     XdmcpWriteARRAYofARRAY8 (&buffer, &AuthenticationNames);
1058     if (broadcast)
1059     {
1060         int i;
1061
1062         for (i = 0; i < NumBroadcastAddresses; i++)
1063             XdmcpFlush (xdmcpSocket, &buffer, &BroadcastAddresses[i],
1064                         sizeof (struct sockaddr_in));
1065     }
1066     else
1067     {
1068         XdmcpFlush (xdmcpSocket, &buffer, &ManagerAddress,
1069                     sizeof (ManagerAddress));
1070     }
1071 }
1072
1073 static void
1074 recv_willing_msg(from, fromlen, length)
1075     struct sockaddr_in  *from;
1076     int                 fromlen;
1077     unsigned            length;
1078 {
1079     ARRAY8      authenticationName;
1080     ARRAY8      hostname;
1081     ARRAY8      status;
1082
1083     authenticationName.data = 0;
1084     hostname.data = 0;
1085     status.data = 0;
1086     if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
1087         XdmcpReadARRAY8 (&buffer, &hostname) &&
1088         XdmcpReadARRAY8 (&buffer, &status))
1089     {
1090         if (length == 6 + authenticationName.length +
1091                       hostname.length + status.length)
1092         {
1093             switch (state)
1094             {
1095             case XDM_COLLECT_QUERY:
1096                 XdmcpSelectHost(from, fromlen, &authenticationName);
1097                 break;
1098             case XDM_COLLECT_BROADCAST_QUERY:
1099             case XDM_COLLECT_INDIRECT_QUERY:
1100                 XdmcpAddHost(from, fromlen, &authenticationName, &hostname, &status);
1101                 break;
1102             }
1103         }
1104     }
1105     XdmcpDisposeARRAY8 (&authenticationName);
1106     XdmcpDisposeARRAY8 (&hostname);
1107     XdmcpDisposeARRAY8 (&status);
1108 }
1109
1110 static void
1111 send_request_msg()
1112 {
1113     XdmcpHeader     header;
1114     int             length;
1115     int             i;
1116     ARRAY8          authenticationData;
1117
1118     header.version = XDM_PROTOCOL_VERSION;
1119     header.opcode = (CARD16) REQUEST;
1120
1121     length = 2;                                     /* display number */
1122     length += 1 + 2 * ConnectionTypes.length;       /* connection types */
1123     length += 1;                                    /* connection addresses */
1124     for (i = 0; i < ConnectionAddresses.length; i++)
1125         length += 2 + ConnectionAddresses.data[i].length;
1126     authenticationData.length = 0;
1127     authenticationData.data = 0;
1128     if (AuthenticationFuncs)
1129     {
1130         (*AuthenticationFuncs->Generator) (AuthenticationData,
1131                                            &authenticationData,
1132                                            REQUEST);
1133     }
1134     length += 2 + AuthenticationName->length;       /* authentication name */
1135     length += 2 + authenticationData.length;        /* authentication data */
1136     length += 1;                                    /* authorization names */
1137     for (i = 0; i < AuthorizationNames.length; i++)
1138         length += 2 + AuthorizationNames.data[i].length;
1139     length += 2 + ManufacturerDisplayID.length;     /* display ID */
1140     header.length = length;
1141
1142     if (!XdmcpWriteHeader (&buffer, &header))
1143     {
1144         XdmcpDisposeARRAY8 (&authenticationData);
1145         return;
1146     }
1147     XdmcpWriteCARD16 (&buffer, DisplayNumber);
1148     XdmcpWriteARRAY16 (&buffer, &ConnectionTypes);
1149     XdmcpWriteARRAYofARRAY8 (&buffer, &ConnectionAddresses);
1150
1151     XdmcpWriteARRAY8 (&buffer, AuthenticationName);
1152     XdmcpWriteARRAY8 (&buffer, &authenticationData);
1153     XdmcpDisposeARRAY8 (&authenticationData);
1154     XdmcpWriteARRAYofARRAY8 (&buffer, &AuthorizationNames);
1155     XdmcpWriteARRAY8 (&buffer, &ManufacturerDisplayID);
1156     if (XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen))
1157         state = XDM_AWAIT_REQUEST_RESPONSE;
1158 }
1159
1160 static void
1161 recv_accept_msg(length)
1162     unsigned            length;
1163 {
1164     CARD32  AcceptSessionID;
1165     ARRAY8  AcceptAuthenticationName, AcceptAuthenticationData;
1166     ARRAY8  AcceptAuthorizationName, AcceptAuthorizationData;
1167
1168     if (state != XDM_AWAIT_REQUEST_RESPONSE)
1169         return;
1170     AcceptAuthenticationName.data = 0;
1171     AcceptAuthenticationData.data = 0;
1172     AcceptAuthorizationName.data = 0;
1173     AcceptAuthorizationData.data = 0;
1174     if (XdmcpReadCARD32 (&buffer, &AcceptSessionID) &&
1175         XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationName) &&
1176         XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationData) &&
1177         XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationName) &&
1178         XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationData))
1179     {
1180         if (length == 12 + AcceptAuthenticationName.length +
1181                            AcceptAuthenticationData.length +
1182                            AcceptAuthorizationName.length +
1183                            AcceptAuthorizationData.length)
1184         {
1185             if (!XdmcpCheckAuthentication (&AcceptAuthenticationName,
1186                                       &AcceptAuthenticationData, ACCEPT))
1187             {
1188                 XdmcpFatal ("Authentication Failure", &AcceptAuthenticationName);
1189             }
1190             /* permit access control manipulations from this host */
1191             AugmentSelf (&req_sockaddr, req_socklen);
1192             /* if the authorization specified in the packet fails
1193              * to be acceptable, enable the local addresses
1194              */
1195             if (!XdmcpAddAuthorization (&AcceptAuthorizationName,
1196                                         &AcceptAuthorizationData))
1197             {
1198                 AddLocalHosts ();
1199             }
1200             SessionID = AcceptSessionID;
1201             state = XDM_MANAGE;
1202             send_packet();
1203         }
1204     }
1205     XdmcpDisposeARRAY8 (&AcceptAuthenticationName);
1206     XdmcpDisposeARRAY8 (&AcceptAuthenticationData);
1207     XdmcpDisposeARRAY8 (&AcceptAuthorizationName);
1208     XdmcpDisposeARRAY8 (&AcceptAuthorizationData);
1209 }
1210
1211 static void
1212 recv_decline_msg(length)
1213     unsigned            length;
1214 {
1215     ARRAY8  status, DeclineAuthenticationName, DeclineAuthenticationData;
1216
1217     status.data = 0;
1218     DeclineAuthenticationName.data = 0;
1219     DeclineAuthenticationData.data = 0;
1220     if (XdmcpReadARRAY8 (&buffer, &status) &&
1221         XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationName) &&
1222         XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationData))
1223     {
1224         if (length == 6 + status.length +
1225                           DeclineAuthenticationName.length +
1226                           DeclineAuthenticationData.length &&
1227             XdmcpCheckAuthentication (&DeclineAuthenticationName,
1228                                       &DeclineAuthenticationData, DECLINE))
1229         {
1230             XdmcpFatal ("Session declined", &status);
1231         }
1232     }
1233     XdmcpDisposeARRAY8 (&status);
1234     XdmcpDisposeARRAY8 (&DeclineAuthenticationName);
1235     XdmcpDisposeARRAY8 (&DeclineAuthenticationData);
1236 }
1237
1238 static void
1239 send_manage_msg()
1240 {
1241     XdmcpHeader header;
1242
1243     header.version = XDM_PROTOCOL_VERSION;
1244     header.opcode = (CARD16) MANAGE;
1245     header.length = 8 + DisplayClass.length;
1246
1247     if (!XdmcpWriteHeader (&buffer, &header))
1248         return;
1249     XdmcpWriteCARD32 (&buffer, SessionID);
1250     XdmcpWriteCARD16 (&buffer, DisplayNumber);
1251     XdmcpWriteARRAY8 (&buffer, &DisplayClass);
1252     state = XDM_AWAIT_MANAGE_RESPONSE;
1253     XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen);
1254 }
1255
1256 static void
1257 recv_refuse_msg(length)
1258     unsigned            length;
1259 {
1260     CARD32  RefusedSessionID;
1261
1262     if (state != XDM_AWAIT_MANAGE_RESPONSE)
1263         return;
1264     if (length != 4)
1265         return;
1266     if (XdmcpReadCARD32 (&buffer, &RefusedSessionID))
1267     {
1268         if (RefusedSessionID == SessionID)
1269         {
1270             state = XDM_START_CONNECTION;
1271             send_packet();
1272         }
1273     }
1274 }
1275
1276 static void
1277 recv_failed_msg(length)
1278     unsigned            length;
1279 {
1280     CARD32  FailedSessionID;
1281     ARRAY8  status;
1282
1283     if (state != XDM_AWAIT_MANAGE_RESPONSE)
1284         return;
1285     status.data = 0;
1286     if (XdmcpReadCARD32 (&buffer, &FailedSessionID) &&
1287         XdmcpReadARRAY8 (&buffer, &status))
1288     {
1289         if (length == 6 + status.length &&
1290             SessionID == FailedSessionID)
1291         {
1292             XdmcpFatal ("Session failed", &status);
1293         }
1294     }
1295     XdmcpDisposeARRAY8 (&status);
1296 }
1297
1298 static void
1299 send_keepalive_msg()
1300 {
1301     XdmcpHeader header;
1302
1303     header.version = XDM_PROTOCOL_VERSION;
1304     header.opcode = (CARD16) KEEPALIVE;
1305     header.length = 6;
1306
1307     XdmcpWriteHeader (&buffer, &header);
1308     XdmcpWriteCARD16 (&buffer, DisplayNumber);
1309     XdmcpWriteCARD32 (&buffer, SessionID);
1310
1311     state = XDM_AWAIT_ALIVE_RESPONSE;
1312     XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen);
1313 }
1314
1315 static void
1316 recv_alive_msg (length)
1317     unsigned            length;
1318 {
1319     CARD8   SessionRunning;
1320     CARD32  AliveSessionID;
1321     int     dormancy;
1322
1323     if (state != XDM_AWAIT_ALIVE_RESPONSE)
1324         return;
1325     if (length != 5)
1326         return;
1327     if (XdmcpReadCARD8 (&buffer, &SessionRunning) &&
1328         XdmcpReadCARD32 (&buffer, &AliveSessionID))
1329     {
1330         if (SessionRunning && AliveSessionID == SessionID)
1331         {
1332             /* backoff dormancy period */
1333             state = XDM_RUN_SESSION;
1334             if ((GetTimeInMillis() - lastDeviceEventTime.milliseconds) >
1335                 keepaliveDormancy * 1000)
1336             {
1337                 keepaliveDormancy <<= 1;
1338                 if (keepaliveDormancy > XDM_MAX_DORMANCY)
1339                     keepaliveDormancy = XDM_MAX_DORMANCY;
1340             }
1341             timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
1342         }
1343         else
1344         {
1345             XdmcpDeadSession ("Alive respose indicates session dead");
1346         }
1347     }
1348 }
1349
1350 static 
1351 XdmcpFatal (type, status)
1352     char        *type;
1353     ARRAY8Ptr   status;
1354 {
1355     FatalError ("XDMCP fatal error: %s %*.*s\n", type,
1356            status->length, status->length, status->data);
1357 }
1358
1359 static 
1360 XdmcpWarning(str)
1361     char *str;
1362 {
1363     ErrorF("XDMCP warning: %s\n", str);
1364 }
1365
1366 static
1367 get_manager_by_name(argc, argv, i)
1368     int     argc, i;
1369     char    **argv;
1370 {
1371     struct hostent *hep;
1372
1373     if (i == argc)
1374     {
1375         ErrorF("Xserver: missing host name in command line\n");
1376         exit(1);
1377     }
1378     if (!(hep = gethostbyname(argv[i])))
1379     {
1380         ErrorF("Xserver: unknown host: %s\n", argv[i]);
1381         exit(1);
1382     }
1383 #ifndef _MINIX
1384     if (hep->h_length == sizeof (struct in_addr))
1385 #else
1386     if (hep->h_length == sizeof (ipaddr_t))
1387 #endif
1388     {
1389         memmove(&ManagerAddress.sin_addr, hep->h_addr, hep->h_length);
1390 #ifdef BSD44SOCKETS
1391         ManagerAddress.sin_len = sizeof(ManagerAddress);
1392 #endif
1393         ManagerAddress.sin_family = AF_INET;
1394         ManagerAddress.sin_port = htons (xdm_udp_port);
1395     }
1396     else
1397     {
1398         ErrorF ("Xserver: host on strange network %s\n", argv[i]);
1399         exit (1);
1400     }
1401 }
1402
1403 #ifdef MINIX
1404 static char read_buffer[XDM_MAX_MSGLEN+sizeof(udp_io_hdr_t)];
1405 static int read_inprogress;
1406 static int read_size;
1407
1408 int
1409 XdmcpFill (fd, buffer, from, fromlen)
1410 int             fd;
1411 XdmcpBufferPtr  buffer;
1412 XdmcpNetaddr    from;       /* return */
1413 int             *fromlen;   /* return */
1414 {
1415         int r;
1416
1417         if (read_inprogress)
1418                 return 0;
1419
1420         if (read_size != 0)
1421         {
1422                 r= read_size;
1423                 read_size= 0;
1424                 return MNX_XdmcpFill(fd, buffer, from, fromlen, read_buffer,
1425                         r);
1426         }
1427
1428         r= read(fd, read_buffer, sizeof(read_buffer));
1429         if (r > 0)
1430         {
1431                 return MNX_XdmcpFill(fd, buffer, from, fromlen, read_buffer,
1432                         r);
1433         }
1434         else if (r == -1 && errno == EINPROGRESS)
1435         {
1436                 read_inprogress= 1;
1437                 nbio_inprogress(fd, ASIO_READ, 1 /* read */, 0 /* write */,
1438                         0 /* except */);
1439                 return 0;
1440         }
1441         else
1442                 FatalError("XdmcpFill: read failed: %s\n",
1443                         r == 0 ? "EOF" : strerror(errno));
1444         return 0;
1445 }
1446
1447 static void read_cb(ref, res, err)
1448 nbio_ref_t ref;
1449 int res;
1450 int err;
1451 {
1452         if (res <= 0)
1453         {
1454                 FatalError("xdmcp'read_cb: read failed: %s\n",
1455                         res == 0 ? "EOF" : strerror(err));
1456         }
1457         read_inprogress= 0;
1458         read_size= res;
1459 }
1460 #endif
1461
1462 #else
1463 static int xdmcp_non_empty; /* avoid complaint by ranlib */
1464 #endif /* XDMCP */