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

  1. /*
  2.  * xdm - display manager daemon
  3.  *
  4.  * $XConsortium: xdmcp.c,v 1.6 92/03/24 10:30:37 gildea Exp $
  5.  *
  6.  * Copyright 1988 Massachusetts Institute of Technology
  7.  *
  8.  * Permission to use, copy, modify, and distribute this software and its
  9.  * documentation for any purpose and without fee is hereby granted, provided
  10.  * that the above copyright notice appear in all copies and that both that
  11.  * copyright notice and this permission notice appear in supporting
  12.  * documentation, and that the name of M.I.T. not be used in advertising or
  13.  * publicity pertaining to distribution of the software without specific,
  14.  * written prior permission.  M.I.T. makes no representations about the
  15.  * suitability of this software for any purpose.  It is provided "as is"
  16.  * without express or implied warranty.
  17.  *
  18.  * Author:  Keith Packard, MIT X Consortium
  19.  */
  20.  
  21. /*
  22.  * xdmcp.c - Support for XDMCP
  23.  */
  24.  
  25. # include "dm.h"
  26.  
  27. #ifdef XDMCP
  28.  
  29. # include    <X11/X.h>
  30. # include    <X11/Xfuncs.h>
  31. # include    <sys/types.h>
  32. # include    <ctype.h>
  33.  
  34. #include    <sys/socket.h>
  35. #include    <netinet/in.h>
  36. #include    <sys/un.h>
  37. #include    <netdb.h>
  38.  
  39. #define getString(name,len)    ((name = malloc (len + 1)) ? 1 : 0)
  40.  
  41. /*
  42.  * interface to policy routines
  43.  */
  44.  
  45. extern ARRAY8Ptr    ChooseAuthentication ();
  46. extern int        Willing ();
  47. extern ARRAY8Ptr    Accept ();
  48. extern int        SelectConnectionTypeIndex ();
  49.  
  50. int    xdmcpFd = -1;
  51. int    chooserFd = -1;
  52.  
  53. FD_TYPE    WellKnownSocketsMask;
  54. int    WellKnownSocketsMax;
  55.  
  56. #define pS(s)    ((s) ? ((char *) (s)) : "empty string")
  57.  
  58. DestroyWellKnownSockets ()
  59. {
  60.     if (xdmcpFd != -1)
  61.     {
  62.     close (xdmcpFd);
  63.     xdmcpFd = -1;
  64.     }
  65.     if (chooserFd != -1)
  66.     {
  67.     close (chooserFd);
  68.     chooserFd = -1;
  69.     }
  70. }
  71.  
  72. AnyWellKnownSockets ()
  73. {
  74.     return xdmcpFd != -1 || chooserFd != -1;
  75. }
  76.  
  77. WaitForSomething ()
  78. {
  79.     FD_TYPE    reads;
  80.     int    nready;
  81.     extern int Rescan, ChildReady;
  82.  
  83.     Debug ("WaitForSomething\n");
  84.     if (AnyWellKnownSockets () && !ChildReady) {
  85.     reads = WellKnownSocketsMask;
  86.     nready = select (WellKnownSocketsMax + 1, &reads, 0, 0, 0);
  87.     Debug ("select returns %d.  Rescan: %d  ChildReady: %d\n",
  88.         nready, Rescan, ChildReady);
  89.     if (nready > 0)
  90.     {
  91.         if (xdmcpFd >= 0 && FD_ISSET (xdmcpFd, &reads))
  92.         ProcessRequestSocket ();
  93.         if (chooserFd >= 0 && FD_ISSET (chooserFd, &reads))
  94.         ProcessChooserSocket (chooserFd);
  95.     }
  96.     if (ChildReady)
  97.     {
  98.         WaitForChild ();
  99.     }
  100.     } else
  101.     WaitForChild ();
  102. }
  103.  
  104. /*
  105.  * respond to a request on the UDP socket.
  106.  */
  107.  
  108. static ARRAY8    Hostname;
  109.  
  110. registerHostname (name, namelen)
  111.     char    *name;
  112.     int        namelen;
  113. {
  114.     int    i;
  115.  
  116.     if (!XdmcpReallocARRAY8 (&Hostname, namelen))
  117.     return;
  118.     for (i = 0; i < namelen; i++)
  119.     Hostname.data[i] = name[i];
  120. }
  121.  
  122. static XdmcpBuffer    buffer;
  123.  
  124. ProcessRequestSocket ()
  125. {
  126.     XdmcpHeader        header;
  127.     struct sockaddr_in    addr;
  128.     int            addrlen = sizeof addr;
  129.  
  130.     Debug ("ProcessRequestSocket\n");
  131.     bzero ((char *) &addr, sizeof (addr));
  132.     if (!XdmcpFill (xdmcpFd, &buffer, &addr, &addrlen)) {
  133.     Debug ("XdmcpFill failed\n");
  134.     return;
  135.     }
  136.     if (!XdmcpReadHeader (&buffer, &header)) {
  137.     Debug ("XdmcpReadHeader failed\n");
  138.     return;
  139.     }
  140.     if (header.version != XDM_PROTOCOL_VERSION) {
  141.     Debug ("XDMCP header version read was %d, expected %d\n",
  142.            header.version, XDM_PROTOCOL_VERSION);
  143.     return;
  144.     }
  145.     Debug ("header: %d %d %d\n", header.version, header.opcode, header.length);
  146.     switch (header.opcode)
  147.     {
  148.     case BROADCAST_QUERY:
  149.     broadcast_respond (&addr, addrlen, header.length);
  150.     break;
  151.     case QUERY:
  152.     query_respond (&addr, addrlen, header.length);
  153.     break;
  154.     case INDIRECT_QUERY:
  155.     indirect_respond (&addr, addrlen, header.length);
  156.     break;
  157.     case FORWARD_QUERY:
  158.     forward_respond (&addr, addrlen, header.length);
  159.     break;
  160.     case REQUEST:
  161.     request_respond (&addr, addrlen, header.length);
  162.     break;
  163.     case MANAGE:
  164.     manage (&addr, addrlen, header.length);
  165.     break;
  166.     case KEEPALIVE:
  167.     send_alive (&addr, addrlen, header.length);
  168.     break;
  169.     }
  170. }
  171.  
  172. query_respond (from, fromlen, length)
  173.     struct sockaddr *from;
  174.     int            fromlen;
  175.     int            length;
  176. {
  177.     Debug ("Query respond %d\n", length);
  178.     direct_query_respond (from, fromlen, length, QUERY);
  179. }
  180.  
  181. broadcast_respond (from, fromlen, length)
  182.     struct sockaddr *from;
  183.     int            fromlen;
  184.     int            length;
  185. {
  186.     direct_query_respond (from, fromlen, length, BROADCAST_QUERY);
  187. }
  188.  
  189. direct_query_respond (from, fromlen, length, type)
  190.     struct sockaddr *from;
  191.     int            fromlen;
  192.     int            length;
  193.     xdmOpCode        type;
  194. {
  195.     ARRAYofARRAY8   queryAuthenticationNames;
  196.     int            expectedLen;
  197.     int            i;
  198.     
  199.     if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames))
  200.     return;
  201.     expectedLen = 1;
  202.     for (i = 0; i < (int)queryAuthenticationNames.length; i++)
  203.     expectedLen += 2 + queryAuthenticationNames.data[i].length;
  204.     if (length == expectedLen)
  205.     all_query_respond (from, fromlen, &queryAuthenticationNames, type);
  206.     XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames);
  207. }
  208.  
  209. /*ARGSUSED*/
  210. static int
  211. sendForward (connectionType, address, closure)
  212.     CARD16    connectionType;
  213.     ARRAY8Ptr    address;
  214.     char    *closure;
  215. {
  216. #ifdef AF_INET
  217.     struct sockaddr_in        in_addr;
  218. #endif
  219. #ifdef AF_DECnet
  220. #endif
  221.     struct sockaddr        *addr;
  222.     int                addrlen;
  223.  
  224.     switch (connectionType)
  225.     {
  226. #ifdef AF_INET
  227.     case FamilyInternet:
  228.     addr = (struct sockaddr *) &in_addr;
  229.     bzero ((char *) &in_addr, sizeof (in_addr));
  230.     in_addr.sin_family = AF_INET;
  231.     in_addr.sin_port = htons ((short) XDM_UDP_PORT);
  232.     if (address->length != 4)
  233.         return;
  234.     bcopy (address->data, (char *) &in_addr.sin_addr, address->length);
  235.     addrlen = sizeof (struct sockaddr_in);
  236.     break;
  237. #endif
  238. #ifdef AF_DECnet
  239.     case FamilyDECnet:
  240. #endif
  241.     default:
  242.     return;
  243.     }
  244.     XdmcpFlush (xdmcpFd, &buffer, addr, addrlen);
  245. }
  246.  
  247. extern char *NetaddrAddress();
  248. extern char *NetaddrPort();
  249.  
  250. static void
  251. ClientAddress (from, addr, port, type)
  252.     struct sockaddr *from;
  253.     ARRAY8Ptr        addr, port;    /* return */
  254.     CARD16        *type;    /* return */
  255. {
  256.     int length, family;
  257.     char *data;
  258.  
  259.     data = NetaddrPort(from, &length);
  260.     XdmcpAllocARRAY8 (port, length);
  261.     bcopy (data, port->data, length);
  262.     port->length = length;
  263.  
  264.     family = ConvertAddr(from, &length, &data);
  265.     XdmcpAllocARRAY8 (addr, length);
  266.     bcopy (data, addr->data, length);
  267.     addr->length = length;
  268.  
  269.     *type = family;
  270. }
  271.  
  272. /* computes an X display name */
  273.  
  274. static char *
  275. NetworkAddressToName(connectionType, connectionAddress, displayNumber)
  276.     CARD16    connectionType;
  277.     ARRAY8Ptr   connectionAddress;
  278.     CARD16    displayNumber;
  279. {
  280.     switch (connectionType)
  281.     {
  282.     case FamilyInternet:
  283.     {
  284.         CARD8        *data;
  285.         struct hostent    *hostent;
  286.         char        *name;
  287.         char        *localhost, *localHostname();
  288.  
  289.         data = connectionAddress->data;
  290.         hostent = gethostbyaddr ((char *)data,
  291.                      connectionAddress->length, AF_INET);
  292.  
  293.         localhost = localHostname ();
  294.  
  295.         if (hostent)
  296.         {
  297.         if (!strcmp (localhost, hostent->h_name))
  298.         {
  299.             if (!getString (name, 10))
  300.             return 0;
  301.             sprintf (name, ":%d", displayNumber);
  302.         }
  303.         else
  304.         {
  305.             if (removeDomainname)
  306.             {
  307.                 char    *localDot, *remoteDot;
  308.     
  309.             /* check for a common domain name.  This
  310.              * could reduce names by recognising common
  311.              * super-domain names as well, but I don't think
  312.              * this is as useful, and will confuse more
  313.              * people
  314.               */
  315.                 if ((localDot = index (localhost, '.')) &&
  316.                     (remoteDot = index (hostent->h_name, '.')))
  317.             {
  318.                 /* smash the name in place; it won't
  319.                  * be needed later.
  320.                  */
  321.                 if (!strcmp (localDot+1, remoteDot+1))
  322.                 *remoteDot = '\0';
  323.             }
  324.             }
  325.  
  326.             if (!getString (name, strlen (hostent->h_name) + 10))
  327.             return 0;
  328.             sprintf (name, "%s:%d", hostent->h_name, displayNumber);
  329.         }
  330.         }
  331.         else
  332.         {
  333.         if (!getString (name, 25))
  334.             return 0;
  335.         sprintf(name, "%d.%d.%d.%d:%d",
  336.             data[0], data[1], data[2], data[3], displayNumber);
  337.         }
  338.         return name;
  339.     }
  340. #ifdef DNET
  341.     case FamilyDECnet:
  342.     return NULL;
  343. #endif /* DNET */
  344.     default:
  345.     return NULL;
  346.     }
  347. }
  348.  
  349. indirect_respond (from, fromlen, length)
  350.     struct sockaddr *from;
  351.     int            fromlen;
  352.     int            length;
  353. {
  354.     ARRAYofARRAY8   queryAuthenticationNames;
  355.     ARRAY8        clientAddress;
  356.     ARRAY8        clientPort;
  357.     CARD16        connectionType;
  358.     int            expectedLen;
  359.     int            i;
  360.     XdmcpHeader        header;
  361.     int            localHostAsWell;
  362.     
  363.     Debug ("Indirect respond %d\n", length);
  364.     if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames))
  365.     return;
  366.     expectedLen = 1;
  367.     for (i = 0; i < (int)queryAuthenticationNames.length; i++)
  368.     expectedLen += 2 + queryAuthenticationNames.data[i].length;
  369.     if (length == expectedLen)
  370.     {
  371.     ClientAddress (from, &clientAddress, &clientPort, &connectionType);
  372.     /*
  373.      * set up the forward query packet
  374.      */
  375.         header.version = XDM_PROTOCOL_VERSION;
  376.         header.opcode = (CARD16) FORWARD_QUERY;
  377.         header.length = 0;
  378.         header.length += 2 + clientAddress.length;
  379.         header.length += 2 + clientPort.length;
  380.         header.length += 1;
  381.         for (i = 0; i < (int)queryAuthenticationNames.length; i++)
  382.         header.length += 2 + queryAuthenticationNames.data[i].length;
  383.         XdmcpWriteHeader (&buffer, &header);
  384.         XdmcpWriteARRAY8 (&buffer, &clientAddress);
  385.         XdmcpWriteARRAY8 (&buffer, &clientPort);
  386.         XdmcpWriteARRAYofARRAY8 (&buffer, &queryAuthenticationNames);
  387.  
  388.     localHostAsWell = ForEachMatchingIndirectHost (&clientAddress, connectionType, sendForward, (char *) 0);
  389.     
  390.     XdmcpDisposeARRAY8 (&clientAddress);
  391.     XdmcpDisposeARRAY8 (&clientPort);
  392.     if (localHostAsWell)
  393.         all_query_respond (from, fromlen, &queryAuthenticationNames,
  394.                INDIRECT_QUERY);
  395.     }
  396.     else
  397.     {
  398.     Debug ("Indirect length error got %d expect %d\n", length, expectedLen);
  399.     }
  400.     XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames);
  401. }
  402.  
  403. /*ARGSUSED*/
  404. forward_respond (from, fromlen, length)
  405.     struct sockaddr    *from;
  406.     int            fromlen;
  407.     int            length;
  408. {
  409.     ARRAY8        clientAddress;
  410.     ARRAY8        clientPort;
  411.     ARRAYofARRAY8   authenticationNames;
  412.     struct sockaddr *client;
  413.     int            clientlen;
  414.     int            expectedLen;
  415.     int            i;
  416.     
  417.     Debug ("Forward respond %d\n", length);
  418.     clientAddress.length = 0;
  419.     clientAddress.data = 0;
  420.     clientPort.length = 0;
  421.     clientPort.data = 0;
  422.     authenticationNames.length = 0;
  423.     authenticationNames.data = 0;
  424.     if (XdmcpReadARRAY8 (&buffer, &clientAddress) &&
  425.     XdmcpReadARRAY8 (&buffer, &clientPort) &&
  426.     XdmcpReadARRAYofARRAY8 (&buffer, &authenticationNames))
  427.     {
  428.     expectedLen = 0;
  429.     expectedLen += 2 + clientAddress.length;
  430.     expectedLen += 2 + clientPort.length;
  431.     expectedLen += 1;        /* authenticationNames */
  432.     for (i = 0; i < (int)authenticationNames.length; i++)
  433.         expectedLen += 2 + authenticationNames.data[i].length;
  434.     if (length == expectedLen)
  435.     {
  436.         int    j;
  437.  
  438.         j = 0;
  439.         for (i = 0; i < (int)clientPort.length; i++)
  440.         j = j * 256 + clientPort.data[i];
  441.         Debug ("Forward client address (port %d)", j);
  442.         for (i = 0; i < (int)clientAddress.length; i++)
  443.         Debug (" %d", clientAddress.data[i]);
  444.         Debug ("\n");
  445.             switch (from->sa_family)
  446.             {
  447. #ifdef AF_INET
  448.         case AF_INET:
  449.         {
  450.             struct sockaddr_in    in_addr;
  451.  
  452.             if (clientAddress.length != 4 ||
  453.                 clientPort.length != 2)
  454.             {
  455.             goto badAddress;
  456.             }
  457.             bzero ((char *) &in_addr, sizeof (in_addr));
  458.             in_addr.sin_family = AF_INET;
  459.             bcopy (clientAddress.data, &in_addr.sin_addr, 4);
  460.             bcopy (clientPort.data, (char *) &in_addr.sin_port, 2);
  461.             client = (struct sockaddr *) &in_addr;
  462.             clientlen = sizeof (in_addr);
  463.         }
  464.         break;
  465. #endif
  466. #ifdef AF_UNIX
  467.         case AF_UNIX:
  468.         {
  469.             struct sockaddr_un    un_addr;
  470.  
  471.             if (clientAddress.length >= sizeof (un_addr.sun_path))
  472.             goto badAddress;
  473.             bzero ((char *) &un_addr, sizeof (un_addr));
  474.             un_addr.sun_family = AF_UNIX;
  475.             bcopy (clientAddress.data, un_addr.sun_path, clientAddress.length);
  476.             un_addr.sun_path[clientAddress.length] = '\0';
  477.             client = (struct sockaddr *) &un_addr;
  478.             clientlen = sizeof (un_addr);
  479.         }
  480.         break;
  481. #endif
  482. #ifdef AF_CHAOS
  483.         case AF_CHAOS:
  484.         goto badAddress;
  485. #endif
  486. #ifdef AF_DECnet
  487.         case AF_DECnet:
  488.         goto badAddress;
  489. #endif
  490.             }
  491.         all_query_respond (client, clientlen, &authenticationNames,
  492.                    FORWARD_QUERY);
  493.     }
  494.     else
  495.     {
  496.         Debug ("Forward length error got %d expect %d\n", length, expectedLen);
  497.     }
  498.     }
  499. badAddress:
  500.     XdmcpDisposeARRAY8 (&clientAddress);
  501.     XdmcpDisposeARRAY8 (&clientPort);
  502.     XdmcpDisposeARRAYofARRAY8 (&authenticationNames);
  503. }
  504.  
  505. all_query_respond (from, fromlen, authenticationNames, type)
  506.     struct sockaddr    *from;
  507.     int            fromlen;
  508.     ARRAYofARRAY8Ptr    authenticationNames;
  509.     xdmOpCode        type;
  510. {
  511.     ARRAY8Ptr    authenticationName;
  512.     ARRAY8    status;
  513.     ARRAY8    addr;
  514.     CARD16    connectionType;
  515.     int        length;
  516.  
  517.     connectionType = ConvertAddr(from, &length, &(addr.data));
  518.     addr.length = length;    /* convert int to short */
  519.     Debug ("all_query_respond: conntype=%d, addr=%lx, len=%d\n",
  520.        connectionType, *(addr.data), addr.length);
  521.     if (connectionType < 0)
  522.     return;
  523.  
  524.     if (type == INDIRECT_QUERY)
  525.     RememberIndirectClient (&addr, connectionType);
  526.     else
  527.     ForgetIndirectClient (&addr, connectionType);
  528.  
  529.     authenticationName = ChooseAuthentication (authenticationNames);
  530.     if (Willing (&addr, connectionType, authenticationName, &status, type))
  531.     send_willing (from, fromlen, authenticationName, &status);
  532.     else
  533.     if (type == QUERY)
  534.         send_unwilling (from, fromlen, authenticationName, &status);
  535.     XdmcpDisposeARRAY8 (&status);
  536. }
  537.  
  538. send_willing (from, fromlen, authenticationName, status)
  539.     struct sockaddr *from;
  540.     int            fromlen;
  541.     ARRAY8Ptr        authenticationName;
  542.     ARRAY8Ptr        status;
  543. {
  544.     XdmcpHeader    header;
  545.  
  546.     Debug ("Send willing %*.*s %*.*s\n", authenticationName->length,
  547.                      authenticationName->length,
  548.                      pS(authenticationName->data),
  549.                      status->length,
  550.                      status->length,
  551.                      pS(status->data));
  552.     header.version = XDM_PROTOCOL_VERSION;
  553.     header.opcode = (CARD16) WILLING;
  554.     header.length = 6 + authenticationName->length +
  555.             Hostname.length + status->length;
  556.     XdmcpWriteHeader (&buffer, &header);
  557.     XdmcpWriteARRAY8 (&buffer, authenticationName);
  558.     XdmcpWriteARRAY8 (&buffer, &Hostname);
  559.     XdmcpWriteARRAY8 (&buffer, status);
  560.     XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
  561. }
  562.  
  563. send_unwilling (from, fromlen, authenticationName, status)
  564.     struct sockaddr *from;
  565.     int            fromlen;
  566.     ARRAY8Ptr        authenticationName;
  567.     ARRAY8Ptr        status;
  568. {
  569.     XdmcpHeader    header;
  570.  
  571.     Debug ("Send unwilling %*.*s %*.*s\n", authenticationName->length,
  572.                      authenticationName->length,
  573.                      pS(authenticationName->data),
  574.                      status->length,
  575.                      status->length,
  576.                      pS(status->data));
  577.     header.version = XDM_PROTOCOL_VERSION;
  578.     header.opcode = (CARD16) UNWILLING;
  579.     header.length = 4 + Hostname.length + status->length;
  580.     XdmcpWriteHeader (&buffer, &header);
  581.     XdmcpWriteARRAY8 (&buffer, &Hostname);
  582.     XdmcpWriteARRAY8 (&buffer, status);
  583.     XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
  584. }
  585.  
  586. static unsigned long    globalSessionID;
  587.  
  588. #define NextSessionID()    (++globalSessionID)
  589.     
  590. static ARRAY8 outOfMemory = { (CARD16) 13, (CARD8Ptr) "Out of memory" };
  591. static ARRAY8 noValidAddr = { (CARD16) 16, (CARD8Ptr) "No valid address" };
  592. static ARRAY8 noValidAuth = { (CARD16) 22, (CARD8Ptr) "No valid authorization" };
  593. static ARRAY8 noAuthentic = { (CARD16) 29, (CARD8Ptr) "XDM has no authentication key" };
  594.  
  595. request_respond (from, fromlen, length)
  596.     struct sockaddr *from;
  597.     int            fromlen;
  598.     int            length;
  599. {
  600.     CARD16        displayNumber;
  601.     ARRAY16        connectionTypes;
  602.     ARRAYofARRAY8   connectionAddresses;
  603.     ARRAY8        authenticationName;
  604.     ARRAY8        authenticationData;
  605.     ARRAYofARRAY8   authorizationNames;
  606.     ARRAY8        manufacturerDisplayID;
  607.     ARRAY8Ptr        reason;
  608.     int            expectlen;
  609.     int            i, j;
  610.     struct protoDisplay  *pdpy;
  611.     ARRAY8        authorizationName, authorizationData;
  612.     ARRAY8Ptr        connectionAddress;
  613.  
  614.     Debug ("Request respond %d\n", length);
  615.     connectionTypes.data = 0;
  616.     connectionAddresses.data = 0;
  617.     authenticationName.data = 0;
  618.     authenticationData.data = 0;
  619.     authorizationNames.data = 0;
  620.     authorizationName.length = 0;
  621.     authorizationData.length = 0;
  622.     manufacturerDisplayID.data = 0;
  623.     if (XdmcpReadCARD16 (&buffer, &displayNumber) &&
  624.     XdmcpReadARRAY16 (&buffer, &connectionTypes) &&
  625.     XdmcpReadARRAYofARRAY8 (&buffer, &connectionAddresses) &&
  626.     XdmcpReadARRAY8 (&buffer, &authenticationName) &&
  627.     XdmcpReadARRAY8 (&buffer, &authenticationData) &&
  628.     XdmcpReadARRAYofARRAY8 (&buffer, &authorizationNames) &&
  629.     XdmcpReadARRAY8 (&buffer, &manufacturerDisplayID))
  630.     {
  631.     expectlen = 0;
  632.     expectlen += 2;                    /* displayNumber */
  633.     expectlen += 1 + 2*connectionTypes.length;  /* connectionTypes */
  634.     expectlen += 1;                    /* connectionAddresses */
  635.     for (i = 0; i < (int)connectionAddresses.length; i++)
  636.         expectlen += 2 + connectionAddresses.data[i].length;
  637.     expectlen += 2 + authenticationName.length; /* authenticationName */
  638.     expectlen += 2 + authenticationData.length; /* authenticationData */
  639.     expectlen += 1;                    /* authoriationNames */
  640.     for (i = 0; i < (int)authorizationNames.length; i++)
  641.         expectlen += 2 + authorizationNames.data[i].length;
  642.     expectlen += 2 + manufacturerDisplayID.length;    /* displayID */
  643.     if (expectlen != length)
  644.     {
  645.         Debug ("Request length error got %d expect %d\n", length, expectlen);
  646.         goto abort;
  647.     }
  648.     if (connectionTypes.length == 0 ||
  649.         connectionAddresses.length != connectionTypes.length)
  650.     {
  651.         reason = &noValidAddr;
  652.         pdpy = 0;
  653.         goto decline;
  654.     }
  655.     if (pdpy = FindProtoDisplay (from, fromlen, displayNumber))
  656.         goto accept;
  657.     reason = Accept (from, fromlen, displayNumber);
  658.     if (reason)
  659.         goto decline;
  660.     i = SelectConnectionTypeIndex (&connectionTypes,
  661.                        &connectionAddresses);
  662.     if (i < 0)
  663.     {
  664.         reason = &noValidAddr;
  665.         goto decline;
  666.     }
  667.     if (authorizationNames.length == 0)
  668.         j = 0;
  669.     else
  670.         j = SelectAuthorizationTypeIndex (&authenticationName,
  671.                           &authorizationNames);
  672.     if (j < 0)
  673.     {
  674.         reason = &noValidAuth;
  675.         goto decline;
  676.     }
  677.     connectionAddress = &connectionAddresses.data[i];
  678.     pdpy = NewProtoDisplay (from, fromlen,
  679.                 displayNumber,
  680.                 connectionTypes.data[i],
  681.                 connectionAddress,
  682.                 NextSessionID());
  683.     Debug ("NewProtoDisplay 0x%x\n", pdpy);
  684.     if (!pdpy)
  685.     {
  686.         reason = &outOfMemory;
  687.         goto decline;
  688.     }
  689.     if (!CheckAuthentication (pdpy,
  690.                   &manufacturerDisplayID,
  691.                   &authenticationName,
  692.                   &authenticationData))
  693.     {
  694.         reason = &noAuthentic;
  695.         goto decline;
  696.     }
  697.     if (j < (int)authorizationNames.length)
  698.     {
  699.         Xauth   *auth;
  700.         SetProtoDisplayAuthorization (pdpy,
  701.         (unsigned short) authorizationNames.data[j].length,
  702.         (char *) authorizationNames.data[j].data);
  703.         auth = pdpy->xdmcpAuthorization;
  704.         if (!auth)
  705.         auth = pdpy->fileAuthorization;
  706.         if (auth)
  707.         {
  708.         authorizationName.length = auth->name_length;
  709.         authorizationName.data = (CARD8Ptr) auth->name;
  710.         authorizationData.length = auth->data_length;
  711.         authorizationData.data = (CARD8Ptr) auth->data;
  712.         }
  713.     }
  714.     if (pdpy)
  715.     {
  716. accept:        ;
  717.         send_accept (from, fromlen, pdpy->sessionID,
  718.                         &authenticationName,
  719.                     &authenticationData,
  720.                     &authorizationName,
  721.                     &authorizationData);
  722.     }
  723.     else
  724.     {
  725. decline:    ;
  726.         send_decline (from, fromlen, &authenticationName,
  727.                  &authenticationData,
  728.                  reason);
  729.     }
  730.     }
  731. abort:
  732.     XdmcpDisposeARRAY16 (&connectionTypes);
  733.     XdmcpDisposeARRAYofARRAY8 (&connectionAddresses);
  734.     XdmcpDisposeARRAY8 (&authenticationName);
  735.     XdmcpDisposeARRAY8 (&authenticationData);
  736.     XdmcpDisposeARRAYofARRAY8 (&authorizationNames);
  737.     XdmcpDisposeARRAY8 (&manufacturerDisplayID);
  738. }
  739.  
  740. send_accept (to, tolen, sessionID,
  741.          authenticationName, authenticationData,
  742.          authorizationName, authorizationData)
  743.     struct sockaddr *to;
  744.     int            tolen;
  745.     CARD32        sessionID;
  746.     ARRAY8Ptr        authenticationName, authenticationData;
  747.     ARRAY8Ptr        authorizationName, authorizationData;
  748. {
  749.     XdmcpHeader    header;
  750.  
  751.     Debug ("Accept Session ID %d\n", sessionID);
  752.     header.version = XDM_PROTOCOL_VERSION;
  753.     header.opcode = (CARD16) ACCEPT;
  754.     header.length = 4;                /* session ID */
  755.     header.length += 2 + authenticationName->length;
  756.     header.length += 2 + authenticationData->length;
  757.     header.length += 2 + authorizationName->length;
  758.     header.length += 2 + authorizationData->length;
  759.     XdmcpWriteHeader (&buffer, &header);
  760.     XdmcpWriteCARD32 (&buffer, sessionID);
  761.     XdmcpWriteARRAY8 (&buffer, authenticationName);
  762.     XdmcpWriteARRAY8 (&buffer, authenticationData);
  763.     XdmcpWriteARRAY8 (&buffer, authorizationName);
  764.     XdmcpWriteARRAY8 (&buffer, authorizationData);
  765.     XdmcpFlush (xdmcpFd, &buffer, to, tolen);
  766. }
  767.    
  768. send_decline (to, tolen, authenticationName, authenticationData, status)
  769.     struct sockaddr *to;
  770.     int            tolen;
  771.     ARRAY8Ptr        authenticationName, authenticationData;
  772.     ARRAY8Ptr        status;
  773. {
  774.     XdmcpHeader    header;
  775.  
  776.     Debug ("Decline %*.*s\n", status->length, status->length, pS(status->data));
  777.     header.version = XDM_PROTOCOL_VERSION;
  778.     header.opcode = (CARD16) DECLINE;
  779.     header.length = 0;
  780.     header.length += 2 + status->length;
  781.     header.length += 2 + authenticationName->length;
  782.     header.length += 2 + authenticationData->length;
  783.     XdmcpWriteHeader (&buffer, &header);
  784.     XdmcpWriteARRAY8 (&buffer, status);
  785.     XdmcpWriteARRAY8 (&buffer, authenticationName);
  786.     XdmcpWriteARRAY8 (&buffer, authenticationData);
  787.     XdmcpFlush (xdmcpFd, &buffer, to, tolen);
  788. }
  789.  
  790. manage (from, fromlen, length)
  791.     struct sockaddr *from;
  792.     int            fromlen;
  793.     int            length;
  794. {
  795.     CARD32        sessionID;
  796.     CARD16        displayNumber;
  797.     ARRAY8        displayClass;
  798.     int            expectlen;
  799.     struct protoDisplay    *pdpy;
  800.     struct display    *d;
  801.     char        *name;
  802.     char        *class;
  803.     XdmcpNetaddr    from_save;
  804.     ARRAY8        clientAddress, clientPort;
  805.     CARD16        connectionType;
  806.  
  807.     Debug ("Manage %d\n", length);
  808.     displayClass.data = 0;
  809.     displayClass.length = 0;
  810.     if (XdmcpReadCARD32 (&buffer, &sessionID) &&
  811.     XdmcpReadCARD16 (&buffer, &displayNumber) &&
  812.     XdmcpReadARRAY8 (&buffer, &displayClass))
  813.     {
  814.     expectlen = 4 +                /* session ID */
  815.             2 +                /* displayNumber */
  816.             2 + displayClass.length;    /* displayClass */
  817.     if (expectlen != length)
  818.     {
  819.         Debug ("Manage length error got %d expect %d\n", length, expectlen);
  820.         goto abort;
  821.     }
  822.     pdpy = FindProtoDisplay (from, fromlen, displayNumber);
  823.     Debug ("Manage Session ID %d, pdpy 0x%x\n", sessionID, pdpy);
  824.     if (!pdpy || pdpy->sessionID != sessionID)
  825.     {
  826.         /*
  827.          * We may have already started a session for this display
  828.          * but it hasn't seen the response in the form of an
  829.          * XOpenDisplay() yet. So check if it is in the list of active
  830.          * displays, and if so check that the session id's match.
  831.          * If all this is true, then we have a duplicate request that
  832.          * can be ignored.
  833.          */
  834.         if (!pdpy 
  835.         && (d = FindDisplayByAddress(from, fromlen, displayNumber))
  836.         && d->sessionID == sessionID) {
  837.              Debug("manage: got duplicate pkt, ignoring\n");
  838.              goto abort;
  839.         }
  840.         Debug ("Session ID %d refused\n", sessionID);
  841.         if (pdpy)
  842.         Debug ("Existing Session ID %d\n", pdpy->sessionID);
  843.         send_refuse (from, fromlen, sessionID);
  844.     }
  845.     else
  846.     {
  847.         name = NetworkAddressToName (pdpy->connectionType,
  848.                      &pdpy->connectionAddress,
  849.                      pdpy->displayNumber);
  850.         Debug ("Computed display name: %s\n", name);
  851.         if (!name)
  852.         {
  853.         send_failed (from, fromlen, "(no name)", sessionID, "out of memory");
  854.         goto abort;
  855.         }
  856.         d = FindDisplayByName (name);
  857.         if (d)
  858.         {
  859.         extern void StopDisplay ();
  860.  
  861.         Debug ("Terminating active session for %s\n", d->name);
  862.         StopDisplay (d);
  863.         }
  864.         class = malloc (displayClass.length + 1);
  865.         if (!class)
  866.         {
  867.         send_failed (from, fromlen, name, sessionID, "out of memory");
  868.         goto abort;
  869.         }
  870.         if (displayClass.length)
  871.         {
  872.         bcopy (displayClass.data, class, displayClass.length);
  873.         class[displayClass.length] = '\0';
  874.         }
  875.         else
  876.         class = (char *) 0;
  877.         from_save = (XdmcpNetaddr) malloc (fromlen);
  878.         if (!from_save)
  879.         {
  880.         send_failed (from, fromlen, name, sessionID, "out of memory");
  881.         goto abort;
  882.         }
  883.         bcopy (from, from_save, fromlen);
  884.         d = NewDisplay (name, class);
  885.         if (!d)
  886.         {
  887.         free ((char *) from_save);
  888.         send_failed (from, fromlen, name, sessionID, "out of memory");
  889.         goto abort;
  890.         }
  891.         d->displayType.location = Foreign;
  892.         d->displayType.lifetime = Transient;
  893.         d->displayType.origin = FromXDMCP;
  894.         d->sessionID = pdpy->sessionID;
  895.         d->from = from_save;
  896.         d->fromlen = fromlen;
  897.         d->displayNumber = pdpy->displayNumber;
  898.         ClientAddress (from, &clientAddress, &clientPort, &connectionType);
  899.         d->useChooser = 0;
  900.         if (IsIndirectClient (&clientAddress, connectionType))
  901.         {
  902.         Debug ("IsIndirectClient\n");
  903.         ForgetIndirectClient (&clientAddress, connectionType);
  904.         if (UseChooser (&clientAddress, connectionType))
  905.         {
  906.             d->useChooser = 1;
  907.             Debug ("Use chooser for %s\n", d->name);
  908.         }
  909.         }
  910.         d->clientAddr = clientAddress;
  911.         d->connectionType = connectionType;
  912.         XdmcpDisposeARRAY8 (&clientPort);
  913.         if (pdpy->fileAuthorization)
  914.         {
  915.         d->authorizations = (Xauth **) malloc (sizeof (Xauth *));
  916.         if (!d->authorizations)
  917.         {
  918.             free ((char *) from_save);
  919.             free ((char *) d);
  920.             send_failed (from, fromlen, name, sessionID, "out of memory");
  921.             goto abort;
  922.         }
  923.         d->authorizations[0] = pdpy->fileAuthorization;
  924.         d->authNum = 1;
  925.         pdpy->fileAuthorization = 0;
  926.         }
  927.         DisposeProtoDisplay (pdpy);
  928.         Debug ("Starting display %s,%s\n", d->name, d->class);
  929.         StartDisplay (d);
  930.     }
  931.     }
  932. abort:
  933.     XdmcpDisposeARRAY8 (&displayClass);
  934. }
  935.  
  936. SendFailed (d, reason)
  937.     struct display  *d;
  938.     char        *reason;
  939. {
  940.     Debug ("Display start failed, sending Failed\n");
  941.     send_failed (d->from, d->fromlen, d->name, d->sessionID, reason);
  942. }
  943.  
  944. send_failed (from, fromlen, name, sessionID, reason)
  945.     struct sockaddr *from;
  946.     int            fromlen;
  947.     char        *name;
  948.     CARD32        sessionID;
  949.     char        *reason;
  950. {
  951.     static char    buf[256];
  952.     XdmcpHeader    header;
  953.     ARRAY8    status;
  954.  
  955.     sprintf (buf, "Session %d failed for display %s: %s",
  956.          sessionID, name, reason);
  957.     Debug ("Send failed %d %s\n", sessionID, buf);
  958.     status.length = strlen (buf);
  959.     status.data = (CARD8Ptr) buf;
  960.     header.version = XDM_PROTOCOL_VERSION;
  961.     header.opcode = (CARD16) FAILED;
  962.     header.length = 6 + status.length;
  963.     XdmcpWriteHeader (&buffer, &header);
  964.     XdmcpWriteCARD32 (&buffer, sessionID);
  965.     XdmcpWriteARRAY8 (&buffer, &status);
  966.     XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
  967. }
  968.  
  969. send_refuse (from, fromlen, sessionID)
  970.     struct sockaddr *from;
  971.     int            fromlen;
  972.     CARD32        sessionID;
  973. {
  974.     XdmcpHeader    header;
  975.  
  976.     Debug ("Send refuse %d\n", sessionID);
  977.     header.version = XDM_PROTOCOL_VERSION;
  978.     header.opcode = (CARD16) REFUSE;
  979.     header.length = 4;
  980.     XdmcpWriteHeader (&buffer, &header);
  981.     XdmcpWriteCARD32 (&buffer, sessionID);
  982.     XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
  983. }
  984.  
  985. send_alive (from, fromlen, length)
  986.     struct sockaddr *from;
  987.     int            fromlen;
  988.     int            length;
  989. {
  990.     CARD32        sessionID;
  991.     CARD16        displayNumber;
  992.     struct display    *d;
  993.     XdmcpHeader        header;
  994.     CARD8        sendRunning;
  995.     CARD32        sendSessionID;
  996.  
  997.     Debug ("Send alive\n");
  998.     if (XdmcpReadCARD16 (&buffer, &displayNumber) &&
  999.     XdmcpReadCARD32 (&buffer, &sessionID))
  1000.     {
  1001.     if (length == 6)
  1002.     {
  1003.         d = FindDisplayBySessionID (sessionID);
  1004.         if (!d) {
  1005.         d = FindDisplayByAddress (from, fromlen, displayNumber);
  1006.         }
  1007.         sendRunning = 0;
  1008.         sendSessionID = 0;
  1009.         if (d && d->status == running)
  1010.          {
  1011.         if (d->sessionID == sessionID)
  1012.             sendRunning = 1;
  1013.         sendSessionID = d->sessionID;
  1014.         }
  1015.         header.version = XDM_PROTOCOL_VERSION;
  1016.         header.opcode = (CARD16) ALIVE;
  1017.         header.length = 5;
  1018.         Debug ("alive: %d %d\n", sendRunning, sendSessionID);
  1019.         XdmcpWriteHeader (&buffer, &header);
  1020.         XdmcpWriteCARD8 (&buffer, sendRunning);
  1021.         XdmcpWriteCARD32 (&buffer, sendSessionID);
  1022.         XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
  1023.     }
  1024.     }
  1025. }
  1026.  
  1027. char *
  1028. NetworkAddressToHostname (connectionType, connectionAddress)
  1029.     CARD16    connectionType;
  1030.     ARRAY8Ptr   connectionAddress;
  1031. {
  1032.     char    *name = 0;
  1033.  
  1034.     switch (connectionType)
  1035.     {
  1036.     case FamilyInternet:
  1037.     {
  1038.         struct hostent    *hostent;
  1039.         char dotted[20];
  1040.         char *local_name;
  1041.  
  1042.         hostent = gethostbyaddr ((char *)connectionAddress->data,
  1043.                      connectionAddress->length, AF_INET);
  1044.  
  1045.         if (hostent)
  1046.         local_name = hostent->h_name;
  1047.         else {
  1048.         /* can't get name, so use emergency fallback */
  1049.         sprintf(dotted, "%d.%d.%d.%d",
  1050.             connectionAddress->data[0],
  1051.             connectionAddress->data[1],
  1052.             connectionAddress->data[2],
  1053.             connectionAddress->data[3]);
  1054.         local_name = dotted;
  1055.         }
  1056.         if (!getString (name, strlen (local_name)))
  1057.         break;
  1058.         strcpy (name, local_name);
  1059.         break;
  1060.     }
  1061. #ifdef DNET
  1062.     case FamilyDECnet:
  1063.     break;
  1064. #endif /* DNET */
  1065.     default:
  1066.     break;
  1067.     }
  1068.     return name;
  1069. }
  1070.  
  1071. static
  1072. HostnameToNetworkAddress (name, connectionType, connectionAddress)
  1073. char        *name;
  1074. CARD16        connectionType;
  1075. ARRAY8Ptr   connectionAddress;
  1076. {
  1077.     switch (connectionType)
  1078.     {
  1079.     case FamilyInternet:
  1080.     {
  1081.         struct hostent    *hostent;
  1082.  
  1083.         hostent = gethostbyname (name);
  1084.         if (!hostent)
  1085.         return FALSE;
  1086.         if (!XdmcpAllocARRAY8 (connectionAddress, hostent->h_length))
  1087.         return FALSE;
  1088.         bcopy (hostent->h_addr, connectionAddress->data, hostent->h_length);
  1089.         return TRUE;
  1090.     }
  1091. #ifdef DNET
  1092.     case FamilyDECnet:
  1093.     return FALSE;
  1094. #endif
  1095.     }
  1096.     return FALSE;
  1097. }
  1098.  
  1099. /*
  1100.  * converts a display name into a network address, using
  1101.  * the same rules as XOpenDisplay (algorithm cribbed from there)
  1102.  */
  1103.  
  1104. static
  1105. NameToNetworkAddress(name, connectionTypep, connectionAddress, displayNumber)
  1106. char        *name;
  1107. CARD16Ptr   connectionTypep;
  1108. ARRAY8Ptr   connectionAddress;
  1109. CARD16Ptr   displayNumber;
  1110. {
  1111.     char    *colon, *display_number;
  1112.     char    hostname[1024];
  1113.     int        dnet = FALSE;
  1114.     CARD16  number;
  1115.     CARD16  connectionType;
  1116.  
  1117.     colon = index (name, ':');
  1118.     if (!colon)
  1119.     return FALSE;
  1120.     if (colon != name)
  1121.     {
  1122.     if (colon - name > sizeof (hostname))
  1123.         return FALSE;
  1124.     strncpy (hostname, name, colon - name);
  1125.     hostname[colon - name] = '\0';
  1126.     }
  1127.     else
  1128.     {
  1129.     strcpy (hostname, localHostname ());
  1130.     }
  1131.     if (colon[1] == ':')
  1132.     {
  1133.     dnet = TRUE;
  1134.     colon++;
  1135.     }
  1136. #ifndef DNETCONN
  1137.     if (dnet)
  1138.     return FALSE;
  1139. #endif
  1140.     display_number = colon + 1;
  1141.     while (*display_number && *display_number != '.')
  1142.     {
  1143.     if (!isascii (*display_number) || !isdigit(*display_number))
  1144.         return FALSE;
  1145.     }
  1146.     if (display_number == colon + 1)
  1147.     return FALSE;
  1148.     number = atoi (colon + 1);
  1149. #ifdef DNETCONN
  1150.     if (dnet)
  1151.     connectionType = FamilyDECnet;
  1152.     else
  1153. #endif
  1154.     connectionType = FamilyInternet;
  1155.     if (!HostnameToNetworkAddress (hostname, connectionType, connectionAddress))
  1156.     return FALSE;
  1157.     *displayNumber = number;
  1158.     *connectionTypep = connectionType;
  1159.     return TRUE;
  1160. }
  1161.  
  1162. #endif /* XDMCP */
  1163.