home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xdm / access.c.orig < prev    next >
Encoding:
Text File  |  1991-07-18  |  15.6 KB  |  732 lines

  1. /*
  2.  * $XConsortium: access.c,v 1.11 91/07/18 19:29:00 rws Exp $
  3.  *
  4.  * Copyright 1990 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  18.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  21.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  *
  23.  * Author:  Keith Packard, MIT X Consortium
  24.  */
  25.  
  26. /*
  27.  * Access control for XDMCP - keep a database of allowable display addresses
  28.  * and (potentially) a list of hosts to send ForwardQuery packets to
  29.  */
  30.  
  31. # include   "dm.h"
  32.  
  33. #ifdef XDMCP
  34.  
  35. # include   <X11/Xos.h>
  36. # include   <X11/Xdmcp.h>
  37. # include   <X11/X.h>
  38. # include   <stdio.h>
  39. # include   <netinet/in.h>
  40. # include   <netdb.h>
  41. # include   <sys/socket.h>
  42.  
  43. #define ALIAS_CHARACTER        '%'
  44. #define NEGATE_CHARACTER    '!'
  45. #define CHOOSER_STRING        "CHOOSER"
  46. #define BROADCAST_STRING    "BROADCAST"
  47.  
  48. #define HOST_ALIAS    0
  49. #define HOST_ADDRESS    1
  50. #define HOST_BROADCAST    2
  51. #define HOST_CHOOSER    3
  52.  
  53. typedef struct _hostEntry {
  54.     struct _hostEntry    *next;
  55.     int        type;
  56.     union _hostOrAlias {
  57.     char    *aliasName;
  58.     ARRAY8    hostAddress;
  59.     } entry;
  60. } HostEntry;
  61.  
  62. #define DISPLAY_ALIAS        0
  63. #define DISPLAY_PATTERN        1
  64. #define DISPLAY_ADDRESS        2
  65.  
  66. typedef struct _displayEntry {
  67.     struct _displayEntry    *next;
  68.     int                type;
  69.     int                notAllowed;
  70.     int                chooser;
  71.     union _displayType {
  72.     char            *aliasName;
  73.     char            *displayPattern;
  74.     struct _display {
  75.         ARRAY8        clientAddress;
  76.         CARD16        connectionType;
  77.     } displayAddress;
  78.     } entry;
  79.     HostEntry            *hosts;
  80. } DisplayEntry;
  81.  
  82. static DisplayEntry    *database;
  83.  
  84. static ARRAY8        localAddress;
  85.  
  86. ARRAY8Ptr
  87. getLocalAddress ()
  88. {
  89.     static int    haveLocalAddress;
  90.     
  91.     if (!haveLocalAddress)
  92.     {
  93.     struct hostent    *hostent;
  94.  
  95.     hostent = gethostbyname (localHostname());
  96.     XdmcpAllocARRAY8 (&localAddress, hostent->h_length);
  97.     bcopy (hostent->h_addr, localAddress.data, hostent->h_length);
  98.     }
  99.     return &localAddress;
  100. }
  101.  
  102. static void
  103. FreeHostEntry (h)
  104.     HostEntry        *h;
  105. {
  106.     switch (h->type) {
  107.     case HOST_ALIAS:
  108.     free (h->entry.aliasName);
  109.     break;
  110.     case HOST_ADDRESS:
  111.     XdmcpDisposeARRAY8 (&h->entry.hostAddress);
  112.     break;
  113.     case HOST_CHOOSER:
  114.     break;
  115.     }
  116.     free ((char *) h);
  117. }
  118.  
  119. static void
  120. FreeDisplayEntry (d)
  121.     DisplayEntry    *d;
  122. {
  123.     HostEntry    *h, *next;
  124.     switch (d->type) {
  125.     case DISPLAY_ALIAS:
  126.     free (d->entry.aliasName);
  127.     break;
  128.     case DISPLAY_PATTERN:
  129.     free (d->entry.displayPattern);
  130.     break;
  131.     case DISPLAY_ADDRESS:
  132.     XdmcpDisposeARRAY8 (&d->entry.displayAddress);
  133.     break;
  134.     }
  135.     for (h = d->hosts; h; h = next) {
  136.     next = h->next;
  137.     FreeHostEntry (h);
  138.     }
  139.     free ((char *) d);
  140. }
  141.  
  142. static void
  143. FreeAccessDatabase ()
  144. {
  145.     DisplayEntry    *d, *next;
  146.  
  147.     for (d = database; d; d = next)
  148.     {
  149.     next = d->next;
  150.     FreeDisplayEntry (d);
  151.     }
  152.     database = 0;
  153. }
  154.  
  155. #define WORD_LEN    256
  156. static char    wordBuffer[WORD_LEN];
  157. static int    nextIsEOF;
  158.  
  159. static char *
  160. ReadWord (file, EOFatEOL)
  161.     FILE    *file;
  162.     int        EOFatEOL;
  163. {
  164.     int        c;
  165.     char    *wordp;
  166.     int        quoted;
  167.  
  168.     wordp = wordBuffer;
  169.     if (nextIsEOF)
  170.     {
  171.     nextIsEOF = FALSE;
  172.     return NULL;
  173.     }
  174.     quoted = FALSE;
  175.     for (;;) {
  176.     c = getc (file);
  177.     switch (c) {
  178.     case '#':
  179.         if (quoted)
  180.         {
  181.         *wordp++ = c;
  182.         break;
  183.         }
  184.         while ((c = getc (file)) != EOF && c != '\n')
  185.         ;
  186.     case '\n':
  187.     case EOF:
  188.         if (c == EOF || (EOFatEOL && !quoted))
  189.         {
  190.         ungetc (c, file);
  191.         if (wordp == wordBuffer)
  192.             return NULL;
  193.         *wordp = '\0';
  194.         nextIsEOF = TRUE;
  195.         return wordBuffer;
  196.         }
  197.     case ' ':
  198.     case '\t':
  199.         if (wordp != wordBuffer)
  200.         {
  201.         ungetc (c, file);
  202.         *wordp = '\0';
  203.         return wordBuffer;
  204.         }
  205.         break;
  206.     case '\\':
  207.         if (!quoted)
  208.         {
  209.         quoted = TRUE;
  210.         continue;
  211.         }
  212.     default:
  213.         *wordp++ = c;
  214.         break;
  215.     }
  216.     quoted = FALSE;
  217.     }
  218. }
  219.  
  220. static HostEntry *
  221. ReadHostEntry (file)
  222.     FILE    *file;
  223. {
  224.     char        *hostOrAlias;
  225.     HostEntry        *h;
  226.     struct hostent  *hostent;
  227.  
  228. tryagain:
  229.     hostOrAlias = ReadWord (file, TRUE);
  230.     if (!hostOrAlias)
  231.     return NULL;
  232.     h = (HostEntry *) malloc (sizeof (DisplayEntry));
  233.     if (*hostOrAlias == ALIAS_CHARACTER)
  234.     {
  235.     h->type = HOST_ALIAS;
  236.     h->entry.aliasName = malloc (strlen (hostOrAlias) + 1);
  237.     if (!h->entry.aliasName) {
  238.         free ((char *) h);
  239.         return NULL;
  240.     }
  241.     strcpy (h->entry.aliasName, hostOrAlias);
  242.     }
  243.     else if (!strcmp (hostOrAlias, CHOOSER_STRING))
  244.     {
  245.     h->type = HOST_CHOOSER;
  246.     }
  247.     else if (!strcmp (hostOrAlias, BROADCAST_STRING))
  248.     {
  249.     h->type = HOST_BROADCAST;
  250.     }
  251.     else
  252.     {
  253.     h->type = HOST_ADDRESS;
  254.     hostent = gethostbyname (hostOrAlias);
  255.     if (!hostent)
  256.     {
  257.         Debug ("No such host %s\n", hostOrAlias);
  258.         LogError ("Access file \"%s\", host \"%s\" not found\n", accessFile, hostOrAlias);
  259.         free ((char *) h);
  260.         goto tryagain;
  261.     }
  262.     if (!XdmcpAllocARRAY8 (&h->entry.hostAddress, hostent->h_length))
  263.     {
  264.         LogOutOfMem ("ReadHostEntry\n");
  265.         free ((char *) h);
  266.         return NULL;
  267.     }
  268.     bcopy (hostent->h_addr, h->entry.hostAddress.data, hostent->h_length);
  269.     }
  270.     return h;
  271. }
  272.  
  273. static int
  274. HasGlobCharacters (s)
  275.     char    *s;
  276. {
  277.     for (;;)
  278.     switch (*s++) {
  279.     case '?':
  280.     case '*':
  281.         return 1;
  282.     case '\0':
  283.         return 0;
  284.     }
  285. }
  286.  
  287. static DisplayEntry *
  288. ReadDisplayEntry (file)
  289.     FILE    *file;
  290. {
  291.     char        *displayOrAlias;
  292.     DisplayEntry    *d;
  293.     struct _display *display;
  294.     HostEntry        *h, **prev;
  295.     struct hostent  *hostent;
  296.     
  297.     displayOrAlias = ReadWord (file, FALSE);
  298.     if (!displayOrAlias)
  299.         return NULL;
  300.     d = (DisplayEntry *) malloc (sizeof (DisplayEntry));
  301.     d->notAllowed = 0;
  302.     d->chooser = 0;
  303.     if (*displayOrAlias == ALIAS_CHARACTER)
  304.     {
  305.     d->type = DISPLAY_ALIAS;
  306.     d->entry.aliasName = malloc (strlen (displayOrAlias) + 1);
  307.     if (!d->entry.aliasName)
  308.     {
  309.         free ((char *) d);
  310.         return NULL;
  311.     }
  312.     strcpy (d->entry.aliasName, displayOrAlias);
  313.     }
  314.     else
  315.     {
  316.     if (*displayOrAlias == NEGATE_CHARACTER)
  317.     {
  318.         d->notAllowed = 1;
  319.         ++displayOrAlias;
  320.     }
  321.         if (HasGlobCharacters (displayOrAlias))
  322.         {
  323.         d->type = DISPLAY_PATTERN;
  324.         d->entry.displayPattern = malloc (strlen (displayOrAlias) + 1);
  325.         if (!d->entry.displayPattern)
  326.         {
  327.             free ((char *) d);
  328.             return NULL;
  329.         }
  330.         strcpy (d->entry.displayPattern, displayOrAlias);
  331.         }
  332.         else
  333.         {
  334.         if ((hostent = gethostbyname (displayOrAlias)) == NULL)
  335.         {
  336.         LogError ("Access file %s, display %s unknown\n", accessFile, displayOrAlias);
  337.         free ((char *) d);
  338.         return NULL;
  339.         }
  340.         d->type = DISPLAY_ADDRESS;
  341.         display = &d->entry.displayAddress;
  342.         if (!XdmcpAllocARRAY8 (&display->clientAddress, hostent->h_length))
  343.         {
  344.             free ((char *) d);
  345.             return NULL;
  346.         }
  347.         bcopy (hostent->h_addr, display->clientAddress.data, hostent->h_length);
  348.         switch (hostent->h_addrtype)
  349.         {
  350. #ifdef AF_UNIX
  351.         case AF_UNIX:
  352.             display->connectionType = FamilyLocal;
  353.             break;
  354. #endif
  355. #ifdef AF_INET
  356.         case AF_INET:
  357.             display->connectionType = FamilyInternet;
  358.             break;
  359. #endif
  360. #ifdef AF_DECnet
  361.         case AF_DECnet:
  362.             display->connectionType = FamilyDECnet;
  363.             break;
  364. #endif
  365.         default:
  366.             display->connectionType = FamilyLocal;
  367.             break;
  368.         }
  369.         }
  370.     }
  371.     prev = &d->hosts;
  372.     while (h = ReadHostEntry (file))
  373.     {
  374.     if (h->type == HOST_CHOOSER)
  375.     {
  376.         FreeHostEntry (h);
  377.         d->chooser = 1;
  378.     } else {
  379.         *prev = h;
  380.         prev = &h->next;
  381.     }
  382.     }
  383.     *prev = NULL;
  384.     return d;
  385. }
  386.  
  387. static
  388. ReadAccessDatabase (file)
  389.     FILE    *file;
  390. {
  391.     DisplayEntry    *d, **prev;
  392.  
  393.     prev = &database;
  394.     while (d = ReadDisplayEntry (file))
  395.     {
  396.     *prev = d;
  397.     prev = &d->next;
  398.     }
  399.     *prev = NULL;
  400. }
  401.  
  402. ScanAccessDatabase ()
  403. {
  404.     FILE    *datafile;
  405.  
  406.     FreeAccessDatabase ();
  407.     if (*accessFile)
  408.     {
  409.         datafile = fopen (accessFile, "r");
  410.         if (!datafile)
  411.     {
  412.         LogError ("Cannot open access control file %s, no XDMCP reqeusts will be granted\n", accessFile);
  413.         return 0;
  414.     }
  415.     ReadAccessDatabase (datafile);
  416.     fclose (datafile);
  417.     }
  418.     return 1;
  419. }
  420.  
  421. /*
  422.  * calls the given function for each valid indirect entry.  Returns TRUE if
  423.  * the local host exists on any of the lists, else FALSE
  424.  */
  425.  
  426. #define MAX_DEPTH   32
  427.  
  428. static int indirectAlias ();
  429.  
  430. static int
  431. scanHostlist (h, clientAddress, connectionType, function, closure, depth, broadcast)
  432.     HostEntry    *h;
  433.     ARRAY8Ptr    clientAddress;
  434.     CARD16    connectionType;
  435.     int        (*function)();
  436.     char    *closure;
  437.     int        depth;
  438.     int        broadcast;
  439. {
  440.     int    haveLocalhost = 0;
  441.  
  442.     for (; h; h = h->next)
  443.     {
  444.     switch (h->type) {
  445.     case HOST_ALIAS:
  446.         if (indirectAlias (h->entry.aliasName, clientAddress,
  447.                    connectionType, function, closure, depth,
  448.                    broadcast))
  449.         haveLocalhost = 1;
  450.         break;
  451.     case HOST_ADDRESS:
  452.         if (XdmcpARRAY8Equal (getLocalAddress(), &h->entry.hostAddress))
  453.         haveLocalhost = 1;
  454.         else if (function)
  455.         (*function) (connectionType, &h->entry.hostAddress, closure);
  456.         break;
  457.     case HOST_BROADCAST:
  458.         if (broadcast)
  459.         {
  460.         ARRAY8    temp;
  461.  
  462.         if (function)
  463.         {
  464.             temp.data = (BYTE *) BROADCAST_STRING;
  465.             temp.length = strlen ((char *)temp.data);
  466.             (*function) (connectionType, &temp, closure);
  467.         }
  468.         }
  469.         break;
  470.     }
  471.     }
  472.     return haveLocalhost;
  473. }
  474.  
  475. static int
  476. patternMatch (string, pattern)
  477.     char    *string, *pattern;
  478. {
  479.     int        p, s;
  480.  
  481.     for (;;)
  482.     {
  483.     s = *string++;
  484.     switch (p = *pattern++) {
  485.     case '*':
  486.         if (!*pattern)
  487.         return TRUE;
  488.         for (string--; *string; string++)
  489.         if (patternMatch (string, pattern))
  490.             return 1;
  491.         return 0;
  492.     case '?':
  493.         if (s == 0)
  494.         return 0;
  495.         break;
  496.     case '\0':
  497.         return s == 0;
  498.     case '\\':
  499.         p = *pattern++;
  500.     default:
  501.         if (p != s)
  502.         return 0;
  503.     }
  504.     }
  505. }
  506.  
  507. static int
  508. indirectAlias (alias, clientAddress, connectionType, function, closure, depth,
  509.            broadcast)
  510.     char    *alias;
  511.     ARRAY8Ptr    clientAddress;
  512.     CARD16    connectionType;
  513.     int        (*function)();
  514.     char    *closure;
  515.     int        depth;
  516.     int        broadcast;
  517. {
  518.     DisplayEntry    *d;
  519.     int            haveLocalhost = 0;
  520.  
  521.     if (depth == MAX_DEPTH)
  522.     return 0;
  523.     for (d = database; d; d = d->next)
  524.     {
  525.     if (d->type != DISPLAY_ALIAS || !patternMatch (alias, d->entry.aliasName))
  526.         continue;
  527.     if (scanHostlist (d->hosts, clientAddress, connectionType,
  528.               function, closure, depth + 1, broadcast))
  529.     {
  530.         haveLocalhost = 1;
  531.     }
  532.     }
  533.     return haveLocalhost;
  534. }
  535.  
  536. ARRAY8Ptr IndirectChoice ();
  537.  
  538. ForEachMatchingIndirectHost (clientAddress, connectionType, function, closure)
  539.     ARRAY8Ptr    clientAddress;
  540.     CARD16    connectionType;
  541.     int        (*function)();
  542.     char    *closure;
  543. {
  544.     int            haveLocalhost = 0;
  545.     DisplayEntry    *d;
  546.     char        *clientName = 0, *NetworkAddressToHostname ();
  547.  
  548.     for (d = database; d; d = d->next)
  549.     {
  550.         switch (d->type) {
  551.         case DISPLAY_ALIAS:
  552.         continue;
  553.         case DISPLAY_PATTERN:
  554.         if (!clientName)
  555.         clientName = NetworkAddressToHostname (connectionType,
  556.                                clientAddress);
  557.         if (!patternMatch (clientName, d->entry.displayPattern))
  558.         continue;
  559.         break;
  560.         case DISPLAY_ADDRESS:
  561.         if (d->entry.displayAddress.connectionType != connectionType ||
  562.             !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
  563.                   clientAddress))
  564.         {
  565.         continue;
  566.         }
  567.         break;
  568.         }
  569.     if (!d->hosts)
  570.         continue;
  571.     if (d->notAllowed)
  572.         break;
  573.     if (d->chooser)
  574.     {
  575.         ARRAY8Ptr    choice;
  576.  
  577.         choice = IndirectChoice (clientAddress, connectionType);
  578.         if (!choice || XdmcpARRAY8Equal (getLocalAddress(), choice))
  579.         haveLocalhost = 1;
  580.         else
  581.         (*function) (connectionType, choice, closure);
  582.     }
  583.     else if (scanHostlist (d->hosts, clientAddress, connectionType,
  584.               function, closure, 0, FALSE))
  585.     {
  586.         haveLocalhost = 1;
  587.     }
  588.     break;
  589.     }
  590.     if (clientName)
  591.     free (clientName);
  592.     return haveLocalhost;
  593. }
  594.  
  595. UseChooser (clientAddress, connectionType)
  596.     ARRAY8Ptr    clientAddress;
  597.     CARD16    connectionType;
  598. {
  599.     DisplayEntry    *d;
  600.     char        *clientName = 0, *NetworkAddressToHostname ();
  601.  
  602.     for (d = database; d; d = d->next)
  603.     {
  604.         switch (d->type) {
  605.         case DISPLAY_ALIAS:
  606.         continue;
  607.         case DISPLAY_PATTERN:
  608.         if (!clientName)
  609.         clientName = NetworkAddressToHostname (connectionType,
  610.                                clientAddress);
  611.         if (!patternMatch (clientName, d->entry.displayPattern))
  612.         continue;
  613.         break;
  614.         case DISPLAY_ADDRESS:
  615.         if (d->entry.displayAddress.connectionType != connectionType ||
  616.             !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
  617.                   clientAddress))
  618.         {
  619.         continue;
  620.         }
  621.         break;
  622.         }
  623.     if (!d->hosts)
  624.         continue;
  625.     if (d->notAllowed)
  626.         break;
  627.     if (d->chooser && !IndirectChoice (clientAddress, connectionType))
  628.         return 1;
  629.     break;
  630.     }
  631.     return 0;
  632. }
  633.  
  634. ForEachChooserHost (clientAddress, connectionType, function, closure)
  635.     ARRAY8Ptr    clientAddress;
  636.     CARD16    connectionType;
  637.     int        (*function)();
  638.     char    *closure;
  639. {
  640.     int            haveLocalhost = 0;
  641.     DisplayEntry    *d;
  642.     char        *clientName = 0, *NetworkAddressToHostname ();
  643.  
  644.     for (d = database; d; d = d->next)
  645.     {
  646.         switch (d->type) {
  647.         case DISPLAY_ALIAS:
  648.         continue;
  649.         case DISPLAY_PATTERN:
  650.         if (!clientName)
  651.         clientName = NetworkAddressToHostname (connectionType,
  652.                                clientAddress);
  653.         if (!patternMatch (clientName, d->entry.displayPattern))
  654.         continue;
  655.         break;
  656.         case DISPLAY_ADDRESS:
  657.         if (d->entry.displayAddress.connectionType != connectionType ||
  658.             !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
  659.                   clientAddress))
  660.         {
  661.         continue;
  662.         }
  663.         break;
  664.         }
  665.     if (!d->hosts)
  666.         continue;
  667.     if (d->notAllowed)
  668.         break;
  669.     if (!d->chooser)
  670.         break;
  671.     if (scanHostlist (d->hosts, clientAddress, connectionType,
  672.               function, closure, 0, TRUE))
  673.     {
  674.         haveLocalhost = 1;
  675.     }
  676.     break;
  677.     }
  678.     if (clientName)
  679.     free (clientName);
  680.     if (haveLocalhost)
  681.     (*function) (connectionType, getLocalAddress(), closure);
  682. }
  683.  
  684. /*
  685.  * returns TRUE if the given client is acceptable to the local host.  The
  686.  * given display client is acceptable if it occurs without a host list.
  687.  */
  688.  
  689. AcceptableDisplayAddress (clientAddress, connectionType, type)
  690.     ARRAY8Ptr    clientAddress;
  691.     CARD16    connectionType;
  692.     xdmOpCode    type;
  693. {
  694.     DisplayEntry    *d;
  695.     char        *clientName = 0, *NetworkAddressToHostname ();
  696.  
  697.     if (!*accessFile)
  698.     return 1;
  699.     if (type == INDIRECT_QUERY)
  700.     return 1;
  701.     for (d = database; d; d = d->next)
  702.     {
  703.     if (d->hosts)
  704.         continue;
  705.         switch (d->type) {
  706.         case DISPLAY_ALIAS:
  707.         continue;
  708.         case DISPLAY_PATTERN:
  709.         if (!clientName)
  710.         clientName = NetworkAddressToHostname (connectionType,
  711.                                clientAddress);
  712.         if (!patternMatch (clientName, d->entry.displayPattern))
  713.         continue;
  714.         break;
  715.         case DISPLAY_ADDRESS:
  716.         if (d->entry.displayAddress.connectionType != connectionType ||
  717.             !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
  718.                   clientAddress))
  719.         {
  720.         continue;
  721.         }
  722.         break;
  723.         }
  724.     break;
  725.     }
  726.     if (clientName)
  727.     free (clientName);
  728.     return (d != 0) && (d->notAllowed == 0);
  729. }
  730.  
  731. #endif /* XDMCP */
  732.