home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / server / os / xdmcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  27.9 KB  |  1,136 lines

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