home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / server / os / xdmcp.c.orig < prev    next >
Encoding:
Text File  |  1991-07-24  |  27.8 KB  |  1,135 lines

  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. #include "Xos.h"
  17. #include <sys/param.h>
  18. #include <sys/socket.h>
  19. #include <netinet/in.h>
  20. #include <netdb.h>
  21. #include <stdio.h>
  22. #include "X.h"
  23. #include "Xmd.h"
  24. #include "misc.h"
  25. #include "osdep.h"
  26. #include "input.h"
  27. #include "opaque.h"
  28.  
  29. #ifdef XDMCP
  30. #include "Xdmcp.h"
  31.  
  32. extern int argcGlobal;
  33. extern char **argvGlobal;
  34. extern char *display;
  35. extern long EnabledDevices[];
  36. extern long AllClients[];
  37. extern char *defaultDisplayClass;
  38.  
  39. static int            xdmcpSocket, sessionSocket;
  40. static xdmcp_states        state;
  41. static struct sockaddr_in   req_sockaddr;
  42. static int            req_socklen;
  43. static CARD32            SessionID;
  44. static long            timeOutTime;
  45. static int            timeOutRtx;
  46. static long            defaultKeepaliveDormancy = XDM_DEF_DORMANCY;
  47. static long            keepaliveDormancy = XDM_DEF_DORMANCY;
  48. static CARD16            DisplayNumber;
  49. static xdmcp_states        XDM_INIT_STATE = XDM_OFF;
  50. #ifdef HASXDMAUTH
  51. static char            *xdmAuthCookie;
  52. #endif
  53.  
  54. static XdmcpBuffer        buffer;
  55.  
  56. static struct sockaddr_in   ManagerAddress;
  57.  
  58. static get_manager_by_name(), get_xdmcp_sock();
  59.  
  60. static    receive_packet(), send_packet();
  61. static    timeout(), restart();
  62.  
  63. static    recv_willing_msg();
  64. static    recv_accept_msg(),    recv_decline_msg();
  65. static    recv_refuse_msg(),    recv_failed_msg();
  66. static    recv_alive_msg();
  67.  
  68. static    send_query_msg();
  69. static    send_request_msg();
  70. static    send_manage_msg();
  71. static    send_keepalive_msg();
  72.  
  73. static XdmcpFatal(), XdmcpWarning();
  74. static void XdmcpBlockHandler(), XdmcpWakeupHandler();
  75.  
  76. static short    xdm_udp_port = XDM_UDP_PORT;
  77. static Bool    OneSession = FALSE;
  78.  
  79. XdmcpUseMsg ()
  80. {
  81.     ErrorF("-query host-name       contact named host for XDMCP\n");
  82.     ErrorF("-broadcast             broadcast for XDMCP\n");
  83.     ErrorF("-indirect host-name    contact named host for indirect XDMCP\n");
  84.     ErrorF("-port port-num         UDP port number to send messages to\n");
  85.     ErrorF("-once                  Terminate server after one session\n");
  86.     ErrorF("-class display-class   specify display class to send in manage\n");
  87. #ifdef HASXDMAUTH
  88.     ErrorF("-cookie xdm-auth-bits  specify the magic cookie for XDMCP\n");
  89. #endif
  90.     ErrorF("-displayID display-id  manufacturer display ID for request\n");
  91. }
  92.  
  93. int 
  94. XdmcpOptions(argc, argv, i)
  95.     int        argc, i;
  96.     char    **argv;
  97. {
  98.     if (strcmp(argv[i], "-query") == 0) {
  99.     get_manager_by_name(argc, argv, ++i);
  100.     XDM_INIT_STATE = XDM_QUERY;
  101.     AccessUsingXdmcp ();
  102.     return (i + 1);
  103.     }
  104.     if (strcmp(argv[i], "-broadcast") == 0) {
  105.     XDM_INIT_STATE = XDM_BROADCAST;
  106.     AccessUsingXdmcp ();
  107.     return (i + 1);
  108.     }
  109.     if (strcmp(argv[i], "-indirect") == 0) {
  110.     get_manager_by_name(argc, argv, ++i);
  111.     XDM_INIT_STATE = XDM_INDIRECT;
  112.     AccessUsingXdmcp ();
  113.     return (i + 1);
  114.     }
  115.     if (strcmp(argv[i], "-port") == 0) {
  116.     ++i;
  117.     xdm_udp_port = atoi(argv[i]);
  118.     return (i + 1);
  119.     }
  120.     if (strcmp(argv[i], "-once") == 0) {
  121.     OneSession = TRUE;
  122.     return (i + 1);
  123.     }
  124.     if (strcmp(argv[i], "-class") == 0) {
  125.     ++i;
  126.     defaultDisplayClass = argv[i];
  127.     return (i + 1);
  128.     }
  129. #ifdef HASXDMAUTH
  130.     if (strcmp(argv[i], "-cookie") == 0) {
  131.     ++i;
  132.     xdmAuthCookie = argv[i];
  133.     return (i + 1);
  134.     }
  135. #endif
  136.     if (strcmp(argv[i], "-displayID") == 0) {
  137.     ++i;
  138.     XdmcpRegisterManufacturerDisplayID (argv[i], strlen (argv[i]));
  139.     return (i + 1);
  140.     }
  141.     return (i);
  142. }
  143.  
  144. /*
  145.  * This section is a collection of routines for
  146.  * registering server-specific data with the XDMCP
  147.  * state machine.
  148.  */
  149.  
  150.  
  151. /*
  152.  * Save all broadcast addresses away so BroadcastQuery
  153.  * packets get sent everywhere
  154.  */
  155.  
  156. #define MAX_BROADCAST    10
  157.  
  158. static struct sockaddr_in   BroadcastAddresses[MAX_BROADCAST];
  159. static int            NumBroadcastAddresses;
  160.  
  161. XdmcpRegisterBroadcastAddress (addr)
  162.     struct sockaddr_in    *addr;
  163. {
  164.     struct sockaddr_in    *bcast;
  165.     if (NumBroadcastAddresses >= MAX_BROADCAST)
  166.     return;
  167.     bcast = &BroadcastAddresses[NumBroadcastAddresses++];
  168.     bzero (bcast, sizeof (struct sockaddr_in));
  169.     bcast->sin_family = addr->sin_family;
  170.     bcast->sin_port = htons (xdm_udp_port);
  171.     bcast->sin_addr = addr->sin_addr;
  172. }
  173.  
  174. /*
  175.  * Each authentication type is registered here; Validator
  176.  * will be called to check all access attempts using
  177.  * the specified authentication type
  178.  */
  179.  
  180. static ARRAYofARRAY8    AuthenticationNames, AuthenticationDatas;
  181. typedef struct _AuthenticationFuncs {
  182.     Bool    (*Validator)();
  183.     Bool    (*Generator)();
  184.     Bool    (*AddAuth)();
  185. } AuthenticationFuncsRec, *AuthenticationFuncsPtr;
  186.  
  187. static AuthenticationFuncsPtr    AuthenticationFuncsList;
  188.  
  189. XdmcpRegisterAuthentication (name, namelen, data, datalen, Validator, Generator, AddAuth)
  190.     char    *name;
  191.     int        namelen;
  192.     char    *data;
  193.     int        datalen;
  194.     Bool    (*Validator)();
  195.     Bool    (*Generator)();
  196.     Bool    (*AddAuth)();
  197. {
  198.     int        i;
  199.     ARRAY8  AuthenticationName, AuthenticationData;
  200.     static AuthenticationFuncsPtr    newFuncs;
  201.  
  202.     if (!XdmcpAllocARRAY8 (&AuthenticationName, namelen))
  203.     return;
  204.     if (!XdmcpAllocARRAY8 (&AuthenticationData, datalen))
  205.     {
  206.     XdmcpDisposeARRAY8 (&AuthenticationName);
  207.     return;
  208.     }
  209.     for (i = 0; i < namelen; i++)
  210.     AuthenticationName.data[i] = name[i];
  211.     for (i = 0; i < datalen; i++)
  212.     AuthenticationData.data[i] = data[i];
  213.     if (!(XdmcpReallocARRAYofARRAY8 (&AuthenticationNames,
  214.                      AuthenticationNames.length + 1) &&
  215.       XdmcpReallocARRAYofARRAY8 (&AuthenticationDatas,
  216.                      AuthenticationDatas.length + 1) &&
  217.       (newFuncs = (AuthenticationFuncsPtr) xalloc (
  218.             (AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec)))))
  219.     {
  220.     XdmcpDisposeARRAY8 (&AuthenticationName);
  221.     XdmcpDisposeARRAY8 (&AuthenticationData);
  222.     return;
  223.     }
  224.     for (i = 0; i < AuthenticationNames.length - 1; i++)
  225.     newFuncs[i] = AuthenticationFuncsList[i];
  226.     newFuncs[AuthenticationNames.length-1].Validator = Validator;
  227.     newFuncs[AuthenticationNames.length-1].Generator = Generator;
  228.     newFuncs[AuthenticationNames.length-1].AddAuth = AddAuth;
  229.     xfree (AuthenticationFuncsList);
  230.     AuthenticationFuncsList = newFuncs;
  231.     AuthenticationNames.data[AuthenticationNames.length-1] = AuthenticationName;
  232.     AuthenticationDatas.data[AuthenticationDatas.length-1] = AuthenticationData;
  233. }
  234.  
  235. /*
  236.  * Select the authentication type to be used; this is
  237.  * set by the manager of the host to be connected to.
  238.  */
  239.  
  240. ARRAY8        noAuthenticationName = {(CARD16) 0, (CARD8Ptr) 0};
  241. ARRAY8        noAuthenticationData = {(CARD16) 0, (CARD8Ptr) 0};
  242. ARRAY8Ptr    AuthenticationName = &noAuthenticationName;
  243. ARRAY8Ptr    AuthenticationData = &noAuthenticationData;
  244. AuthenticationFuncsPtr    AuthenticationFuncs;
  245.  
  246. XdmcpSetAuthentication (name)
  247.     ARRAY8Ptr    name;
  248. {
  249.     int    i;
  250.  
  251.     XdmcpDisposeARRAY8 (AuthenticationName);
  252.     for (i = 0; i < AuthenticationNames.length; i++)
  253.     if (XdmcpARRAY8Equal (&AuthenticationNames.data[i], name))
  254.     {
  255.         AuthenticationName = &AuthenticationNames.data[i];
  256.         AuthenticationData = &AuthenticationDatas.data[i];
  257.         AuthenticationFuncs = &AuthenticationFuncsList[i];
  258.         break;
  259.     }
  260. }
  261.  
  262. /*
  263.  * Register the host address for the display
  264.  */
  265.  
  266. static ARRAY16        ConnectionTypes;
  267. static ARRAYofARRAY8    ConnectionAddresses;
  268. static long        xdmcpGeneration;
  269.  
  270. XdmcpRegisterConnection (type, address, addrlen)
  271.     int        type;
  272.     char    *address;
  273.     int        addrlen;
  274. {
  275.     int        i;
  276.     CARD8   *newAddress;
  277.  
  278.     if (xdmcpGeneration != serverGeneration)
  279.     {
  280.     XdmcpDisposeARRAY16 (&ConnectionTypes);
  281.     XdmcpDisposeARRAYofARRAY8 (&ConnectionAddresses);
  282.     xdmcpGeneration = serverGeneration;
  283.     }
  284.     newAddress = (CARD8 *) xalloc (addrlen * sizeof (CARD8));
  285.     if (!newAddress)
  286.     return;
  287.     if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1))
  288.     {
  289.     xfree (newAddress);
  290.     return;
  291.     }
  292.     if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses,
  293.                     ConnectionAddresses.length +  1))
  294.     {
  295.     xfree (newAddress);
  296.     return;
  297.     }
  298.     ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type;
  299.     for (i = 0; i < addrlen; i++)
  300.     newAddress[i] = address[i];
  301.     ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress;
  302.     ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen;
  303. }
  304.  
  305. /*
  306.  * Register an Authorization Name.  XDMCP advertises this list
  307.  * to the manager.
  308.  */
  309.  
  310. static ARRAYofARRAY8    AuthorizationNames;
  311.  
  312. XdmcpRegisterAuthorizations ()
  313. {
  314.     XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames);
  315.     RegisterAuthorizations ();
  316. }
  317.  
  318. XdmcpRegisterAuthorization (name, namelen)
  319.     char    *name;
  320.     int        namelen;
  321. {
  322.     ARRAY8  authName;
  323.     int        i;
  324.  
  325.     authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8));
  326.     if (!authName.data)
  327.     return;
  328.     if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1))
  329.     {
  330.     xfree (authName.data);
  331.     return;
  332.     }
  333.     for (i = 0; i < namelen; i++)
  334.     authName.data[i] = (CARD8) name[i];
  335.     authName.length = namelen;
  336.     AuthorizationNames.data[AuthorizationNames.length-1] = authName;
  337. }
  338.  
  339. /*
  340.  * Register the DisplayClass string
  341.  */
  342.  
  343. ARRAY8    DisplayClass;
  344.  
  345. XdmcpRegisterDisplayClass (name, length)
  346.     char    *name;
  347.     int        length;
  348. {
  349.     int        i;
  350.  
  351.     XdmcpDisposeARRAY8 (&DisplayClass);
  352.     if (!XdmcpAllocARRAY8 (&DisplayClass, length))
  353.     return;
  354.     for (i = 0; i < length; i++)
  355.     DisplayClass.data[i] = (CARD8) name[i];
  356. }
  357.  
  358. /*
  359.  * Register the Manufacturer display ID
  360.  */
  361.  
  362. ARRAY8 ManufacturerDisplayID;
  363.  
  364. XdmcpRegisterManufacturerDisplayID (name, length)
  365.     char    *name;
  366.     int        length;
  367. {
  368.     int        i;
  369.  
  370.     XdmcpDisposeARRAY8 (&ManufacturerDisplayID);
  371.     if (!XdmcpAllocARRAY8 (&ManufacturerDisplayID, length))
  372.     return;
  373.     for (i = 0; i < length; i++)
  374.     ManufacturerDisplayID.data[i] = (CARD8) name[i];
  375. }
  376.  
  377. /* 
  378.  * initialize XDMCP; create the socket, compute the display
  379.  * number, set up the state machine
  380.  */
  381.  
  382. void 
  383. XdmcpInit()
  384. {
  385.     state = XDM_INIT_STATE;
  386. #ifdef HASXDMAUTH
  387.     if (xdmAuthCookie)
  388.     XdmAuthenticationInit (xdmAuthCookie, strlen (xdmAuthCookie));
  389. #endif
  390.     if (state != XDM_OFF)
  391.     {
  392.     XdmcpRegisterAuthorizations();
  393.     XdmcpRegisterDisplayClass (defaultDisplayClass, strlen (defaultDisplayClass));
  394.     AccessUsingXdmcp();
  395.     RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
  396.                         (pointer) 0);
  397.         timeOutRtx = 0;
  398.         DisplayNumber = (CARD16) atoi(display);
  399.         get_xdmcp_sock();
  400.         send_packet();
  401.     }
  402. }
  403.  
  404. void
  405. XdmcpReset ()
  406. {
  407.     state = XDM_INIT_STATE;
  408.     if (state != XDM_OFF)
  409.     {
  410.     RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
  411.                         (pointer) 0);
  412.         timeOutRtx = 0;
  413.         send_packet();
  414.     }
  415. }
  416.  
  417. /*
  418.  * Called whenever a new connection is created; notices the
  419.  * first connection and saves it to terminate the session
  420.  * when it is closed
  421.  */
  422.  
  423. void
  424. XdmcpOpenDisplay(sock)
  425.     int    sock;
  426. {
  427.     extern void AugmentSelf();
  428.  
  429.     if (state != XDM_AWAIT_MANAGE_RESPONSE)
  430.     return;
  431.     state = XDM_RUN_SESSION;
  432.     sessionSocket = sock;
  433.     /* permit access control manipulations from this host */
  434.     AugmentSelf(sock);
  435. }
  436.  
  437. void 
  438. XdmcpCloseDisplay(sock)
  439.     int    sock;
  440. {
  441.     if ((state != XDM_RUN_SESSION && state != XDM_AWAIT_ALIVE_RESPONSE)
  442.     || sessionSocket != sock)
  443.         return;
  444.     state = XDM_INIT_STATE;
  445.     if (OneSession)
  446.     dispatchException |= DE_TERMINATE;
  447.     else
  448.     dispatchException |= DE_RESET;
  449.     isItTimeToYield = TRUE;
  450. }
  451.  
  452. /*
  453.  * called before going to sleep, this routine
  454.  * may modify the timeout value about to be sent
  455.  * to select; in this way XDMCP can do appropriate things
  456.  * dynamically while starting up
  457.  */
  458.  
  459. /*ARGSUSED*/
  460. static void
  461. XdmcpBlockHandler(data, wt, LastSelectMask)
  462.     pointer        data;   /* unused */
  463.     struct timeval  **wt;
  464.     long        *LastSelectMask;
  465. {
  466.     long millisToGo, wtMillis;
  467.     static struct timeval waittime;
  468.  
  469.     if (state == XDM_OFF)
  470.     return;
  471.     *LastSelectMask |= (1 << xdmcpSocket);
  472.     if (timeOutTime == 0)
  473.     return;
  474.     millisToGo = timeOutTime - GetTimeInMillis() + 1;
  475.     if (millisToGo < 0)
  476.     millisToGo = 0;
  477.     if (*wt == NULL)
  478.     {
  479.     waittime.tv_sec = (millisToGo) / 1000;
  480.     waittime.tv_usec = 1000 * (millisToGo % 1000);
  481.     *wt = &waittime;
  482.     }
  483.     else
  484.     {
  485.     wtMillis = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000;
  486.     if (millisToGo < wtMillis)
  487.      {
  488.         (*wt)->tv_sec = (millisToGo) / 1000;
  489.         (*wt)->tv_usec = 1000 * (millisToGo % 1000);
  490.     }
  491.     }
  492. }
  493.  
  494. /*
  495.  * called after select returns; this routine will
  496.  * recognise when XDMCP packets await and
  497.  * process them appropriately
  498.  */
  499.  
  500. /*ARGSUSED*/
  501. static void
  502. XdmcpWakeupHandler(data, i, LastSelectMask)
  503.     pointer data;   /* unused */
  504.     int        i;
  505.     long    *LastSelectMask;
  506. {
  507.     long    devicesReadable[mskcnt];
  508.  
  509.     if (state == XDM_OFF)
  510.     return;
  511.     if (i > 0)
  512.     {
  513.     if (GETBIT(LastSelectMask, xdmcpSocket))
  514.     {
  515.         receive_packet();
  516.         BITCLEAR(LastSelectMask, xdmcpSocket);
  517.     } 
  518.     MASKANDSETBITS(devicesReadable, LastSelectMask, EnabledDevices);
  519.     if (ANYSET(devicesReadable))
  520.     {
  521.         if (state == XDM_AWAIT_USER_INPUT)
  522.         restart();
  523.         else if (state == XDM_RUN_SESSION)
  524.         keepaliveDormancy = defaultKeepaliveDormancy;
  525.     }
  526.     if (ANYSET(AllClients) && state == XDM_RUN_SESSION)
  527.         timeOutTime = GetTimeInMillis() +  keepaliveDormancy * 1000;
  528.     }
  529.     else if (timeOutTime && GetTimeInMillis() >= timeOutTime)
  530.     {
  531.         if (state == XDM_RUN_SESSION)
  532.         {
  533.         state = XDM_KEEPALIVE;
  534.         send_packet();
  535.         }
  536.         else
  537.         timeout();
  538.     }
  539. }
  540.  
  541. /*
  542.  * This routine should be called from the routine that drives the
  543.  * user's host menu when the user selects a host
  544.  */
  545.  
  546. XdmcpSelectHost(host_sockaddr, host_len, AuthenticationName)
  547.     struct sockaddr_in    *host_sockaddr;
  548.     int            host_len;
  549.     ARRAY8Ptr        AuthenticationName;
  550. {
  551.     state = XDM_START_CONNECTION;
  552.     bcopy(host_sockaddr, &req_sockaddr, host_len);
  553.     req_socklen = host_len;
  554.     XdmcpSetAuthentication (AuthenticationName);
  555.     send_packet();
  556. }
  557.  
  558. /*
  559.  * !!! this routine should be replaced by a routine that adds
  560.  * the host to the user's host menu. the current version just
  561.  * selects the first host to respond with willing message.
  562.  */
  563.  
  564. /*ARGSUSED*/
  565. XdmcpAddHost(from, fromlen, AuthenticationName, hostname, status)
  566.     struct sockaddr_in  *from;
  567.     ARRAY8Ptr        AuthenticationName, hostname, status;
  568. {
  569.     XdmcpSelectHost(from, fromlen, AuthenticationName);
  570. }
  571.  
  572. /*
  573.  * A message is queued on the socket; read it and
  574.  * do the appropriate thing
  575.  */
  576.  
  577. ARRAY8    UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" };
  578.  
  579. static
  580. receive_packet()
  581. {
  582.     struct sockaddr_in from;
  583.     int fromlen = sizeof(struct sockaddr_in);
  584.     XdmcpHeader    header;
  585.  
  586.     /* read message off socket */
  587.     if (!XdmcpFill (xdmcpSocket, &buffer, (struct sockaddr *) &from, &fromlen))
  588.     return;
  589.  
  590.     /* reset retransmission backoff */
  591.     timeOutRtx = 0;
  592.  
  593.     if (!XdmcpReadHeader (&buffer, &header))
  594.     return;
  595.  
  596.     if (header.version != XDM_PROTOCOL_VERSION)
  597.     return;
  598.  
  599.     switch (header.opcode) {
  600.     case WILLING:
  601.     recv_willing_msg(&from, fromlen, header.length);
  602.     break;
  603.     case UNWILLING:
  604.     XdmcpFatal("Manager unwilling", &UnwillingMessage);
  605.     break;
  606.     case ACCEPT:
  607.     recv_accept_msg(header.length);
  608.     break;
  609.     case DECLINE:
  610.     recv_decline_msg(header.length);
  611.     break;
  612.     case REFUSE:
  613.     recv_refuse_msg(header.length);
  614.     break;
  615.     case FAILED:
  616.     recv_failed_msg(header.length);
  617.     break;
  618.     case ALIVE:
  619.     recv_alive_msg(header.length);
  620.     break;
  621.     }
  622. }
  623.  
  624. /*
  625.  * send the appropriate message given the current state
  626.  */
  627.  
  628. static
  629. send_packet()
  630. {
  631.     int rtx;
  632.     switch (state) {
  633.     case XDM_QUERY:
  634.     case XDM_BROADCAST:
  635.     case XDM_INDIRECT:
  636.     send_query_msg();
  637.     break;
  638.     case XDM_START_CONNECTION:
  639.     send_request_msg();
  640.     break;
  641.     case XDM_MANAGE:
  642.     send_manage_msg();
  643.     break;
  644.     case XDM_KEEPALIVE:
  645.     send_keepalive_msg();
  646.     break;
  647.     }
  648.     rtx = (XDM_MIN_RTX << timeOutRtx);
  649.     if (rtx > XDM_MAX_RTX)
  650.     rtx = XDM_MAX_RTX;
  651.     timeOutTime = GetTimeInMillis() + rtx * 1000;
  652. }
  653.  
  654. /*
  655.  * The session is declared dead for some reason; too many
  656.  * timeouts, or Keepalive failure.
  657.  */
  658.  
  659. XdmcpDeadSession (reason)
  660.     char *reason;
  661. {
  662.     printf ("XDM: %s, declaring session dead\n", reason);
  663.     state = XDM_INIT_STATE;
  664.     isItTimeToYield = TRUE;
  665.     dispatchException |= DE_RESET;
  666.     timeOutTime = 0;
  667.     timeOutRtx = 0;
  668.     send_packet();
  669. }
  670.  
  671. /*
  672.  * Timeout waiting for an XDMCP response.
  673.  */
  674.  
  675. static 
  676. timeout()
  677. {
  678.     timeOutRtx++;
  679.     if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT )
  680.     {
  681.     XdmcpDeadSession ("too many keepalive retransmissions");
  682.     return;
  683.     }
  684.     else if (timeOutRtx >= XDM_RTX_LIMIT)
  685.     {
  686.     printf("XDM: too many retransmissions\n");
  687.     state = XDM_AWAIT_USER_INPUT;
  688.     timeOutTime = 0;
  689.     timeOutRtx = 0;
  690.     return;
  691.     }
  692.  
  693.     switch (state) {
  694.     case XDM_COLLECT_QUERY:
  695.     state = XDM_QUERY;
  696.     break;
  697.     case XDM_COLLECT_BROADCAST_QUERY:
  698.     state = XDM_BROADCAST;
  699.     break;
  700.     case XDM_COLLECT_INDIRECT_QUERY:
  701.     state = XDM_INDIRECT;
  702.     break;
  703.     case XDM_AWAIT_REQUEST_RESPONSE:
  704.     state = XDM_START_CONNECTION;
  705.     break;
  706.     case XDM_AWAIT_MANAGE_RESPONSE:
  707.     state = XDM_MANAGE;
  708.     break;
  709.     case XDM_AWAIT_ALIVE_RESPONSE:
  710.     state = XDM_KEEPALIVE;
  711.     break;
  712.     }
  713.     send_packet();
  714. }
  715.  
  716. static
  717. restart()
  718. {
  719.     state = XDM_INIT_STATE;
  720.     timeOutRtx = 0;
  721.     send_packet();
  722. }
  723.  
  724. XdmcpCheckAuthentication (Name, Data, packet_type)
  725.     ARRAY8Ptr    Name, Data;
  726.     int    packet_type;
  727. {
  728.     return (XdmcpARRAY8Equal (Name, AuthenticationName) &&
  729.         (AuthenticationName->length == 0 ||
  730.          (*AuthenticationFuncs->Validator) (AuthenticationData, Data, packet_type)));
  731. }
  732.  
  733. XdmcpAddAuthorization (name, data)
  734.     ARRAY8Ptr    name, data;
  735. {
  736.     Bool    (*AddAuth)(), AddAuthorization();
  737.  
  738.     if (AuthenticationFuncs && AuthenticationFuncs->AddAuth)
  739.     AddAuth = AuthenticationFuncs->AddAuth;
  740.     else
  741.     AddAuth = AddAuthorization;
  742.     return (*AddAuth) ((unsigned short)name->length,
  743.                (char *)name->data,
  744.                (unsigned short)data->length,
  745.                (char *)data->data);
  746. }
  747.  
  748. /*
  749.  * from here to the end of this file are routines private
  750.  * to the state machine.
  751.  */
  752.  
  753. static
  754. get_xdmcp_sock()
  755. {
  756.     int soopts = 1;
  757.  
  758.     if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  759.     XdmcpWarning("UDP socket creation failed");
  760. #ifdef SO_BROADCAST
  761.     else if (setsockopt(xdmcpSocket, SOL_SOCKET, SO_BROADCAST, &soopts,
  762.     sizeof(soopts)) < 0)
  763.         XdmcpWarning("UDP set broadcast socket-option failed");
  764. #endif /* SO_BROADCAST */
  765. }
  766.  
  767. static
  768. send_query_msg()
  769. {
  770.     XdmcpHeader    header;
  771.     Bool    broadcast = FALSE;
  772.     int        i;
  773.  
  774.     header.version = XDM_PROTOCOL_VERSION;
  775.     switch(state){
  776.     case XDM_QUERY:
  777.     header.opcode = (CARD16) QUERY; 
  778.     state = XDM_COLLECT_QUERY;
  779.     break;
  780.     case XDM_BROADCAST:
  781.     header.opcode = (CARD16) BROADCAST_QUERY;
  782.     state = XDM_COLLECT_BROADCAST_QUERY;
  783.     broadcast = TRUE;
  784.     break;
  785.     case XDM_INDIRECT:
  786.     header.opcode = (CARD16) INDIRECT_QUERY;
  787.     state = XDM_COLLECT_INDIRECT_QUERY;
  788.     break;
  789.     }
  790.     header.length = 1;
  791.     for (i = 0; i < AuthenticationNames.length; i++)
  792.     header.length += 2 + AuthenticationNames.data[i].length;
  793.  
  794.     XdmcpWriteHeader (&buffer, &header);
  795.     XdmcpWriteARRAYofARRAY8 (&buffer, &AuthenticationNames);
  796.     if (broadcast)
  797.     {
  798.     int i;
  799.  
  800.     for (i = 0; i < NumBroadcastAddresses; i++)
  801.         XdmcpFlush (xdmcpSocket, &buffer, &BroadcastAddresses[i],
  802.             sizeof (struct sockaddr_in));
  803.     }
  804.     else
  805.     {
  806.     XdmcpFlush (xdmcpSocket, &buffer, &ManagerAddress,
  807.             sizeof (ManagerAddress));
  808.     }
  809. }
  810.  
  811. static
  812. recv_willing_msg(from, fromlen, length)
  813.     struct sockaddr_in    *from;
  814.     int            fromlen;
  815.     unsigned        length;
  816. {
  817.     ARRAY8    authenticationName;
  818.     ARRAY8    hostname;
  819.     ARRAY8    status;
  820.  
  821.     authenticationName.data = 0;
  822.     hostname.data = 0;
  823.     status.data = 0;
  824.     if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
  825.     XdmcpReadARRAY8 (&buffer, &hostname) &&
  826.     XdmcpReadARRAY8 (&buffer, &status))
  827.     {
  828.         if (length == 6 + authenticationName.length +
  829.               hostname.length + status.length)
  830.         {
  831.         switch (state)
  832.         {
  833.         case XDM_COLLECT_QUERY:
  834.             XdmcpSelectHost(from, fromlen, &authenticationName);
  835.             break;
  836.         case XDM_COLLECT_BROADCAST_QUERY:
  837.         case XDM_COLLECT_INDIRECT_QUERY:
  838.             XdmcpAddHost(from, fromlen, &authenticationName, &hostname, &status);
  839.             break;
  840.             }
  841.         }
  842.     }
  843.     XdmcpDisposeARRAY8 (&authenticationName);
  844.     XdmcpDisposeARRAY8 (&hostname);
  845.     XdmcpDisposeARRAY8 (&status);
  846. }
  847.  
  848. static
  849. send_request_msg()
  850. {
  851.     XdmcpHeader        header;
  852.     int            length;
  853.     int            i;
  854.     ARRAY8        authenticationData;
  855.  
  856.     header.version = XDM_PROTOCOL_VERSION;
  857.     header.opcode = (CARD16) REQUEST;
  858.  
  859.     length = 2;                        /* display number */
  860.     length += 1 + 2 * ConnectionTypes.length;        /* connection types */
  861.     length += 1;                    /* connection addresses */
  862.     for (i = 0; i < ConnectionAddresses.length; i++)
  863.     length += 2 + ConnectionAddresses.data[i].length;
  864.     authenticationData.length = 0;
  865.     authenticationData.data = 0;
  866.     if (AuthenticationFuncs)
  867.     {
  868.     (*AuthenticationFuncs->Generator) (AuthenticationData,
  869.                        &authenticationData,
  870.                         REQUEST);
  871.     }
  872.     length += 2 + AuthenticationName->length;        /* authentication name */
  873.     length += 2 + authenticationData.length;        /* authentication data */
  874.     length += 1;                    /* authorization names */
  875.     for (i = 0; i < AuthorizationNames.length; i++)
  876.     length += 2 + AuthorizationNames.data[i].length;
  877.     length += 2 + ManufacturerDisplayID.length;        /* display ID */
  878.     header.length = length;
  879.  
  880.     if (!XdmcpWriteHeader (&buffer, &header))
  881.     {
  882.     XdmcpDisposeARRAY8 (&authenticationData);
  883.     return;
  884.     }
  885.     XdmcpWriteCARD16 (&buffer, DisplayNumber);
  886.     XdmcpWriteARRAY16 (&buffer, &ConnectionTypes);
  887.     XdmcpWriteARRAYofARRAY8 (&buffer, &ConnectionAddresses);
  888.  
  889.     XdmcpWriteARRAY8 (&buffer, AuthenticationName);
  890.     XdmcpWriteARRAY8 (&buffer, &authenticationData);
  891.     XdmcpDisposeARRAY8 (&authenticationData);
  892.     XdmcpWriteARRAYofARRAY8 (&buffer, &AuthorizationNames);
  893.     XdmcpWriteARRAY8 (&buffer, &ManufacturerDisplayID);
  894.     if (XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen))
  895.     state = XDM_AWAIT_REQUEST_RESPONSE;
  896. }
  897.  
  898. static
  899. recv_accept_msg(length)
  900.     unsigned        length;
  901. {
  902.     CARD32  AcceptSessionID;
  903.     ARRAY8  AcceptAuthenticationName, AcceptAuthenticationData;
  904.     ARRAY8  AcceptAuthorizationName, AcceptAuthorizationData;
  905.  
  906.     if (state != XDM_AWAIT_REQUEST_RESPONSE)
  907.     return;
  908.     AcceptAuthenticationName.data = 0;
  909.     AcceptAuthenticationData.data = 0;
  910.     AcceptAuthorizationName.data = 0;
  911.     AcceptAuthorizationData.data = 0;
  912.     if (XdmcpReadCARD32 (&buffer, &AcceptSessionID) &&
  913.     XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationName) &&
  914.     XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationData) &&
  915.     XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationName) &&
  916.     XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationData))
  917.     {
  918.         if (length == 12 + AcceptAuthenticationName.length +
  919.                      AcceptAuthenticationData.length +
  920.                      AcceptAuthorizationName.length +
  921.                       AcceptAuthorizationData.length)
  922.         {
  923.         if (!XdmcpCheckAuthentication (&AcceptAuthenticationName,
  924.                       &AcceptAuthenticationData, ACCEPT))
  925.         {
  926.         XdmcpFatal ("Authentication Failure", &AcceptAuthenticationName);
  927.         }
  928.         /* if the authorization specified in the packet fails
  929.          * to be acceptable, enable the local addresses
  930.          */
  931.         if (!XdmcpAddAuthorization (&AcceptAuthorizationName,
  932.                     &AcceptAuthorizationData))
  933.         {
  934.         AddLocalHosts ();
  935.         }
  936.         SessionID = AcceptSessionID;
  937.             state = XDM_MANAGE;
  938.             send_packet();
  939.         }
  940.     }
  941.     XdmcpDisposeARRAY8 (&AcceptAuthenticationName);
  942.     XdmcpDisposeARRAY8 (&AcceptAuthenticationData);
  943.     XdmcpDisposeARRAY8 (&AcceptAuthorizationName);
  944.     XdmcpDisposeARRAY8 (&AcceptAuthorizationData);
  945. }
  946.  
  947. static
  948. recv_decline_msg(length)
  949.     unsigned        length;
  950. {
  951.     ARRAY8  Status, DeclineAuthenticationName, DeclineAuthenticationData;
  952.  
  953.     Status.data = 0;
  954.     DeclineAuthenticationName.data = 0;
  955.     DeclineAuthenticationData.data = 0;
  956.     if (XdmcpReadARRAY8 (&buffer, &Status) &&
  957.     XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationName) &&
  958.     XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationData))
  959.     {
  960.         if (length == 6 + Status.length +
  961.                     DeclineAuthenticationName.length +
  962.                      DeclineAuthenticationData.length &&
  963.         XdmcpCheckAuthentication (&DeclineAuthenticationName,
  964.                       &DeclineAuthenticationData, DECLINE))
  965.         {
  966.         XdmcpFatal ("Session declined", &Status);
  967.         }
  968.     }
  969.     XdmcpDisposeARRAY8 (&Status);
  970.     XdmcpDisposeARRAY8 (&DeclineAuthenticationName);
  971.     XdmcpDisposeARRAY8 (&DeclineAuthenticationData);
  972. }
  973.  
  974. static
  975. send_manage_msg()
  976. {
  977.     XdmcpHeader    header;
  978.  
  979.     header.version = XDM_PROTOCOL_VERSION;
  980.     header.opcode = (CARD16) MANAGE;
  981.     header.length = 8 + DisplayClass.length;
  982.  
  983.     if (!XdmcpWriteHeader (&buffer, &header))
  984.     return;
  985.     XdmcpWriteCARD32 (&buffer, SessionID);
  986.     XdmcpWriteCARD16 (&buffer, DisplayNumber);
  987.     XdmcpWriteARRAY8 (&buffer, &DisplayClass);
  988.     state = XDM_AWAIT_MANAGE_RESPONSE;
  989.     XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen);
  990. }
  991.  
  992. static
  993. recv_refuse_msg(length)
  994.     unsigned        length;
  995. {
  996.     CARD32  RefusedSessionID;
  997.  
  998.     if (state != XDM_AWAIT_MANAGE_RESPONSE)
  999.     return;
  1000.     if (length != 4)
  1001.     return;
  1002.     if (XdmcpReadCARD32 (&buffer, &RefusedSessionID))
  1003.     {
  1004.     if (RefusedSessionID == SessionID)
  1005.     {
  1006.             state = XDM_START_CONNECTION;
  1007.             send_packet();
  1008.     }
  1009.     }
  1010. }
  1011.  
  1012. static
  1013. recv_failed_msg(length)
  1014.     unsigned        length;
  1015. {
  1016.     CARD32  FailedSessionID;
  1017.     ARRAY8  Status;
  1018.  
  1019.     if (state != XDM_AWAIT_MANAGE_RESPONSE)
  1020.     return;
  1021.     Status.data = 0;
  1022.     if (XdmcpReadCARD32 (&buffer, &FailedSessionID) &&
  1023.     XdmcpReadARRAY8 (&buffer, &Status))
  1024.     {
  1025.         if (length == 5 + Status.length &&
  1026.         SessionID == FailedSessionID)
  1027.     {
  1028.         XdmcpFatal ("Session failed", &Status);
  1029.     }
  1030.     }
  1031.     XdmcpDisposeARRAY8 (&Status);
  1032. }
  1033.  
  1034. static
  1035. send_keepalive_msg()
  1036. {
  1037.     XdmcpHeader    header;
  1038.  
  1039.     header.version = XDM_PROTOCOL_VERSION;
  1040.     header.opcode = (CARD16) KEEPALIVE;
  1041.     header.length = 6;
  1042.  
  1043.     XdmcpWriteHeader (&buffer, &header);
  1044.     XdmcpWriteCARD16 (&buffer, DisplayNumber);
  1045.     XdmcpWriteCARD32 (&buffer, SessionID);
  1046.  
  1047.     state = XDM_AWAIT_ALIVE_RESPONSE;
  1048.     XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen);
  1049. }
  1050.  
  1051. static
  1052. recv_alive_msg (length)
  1053.     unsigned        length;
  1054. {
  1055.     CARD8   SessionRunning;
  1056.     CARD32  AliveSessionID;
  1057.     int        dormancy;
  1058.  
  1059.     if (state != XDM_AWAIT_ALIVE_RESPONSE)
  1060.     return;
  1061.     if (length != 5)
  1062.     return;
  1063.     if (XdmcpReadCARD8 (&buffer, &SessionRunning) &&
  1064.     XdmcpReadCARD32 (&buffer, &AliveSessionID))
  1065.     {
  1066.         if (SessionRunning && AliveSessionID == SessionID)
  1067.         {
  1068.         /* backoff dormancy period */
  1069.         state = XDM_RUN_SESSION;
  1070.         if (TimeSinceLastInputEvent() > keepaliveDormancy * 1000)
  1071.         {
  1072.         keepaliveDormancy <<= 1;
  1073.         if (keepaliveDormancy > XDM_MAX_DORMANCY)
  1074.             keepaliveDormancy = XDM_MAX_DORMANCY;
  1075.         }
  1076.         timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
  1077.         }
  1078.     else
  1079.         {
  1080.         XdmcpDeadSession ("Alive respose indicates session dead");
  1081.         }
  1082.     }
  1083. }
  1084.  
  1085. static 
  1086. XdmcpFatal (type, status)
  1087.     char    *type;
  1088.     ARRAY8Ptr    status;
  1089. {
  1090.     extern void AbortDDX();
  1091.  
  1092.     printf("XDMCP fatal error: %s %*.*s\n", type,
  1093.        status->length, status->length, status->data);
  1094.     AbortDDX ();
  1095.     exit (1);
  1096. }
  1097.  
  1098. static 
  1099. XdmcpWarning(str)
  1100.     char *str;
  1101. {
  1102.     printf("XDMCP warning: %s\n", str);
  1103. }
  1104.  
  1105. static
  1106. get_manager_by_name(argc, argv, i)
  1107.     int        argc, i;
  1108.     char    **argv;
  1109. {
  1110.     struct hostent *hep;
  1111.  
  1112.     if (i == argc)
  1113.     {
  1114.     printf("Xserver: missing host name in command line\n");
  1115.     exit(1);
  1116.     }
  1117.     if (!(hep = gethostbyname(argv[i])))
  1118.     {
  1119.     printf("Xserver: unknown host: %s\n", argv[i]);
  1120.     exit(1);
  1121.     }
  1122.     if (hep->h_length == sizeof (struct in_addr))
  1123.     {
  1124.     bcopy(hep->h_addr, &ManagerAddress.sin_addr, hep->h_length);
  1125.     ManagerAddress.sin_family = AF_INET;
  1126.     ManagerAddress.sin_port = htons (xdm_udp_port);
  1127.     }
  1128.     else
  1129.     {
  1130.     printf ("Xserver: host on strange network %s\n", argv[i]);
  1131.     exit (1);
  1132.     }
  1133. }
  1134. #endif /* XDMCP */
  1135.