home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / EXTRAS / UUCODE / UUPC / TEST / UPC12ES1.ZIP / LIB / security.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-31  |  34.3 KB  |  897 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    s e c u r i t y . c                                             */
  3. /*                                                                    */
  4. /*    Security routines for UUPC/extended                             */
  5. /*                                                                    */
  6. /*    Copyright (c) 1991, Andrew H. Derbyshire                        */
  7. /*    See README.PRN for additional copyrights and restrictions       */
  8. /*--------------------------------------------------------------------*/
  9.  
  10. /*--------------------------------------------------------------------*/
  11. /*                          RCS Information                           */
  12. /*--------------------------------------------------------------------*/
  13.  
  14. /*
  15.  *    $Id: security.c 1.12 1993/10/31 15:51:11 ahd Exp $
  16.  *
  17.  *    Revision history:
  18.  *    $Log: security.c $
  19.  *     Revision 1.12  1993/10/31  15:51:11  ahd
  20.  *     Allow configuring permissions file name
  21.  *
  22.  *     Revision 1.11  1993/10/30  02:29:46  ahd
  23.  *     Trim trailing slash from root directories
  24.  *
  25.  *     Revision 1.11  1993/10/30  02:29:46  ahd
  26.  *     Trim trailing slash from root directories
  27.  *
  28.  *     Revision 1.10  1993/10/12  00:46:16  ahd
  29.  *     Normalize comments
  30.  *
  31.  *     Revision 1.9  1993/10/03  20:37:34  ahd
  32.  *     Lower case all strings loaded into directory array
  33.  *
  34.  *     Revision 1.8  1993/09/20  04:38:11  ahd
  35.  *     TCP/IP support from Dave Watt
  36.  *     't' protocol support
  37.  *     OS/2 2.x support
  38.  *
  39.  *     Revision 1.7  1993/08/03  03:11:49  ahd
  40.  *     Make missing directories non-fatal
  41.  *
  42.  *     Revision 1.6  1993/05/06  03:41:48  ahd
  43.  *     Use NULL to denote current directory, not "."
  44.  *
  45.  *     Revision 1.5  1993/04/11  00:31:04  ahd
  46.  *     Global edits for year, TEXT, etc.
  47.  *
  48.  *     Revision 1.4  1993/03/06  22:48:23  ahd
  49.  *     Re-do compare of sort to void bug in some qsort() functions
  50.  *
  51.  * Revision 1.3  1992/11/22  20:58:55  ahd
  52.  * Normalize directories as read
  53.  * Use strpool to allocate const strings
  54.  *
  55.  * Revision 1.2  1992/11/19  02:57:31  ahd
  56.  * drop rcsid
  57.  *
  58.  * Revision 1.1  1992/11/16  05:00:26  ahd
  59.  * Initial revision
  60.  *
  61.  */
  62.  
  63. /*--------------------------------------------------------------------*/
  64. /*                        System include files                        */
  65. /*--------------------------------------------------------------------*/
  66.  
  67. #include <stdio.h>
  68. #include <stdlib.h>
  69. #include <ctype.h>
  70. #include <string.h>
  71. #include <sys/types.h>        /* Only really needed for MS C          */
  72. #include <sys/stat.h>
  73. #include <time.h>
  74. #include <direct.h>
  75.  
  76. /*--------------------------------------------------------------------*/
  77. /*                    UUPC/extended include files                     */
  78. /*--------------------------------------------------------------------*/
  79.  
  80. #include "lib.h"
  81. #include "hostable.h"
  82. #include "security.h"
  83. #include "usertabl.h"
  84. #include "expath.h"
  85. #include "hlib.h"
  86.  
  87. /*--------------------------------------------------------------------*/
  88. /*                           Local defines                            */
  89. /*--------------------------------------------------------------------*/
  90.  
  91. static boolean InitEntry( char *buf, const char *fname);
  92.  
  93. static size_t InitDir( char *directories,
  94.          const REMOTE_ACCESS access,
  95.          const boolean grant,
  96.          struct HostSecurity *anchor,
  97.          size_t max_elements );
  98.  
  99. int dircmp( const void *a , const void *b );
  100.  
  101. /*--------------------------------------------------------------------*/
  102. /*                          Global varables                           */
  103. /*--------------------------------------------------------------------*/
  104.  
  105. struct HostSecurity *securep = NULL;
  106. static struct HostSecurity *default_security = NULL;
  107. static char drive[] = "C:";
  108.  
  109. currentfile();
  110.  
  111. /*--------------------------------------------------------------------*/
  112. /*    L o a d S e c u r i t y                                         */
  113. /*                                                                    */
  114. /*    Initialize security processing; returns TRUE if security        */
  115. /*    initialized, otherewise FALSE                                   */
  116. /*--------------------------------------------------------------------*/
  117.  
  118. boolean LoadSecurity( void )
  119. {
  120.    char buffer[BUFSIZ*4];     /* Allows around 2K for the data        */
  121.    struct HostTable *hostp;
  122.    FILE *stream;
  123.  
  124. /*--------------------------------------------------------------------*/
  125. /*      Generate a filename for the permissions file and open it      */
  126. /*--------------------------------------------------------------------*/
  127.  
  128.    stream  = FOPEN( E_permissions, "r",TEXT_MODE);
  129.  
  130.    if ( stream == NULL )      /* Did the file open?                   */
  131.    {                          /* No --> Report failure to caller      */
  132.       printerr( E_permissions );
  133.       return FALSE;
  134.    } /* ( stream == NULL ) */
  135.  
  136. /*--------------------------------------------------------------------*/
  137. /*              Get current drive for normalizing names               */
  138. /*--------------------------------------------------------------------*/
  139.  
  140.    getcwd( buffer, sizeof buffer );
  141.    *drive = *buffer;
  142.  
  143. /*--------------------------------------------------------------------*/
  144. /*               Begin processing the PERMISSIONS file                */
  145. /*--------------------------------------------------------------------*/
  146.  
  147.    while ( !feof( stream ) )
  148.    {
  149.       char *next = buffer;
  150.  
  151. /*--------------------------------------------------------------------*/
  152. /*                Build up the buffer to be processed                 */
  153. /*--------------------------------------------------------------------*/
  154.  
  155.       *next = '\0';
  156.       while( fgets( next, sizeof buffer - strlen(next), stream ) != NULL)
  157.       {
  158.          if ((*next == '#') || (*next == '\n'))
  159.          {
  160.             *next = '\0';
  161.             continue;
  162.          }
  163.  
  164.          next = next + strlen( next ) - 1;
  165.          if (*next == '\n')
  166.             *next-- = '\0';
  167.          else if (!feof( stream ))  /* Did we hit EOF?                */
  168.          {                    /* No --> Presume the buffer overflowed*/
  169.             printmsg(0,"LoadSecurity: buffer overflow while reading %s",
  170.                        E_permissions );
  171.             fclose( stream );
  172.             return FALSE;
  173.          }
  174.  
  175.          while( isspace( *next ))   /* Dump trailing white space      */
  176.             *next-- = '\0';
  177.  
  178.          if (*next == '\\')
  179.             *next = '\0';
  180.          else
  181.             break;
  182.       } /* while( fgets( next, sizeof available, stream )) != NULL))  */
  183.  
  184. /*--------------------------------------------------------------------*/
  185. /*            Done read the data; verify we had no errors             */
  186. /*--------------------------------------------------------------------*/
  187.  
  188.       if (ferror( stream ))
  189.       {
  190.          printerr( E_permissions );
  191.          clearerr( stream );
  192.          return FALSE;
  193.       } /* if */
  194.  
  195. /*--------------------------------------------------------------------*/
  196. /*              Build entries for one permissions entry               */
  197. /*--------------------------------------------------------------------*/
  198.  
  199.       printmsg(10,"Buffer is \"%s\"", buffer );
  200.       if ((*next != '\0') && !InitEntry( buffer , E_permissions))
  201.       {
  202.          fclose( stream );
  203.          return FALSE;
  204.       }
  205.  
  206.    } /* while ( !feof( stream ) ) */
  207.  
  208. /*--------------------------------------------------------------------*/
  209. /*                    Initialize local host entry                     */
  210. /*--------------------------------------------------------------------*/
  211.  
  212.    hostp = checkname( E_nodename );
  213.    if ( hostp == NULL )
  214.       panic();
  215.    hostp->hsecure = malloc( sizeof *hostp->hsecure );
  216.    checkref( hostp->hsecure );
  217.    memset( hostp->hsecure , '\0', sizeof *hostp->hsecure);
  218.                               /* Clear pointers                       */
  219.    hostp->hsecure->local = TRUE;
  220.  
  221. /*--------------------------------------------------------------------*/
  222. /*                          Return to caller                          */
  223. /*--------------------------------------------------------------------*/
  224.  
  225.    fclose( stream );
  226.    return TRUE;
  227.  
  228. } /* LoadSecurity */
  229.  
  230. /*--------------------------------------------------------------------*/
  231. /*    I n i t i a l i z e E n t r y                                   */
  232. /*                                                                    */
  233. /*    Initialize a single permissions file entry                      */
  234. /*--------------------------------------------------------------------*/
  235.  
  236. static boolean InitEntry( char *buf, const char *fname)
  237. {
  238.  
  239. /*--------------------------------------------------------------------*/
  240. /*                      Configuration variables                       */
  241. /*--------------------------------------------------------------------*/
  242.  
  243.   static char *myname, *validate, *commands;
  244.  
  245.   static char *callback, *xpubdir, *machine, *noread, *nowrite;
  246.   static char *request, *read, *sendfiles,  *write, *logname;
  247.  
  248.   static CONFIGTABLE securetable[] = {
  249.      { "callback",      &callback,     B_TOKEN  | B_UUXQT } ,
  250.      { "commands",      &commands,     B_CLIST  | B_UUXQT } ,
  251.      { "logname",       &logname,      B_TOKEN  | B_UUXQT } ,
  252.      { "machine",       &machine,      B_TOKEN  | B_UUXQT | B_MALLOC } ,
  253.      { "myname",        &myname,       B_TOKEN  | B_UUXQT } ,
  254.      { "pubdir",        &xpubdir,      B_PATH   | B_UUXQT } ,
  255.      { "noread",        &noread,       B_TOKEN  | B_UUXQT | B_MALLOC } ,
  256.      { "nowrite",       &nowrite,      B_TOKEN  | B_UUXQT | B_MALLOC } ,
  257.      { "read",          &read,         B_TOKEN  | B_UUXQT | B_MALLOC} ,
  258.      { "request",       &request,      B_TOKEN  | B_UUXQT } ,
  259.      { "sendfiles",     &sendfiles,    B_TOKEN  | B_UUXQT } ,
  260.      { "validate",      &validate,     B_CLIST  | B_UUXQT } ,
  261.      { "write",         &write,        B_TOKEN  | B_UUXQT | B_MALLOC } ,
  262.      { nil(char) }
  263. }; /* securetable */
  264.  
  265.    struct HostSecurity *anchor = malloc( sizeof *anchor );
  266.  
  267. /*--------------------------------------------------------------------*/
  268. /*                  Default list of allowed commands                  */
  269. /*--------------------------------------------------------------------*/
  270.  
  271.    static char *command_list[] = { "rmail", "rnews" , NULL } ;
  272.  
  273. /*--------------------------------------------------------------------*/
  274. /*                          Other variables                           */
  275. /*--------------------------------------------------------------------*/
  276.  
  277.    boolean success = TRUE;
  278.    CONFIGTABLE *tptr;
  279.    char *token = buf;
  280.    char *parameter;
  281.    struct UserTable *userp;
  282.    struct HostTable *hostp;
  283.    size_t max_elements = 16;
  284.  
  285. /*--------------------------------------------------------------------*/
  286. /*                 Initialize the security structure                  */
  287. /*--------------------------------------------------------------------*/
  288.  
  289.    checkref( anchor );
  290.    memset( anchor , '\0', sizeof *anchor); /* Clear pointers          */
  291.  
  292. /*--------------------------------------------------------------------*/
  293. /*                        Initialize the table                        */
  294. /*--------------------------------------------------------------------*/
  295.  
  296.    for (tptr = securetable; tptr->sym != nil(char); tptr++)
  297.       if (tptr->bits & (B_TOKEN | B_STRING | B_LIST| B_CLIST))
  298.          *(tptr->loc) = nil(char);
  299.  
  300. /*--------------------------------------------------------------------*/
  301. /*                 Parse the information in the table                 */
  302. /*--------------------------------------------------------------------*/
  303.  
  304.    while ( (parameter = strtok( token, WHITESPACE )) != NULL)
  305.    {
  306.       token = strtok( NULL, ""); /* Save for next pass                */
  307. #ifdef _DEBUG
  308.       printmsg(8,"InitEntry: Parameter is \"%s\"", parameter);
  309.       if ( token != NULL )
  310.          printmsg(10,"InitEntry: Buffer remaining is \"%s\"", token);
  311. #endif
  312.       if (!processconfig(parameter, SYSTEM_CONFIG,B_UUXQT,securetable,NULL))
  313.       {
  314.          printmsg(0,
  315.           "Unknown keyword \"%s\" in %s ignored",parameter, fname);
  316.          success = FALSE;
  317.       } /* if */
  318.    } /* while ( (parameter = strtok( token, WHITESPACE )) != NULL) */
  319.  
  320.    anchor->commands = (char **) commands;
  321.    anchor->validate = (char **) validate;
  322.  
  323. /*--------------------------------------------------------------------*/
  324. /*    Now we have the data procesed by keyword, break it down more    */
  325. /*--------------------------------------------------------------------*/
  326.  
  327.    if ((logname == NULL) && (machine == NULL))
  328.    {
  329.       printmsg(0,"InitEntry: No machine or logname given in %s",
  330.                   fname );
  331.       success = FALSE;
  332.    } /* if ((logname == NULL) && (machine == NULL)) */
  333.  
  334. /*--------------------------------------------------------------------*/
  335. /*                        Handle a login name                         */
  336. /*--------------------------------------------------------------------*/
  337.  
  338.    if (logname != NULL)
  339.    {
  340.       printmsg(10,"InitEntry: Processing logname=%s",logname );
  341.       userp = checkuser( logname );
  342.       if ( userp == BADUSER )
  343.       {
  344.          printmsg(0,"InitEntry: Invalid user id in %s, LOGNAME=%s",
  345.                      fname, logname );
  346.          success = FALSE;
  347.       } /* if ( userp == BADUSER ) */
  348.       else if (userp->hsecure == NULL)
  349.          userp->hsecure = anchor;
  350.       else {
  351.          printmsg(0,"InitEntry: Duplicate user id in %s, LOGNAME=%s",
  352.                      fname, logname );
  353.          success = FALSE;
  354.       } /* else */
  355.    } /* if (logname != NULL) */
  356.  
  357. /*--------------------------------------------------------------------*/
  358. /*                        Handle machine names                        */
  359. /*--------------------------------------------------------------------*/
  360.  
  361.    token = machine;
  362.    while( token != NULL )
  363.    {
  364.       char *host = strtok( token, ":");
  365.       printmsg(10,"InitEntry: Processing machine=%s", host );
  366.  
  367.       token = strtok( NULL, "");
  368.       if ( equal( host , ANY_HOST ) )
  369.       {
  370.          if ( default_security == NULL )
  371.             default_security = anchor;
  372.          else {
  373.             printmsg(0,"InitEntry: "
  374.                        "Multiple MACHINE entries in %s which specify OTHER",
  375.                        fname);
  376.             success = FALSE;
  377.          } /* else */
  378.       } /* if ( equal( host , ANY_HOST ) ) */
  379.       else {
  380.          hostp = checkreal( host );
  381.          if ( hostp == BADUSER )
  382.          {
  383.             printmsg(0,"InitEntry: Invalid host id in %s, MACHINE=%s",
  384.                         fname, host );
  385.             success = FALSE;
  386.          } /* if ( hostp == BADUSER ) */
  387.          else if (hostp->hsecure == NULL)
  388.             hostp->hsecure = anchor;
  389.          else {
  390.             printmsg(0,"InitEntry: Duplicate host id in %s, MACHINE=%s",
  391.                         fname, token );
  392.             success = FALSE;
  393.          } /* else */
  394.       } /* else */
  395.    } /* while( token != NULL ) */
  396.  
  397.    if ( machine != NULL )
  398.       free( machine );
  399.  
  400. /*--------------------------------------------------------------------*/
  401. /*                       Handle validated names                       */
  402. /*--------------------------------------------------------------------*/
  403.  
  404.    if ( anchor->validate != NULL )
  405.    {
  406.       char **plist = anchor->validate;
  407.  
  408.       while ( *plist != NULL )
  409.       {
  410.          hostp = checkreal( *plist );
  411.  
  412.          if ( hostp == BADUSER )
  413.          {
  414.             printmsg(0,"InitEntry: Invalid host id in %s, VALIDATE=%s",
  415.                         fname, *plist);
  416.             success = FALSE;
  417.          } /* if ( hostp == BADUSER ) */
  418.          else
  419.             hostp->anylogin = FALSE;   /* Flag we must use specific
  420.                                           login                       */
  421.  
  422.          plist++;             /* Step to next hostname in list        */
  423.  
  424.       } /* while ( *plist != NULL ) */
  425.  
  426.    } /* if ( anchor->validate != NULL ) */
  427.  
  428. /*--------------------------------------------------------------------*/
  429. /*                          Handle CALLBACK                           */
  430. /*--------------------------------------------------------------------*/
  431.  
  432.    if ( callback != NULL )
  433.    {
  434.       if (equal(strlwr(callback),"no"))
  435.          anchor->callback = FALSE;
  436.       else if (equal(callback,"yes"))
  437.          anchor->callback = TRUE;
  438.       else {
  439.          printmsg(0,"InitEntry: Invalid value in %s, CALLBACK=%s",
  440.                      fname, callback );
  441.          success = FALSE;
  442.       } /* else */
  443.    } /* if ( callback != NULL ) */
  444.  
  445. /*--------------------------------------------------------------------*/
  446. /*                          Handle REQUEST                            */
  447. /*--------------------------------------------------------------------*/
  448.  
  449.    if ( request != NULL )
  450.    {
  451.       if (equal(strlwr(request),"no"))
  452.          anchor->request = FALSE;
  453.       else if (equal(request,"yes"))
  454.          anchor->request = TRUE;
  455.       else {
  456.          printmsg(0,"InitEntry: Invalid value in %s, REQUEST=%s",
  457.                      fname, request );
  458.          success = FALSE;
  459.       } /* else */
  460.  
  461.    } /* if ( request != NULL ) */
  462.  
  463. /*--------------------------------------------------------------------*/
  464. /*                          Handle SENDFILES                          */
  465. /*--------------------------------------------------------------------*/
  466.  
  467.    if ( sendfiles != NULL)
  468.    {
  469.       if (equal(strlwr(sendfiles),"call"))
  470.          anchor->sendfiles = FALSE;
  471.       else if (equal(sendfiles,"yes"))
  472.          anchor->sendfiles = TRUE;
  473.       else {
  474.          printmsg(0,"InitEntry: Invalid value in %s, SENDFILES=%s",
  475.                      fname, sendfiles );
  476.          success = FALSE;
  477.       } /* else */
  478.    } /* if */
  479.  
  480. /*--------------------------------------------------------------------*/
  481. /*                          handle commands                           */
  482. /*--------------------------------------------------------------------*/
  483.  
  484.    if ( anchor->commands == NULL )
  485.       anchor->commands = command_list;
  486.  
  487. /*--------------------------------------------------------------------*/
  488. /*                 Handle local system name aliasing                  */
  489. /*--------------------------------------------------------------------*/
  490.  
  491.    if (myname == NULL)
  492.       anchor->myname = E_nodename;
  493.    else
  494.       anchor->myname = myname;
  495.  
  496. /*--------------------------------------------------------------------*/
  497. /*                      Directory processing                          */
  498. /*--------------------------------------------------------------------*/
  499.  
  500.    anchor->dirlist = malloc( sizeof anchor->dirlist[0] * max_elements );
  501.    checkref( anchor->dirlist );
  502.  
  503.    max_elements = InitDir( read,    ALLOW_READ,  TRUE,  anchor,
  504.             max_elements );
  505.    free( read );
  506.    max_elements = InitDir( noread,  ALLOW_READ,  FALSE, anchor,
  507.             max_elements );
  508.    free( noread );
  509.    max_elements = InitDir( write,   ALLOW_WRITE, TRUE,  anchor,
  510.             max_elements );
  511.    free( write );
  512.    max_elements = InitDir( nowrite, ALLOW_WRITE, FALSE, anchor,
  513.                            max_elements );
  514.    free( nowrite );
  515.  
  516. /*--------------------------------------------------------------------*/
  517. /*                 Provide a default public directory                 */
  518. /*--------------------------------------------------------------------*/
  519.  
  520.    if (xpubdir == NULL)
  521.        anchor->pubdir = E_pubdir;
  522.    else
  523.        anchor->pubdir = xpubdir;
  524.  
  525. /*--------------------------------------------------------------------*/
  526. /*    If no explicit directories given, give them access to pubdir    */
  527. /*--------------------------------------------------------------------*/
  528.  
  529.    if ( anchor->dirsize == 0)
  530.    {
  531.       max_elements = InitDir( anchor->pubdir, ALLOW_READ, TRUE,
  532.                               anchor, max_elements );
  533.       max_elements = InitDir( anchor->pubdir, ALLOW_WRITE, TRUE,
  534.                               anchor, max_elements );
  535.    }
  536.  
  537.    if ( max_elements == 0 )
  538.       success = FALSE;
  539.    else {
  540.       size_t subscript;
  541.       anchor->dirlist = realloc( anchor->dirlist,
  542.                                  anchor->dirsize * sizeof anchor->dirlist[0]);
  543.       checkref( anchor->dirlist );
  544.       qsort(anchor->dirlist, anchor->dirsize, sizeof(anchor->dirlist[0]),
  545.                dircmp);
  546.       if ( debuglevel > 4 )
  547.       for ( subscript = 0; subscript < anchor->dirsize; subscript++ )
  548.          printmsg(4, "InitEntry: dirlist[%d] %s\t%s\t%s",
  549.                   subscript,
  550.                   anchor->dirlist[subscript].grant ? "grant" : "deny" ,
  551.                   anchor->dirlist[subscript].priv == ALLOW_WRITE ?
  552.                            "WRITE" : "READ" ,
  553.                   anchor->dirlist[subscript].path );
  554.    } /* else */
  555.  
  556. /*--------------------------------------------------------------------*/
  557. /*                          Return to caller                          */
  558. /*--------------------------------------------------------------------*/
  559.  
  560.    return success;
  561.  
  562. } /* InitEntry */
  563.  
  564. /*--------------------------------------------------------------------*/
  565. /*    I n i t D i r                                                   */
  566. /*                                                                    */
  567. /*    Initialize security table directory entries                     */
  568. /*--------------------------------------------------------------------*/
  569.  
  570. static size_t InitDir( char *directories,
  571.          const REMOTE_ACCESS access,
  572.          const boolean grant,
  573.          struct HostSecurity *anchor,
  574.          size_t max_elements )
  575. {
  576.    char *field = directories;
  577.    char *token = directories;
  578.    struct  stat    statbuf;
  579.    size_t subscript;
  580.  
  581. /*--------------------------------------------------------------------*/
  582. /*    Don't process data if no input or we previously had an error    */
  583. /*--------------------------------------------------------------------*/
  584.  
  585.    if ( (directories == NULL ) || ( max_elements == 0) )
  586.       return max_elements;
  587.  
  588. /*--------------------------------------------------------------------*/
  589. /*              Begin loop to process names in the path               */
  590. /*--------------------------------------------------------------------*/
  591.  
  592.    while ( (token = NextField( field )) != NULL)
  593.    {
  594.       char path[FILENAME_MAX];
  595.       if ( anchor->dirsize == max_elements )
  596.       {
  597.          max_elements = max_elements * 2;
  598.          anchor->dirlist = realloc( anchor->dirlist,
  599.                 sizeof anchor->dirlist[0] * max_elements );
  600.          checkref( anchor->dirlist );
  601.       }
  602.  
  603. /*--------------------------------------------------------------------*/
  604. /*                      Normalize directory name                      */
  605. /*--------------------------------------------------------------------*/
  606.  
  607.       strcpy( path, token);
  608.       if (isalpha(path[0]) && (path[1] != ':') && (strlen(path) == 2))
  609.          ;                 /* Yup, do nothing for root drive names  */
  610.       else if ( expand_path( path, NULL, E_pubdir , NULL) == NULL )
  611.       {
  612.          printmsg(0, "Unable to expand path \"%s\"",path );
  613.          return 0;
  614.       } /* else */
  615.  
  616.       field = normalize( path );
  617.  
  618. /*--------------------------------------------------------------------*/
  619. /*       Normalize leaves a slash on root directories, which we       */
  620. /*       don't want in our table, so delete if it exists.             */
  621. /*--------------------------------------------------------------------*/
  622.  
  623.       if (( strlen( field ) == 3 ) &&
  624.           isalpha( *field ) && equal( field + 1 , ":/"))
  625.          field[2] = '\0';
  626.  
  627.       strlwr( field );           /* Lower case for compares           */
  628.       field = newstr( field );   /* Save the path for insert in table */
  629.  
  630. /*--------------------------------------------------------------------*/
  631. /*               Verify it really is a valid directory                */
  632. /*--------------------------------------------------------------------*/
  633.  
  634.       if ( strlen( field ) > 2 ) /* More than just drive/colon? (x:)  */
  635.       {                       /* Yes --> Go check disk for path       */
  636.          if (stat(field , &statbuf) != 0)
  637.          {
  638.             printmsg(0,"Warning ... invalid PERMISSIONS file entry %s:",
  639.                        token );
  640.             printerr(field);
  641.          }
  642.          else if ((statbuf.st_mode & S_IFDIR) == 0)
  643.          {
  644.             printmsg(0,"InitDir: \"%s\" is a file, not a directory",
  645.                         field);
  646.             return 0;
  647.          }
  648.       } /* if ( strlen( field ) > 2 ) */
  649.  
  650. /*--------------------------------------------------------------------*/
  651. /*           Verify this directory not already in the list            */
  652. /*--------------------------------------------------------------------*/
  653.  
  654.       for (subscript = 0; subscript < anchor->dirsize ; subscript++)
  655.       {
  656.          if ( (access == anchor->dirlist[subscript].priv) &&
  657.               equal( field, anchor->dirlist[subscript].path))
  658.          {
  659.             printmsg(0,"InitDir: Duplicate directory %s/", field);
  660.             return 0;
  661.          } /* if */
  662.       } /* for */
  663.  
  664. /*--------------------------------------------------------------------*/
  665. /*            No conflict, add this directory to the list             */
  666. /*--------------------------------------------------------------------*/
  667.  
  668.       printmsg(10,"InitDir: Adding \"%s\" as \"%s\"", token , field);
  669.       anchor->dirlist[subscript].path  = field;
  670.       anchor->dirlist[subscript].priv  = access;
  671.       anchor->dirlist[subscript].grant = grant;
  672.       anchor->dirsize++;
  673.  
  674.       field = NULL;           /* Look at next field next pass         */
  675.  
  676.    } /* while ( (field = NextField( field )) != NULL) */
  677.  
  678. /*--------------------------------------------------------------------*/
  679. /*                          Return to caller                          */
  680. /*--------------------------------------------------------------------*/
  681.  
  682.    return max_elements;
  683. } /* InitDir */
  684.  
  685. /*--------------------------------------------------------------------*/
  686. /*    d i r c m p                                                     */
  687. /*                                                                    */
  688. /*                                                                    */
  689. /*    Compares two directory structures for sorting                   */
  690. /*--------------------------------------------------------------------*/
  691.  
  692. int dircmp( const void *a , const void *b )
  693. {
  694.    struct DIRLIST *x = (struct DIRLIST*) a;
  695.    struct DIRLIST *y = (struct DIRLIST*) b;
  696.  
  697.    int result = strcmp(x->path, y->path);
  698.  
  699.    if (result == 0 && (x->priv != y->priv))
  700.       result = ( x->priv < y->priv ) ? -1 : 1;
  701.  
  702.    return result;
  703. }  /*dircmp*/
  704.  
  705. /*--------------------------------------------------------------------*/
  706. /*    V a l i d a t e H o s t                                         */
  707. /*                                                                    */
  708. /*    Determine that a host is allowed for a specific login           */
  709. /*--------------------------------------------------------------------*/
  710.  
  711. boolean ValidateHost( const char *host )
  712. {
  713.    char **target;
  714.  
  715. /*--------------------------------------------------------------------*/
  716. /*      If this host has no security profile, reject the access       */
  717. /*--------------------------------------------------------------------*/
  718.  
  719.    if ( securep == NULL )
  720.       return FALSE;
  721.  
  722. /*--------------------------------------------------------------------*/
  723. /*    If we allow any host on this user id, use it if the calling     */
  724. /*    host is not supported any other profile                         */
  725. /*--------------------------------------------------------------------*/
  726.  
  727.    target = securep->validate;
  728.    if ( target == NULL )      /* No validate list for this user?      */
  729.    {                          /* Correct --> Use if none for host     */
  730.       struct HostTable *hostp = checkreal( host );
  731.       if ( hostp == BADHOST ) /* Host exist?                          */
  732.          panic();             /* No --> Internal error, abort         */
  733.  
  734.       return hostp->anylogin; /* Allow action if generic access
  735.                                  allowed for host                     */
  736.    }  /* if ( target == NULL ) */
  737.  
  738. /*--------------------------------------------------------------------*/
  739. /*          Determine if this host is allowed for this login          */
  740. /*--------------------------------------------------------------------*/
  741.  
  742.    while (*target != NULL)
  743.    {
  744.       if ( equal(*target++, host ))
  745.          return TRUE;
  746.    } /* (*target != NULL) */
  747.  
  748. /*--------------------------------------------------------------------*/
  749. /*                 We didn't find the host; reject it                 */
  750. /*--------------------------------------------------------------------*/
  751.  
  752.    return FALSE;
  753.  
  754. } /* ValidateHost */
  755.  
  756. /*--------------------------------------------------------------------*/
  757. /*    V a l i d a t e F i l e                                         */
  758. /*                                                                    */
  759. /*    Allow or reject access to a file by name                        */
  760. /*--------------------------------------------------------------------*/
  761.  
  762. boolean ValidateFile( const char *input,  /* Full path name           */
  763.                       const REMOTE_ACCESS needed )
  764. {
  765.    char path[FILENAME_MAX];
  766.    char *column;
  767.  
  768. /*--------------------------------------------------------------------*/
  769. /*                  Validate the length of the name                   */
  770. /*--------------------------------------------------------------------*/
  771.  
  772.    printmsg(5,"ValidateFile: Checking %s access for file \"%s\"",
  773.             (needed == ALLOW_WRITE) ? "WRITE" : "READ" , input);
  774.  
  775.    if ( strlen( input ) >= sizeof path)   /* Reject all invalid names*/
  776.    {
  777.       printmsg(0,"ValidateFile: Access rejected, name too long: %s",
  778.                  input);
  779.       return FALSE;
  780.    }
  781.  
  782. /*--------------------------------------------------------------------*/
  783. /*     Validate format of name; we don't allow parent directories     */
  784. /*--------------------------------------------------------------------*/
  785.  
  786.    if ( strstr( input, "..") )            /* Games with parent dir?   */
  787.    {
  788.       printmsg(0,"ValidateFile: Access rejected, name not normalized: %s",
  789.                  input);
  790.       return FALSE;
  791.    }
  792.  
  793. /*--------------------------------------------------------------------*/
  794. /*                Validate the security table is okay                 */
  795. /*--------------------------------------------------------------------*/
  796.  
  797.    if ( securep == NULL )
  798.       panic();
  799.  
  800. /*--------------------------------------------------------------------*/
  801. /*                        Handle local system                         */
  802. /*--------------------------------------------------------------------*/
  803.  
  804.    if ( securep->local )      /* Local system?                        */
  805.       return TRUE;            /* Yes --> Bless the request            */
  806.  
  807. /*--------------------------------------------------------------------*/
  808. /*       Determine if the user is allowed to request files            */
  809. /*--------------------------------------------------------------------*/
  810.  
  811.    if ((needed == ALLOW_READ) && !securep->request)
  812.    {
  813.       printmsg(0,"ValidateFile: access rejected, "
  814.                  "REQUEST not enabled in permissions file");
  815.       return FALSE;
  816.    }
  817.  
  818. /*--------------------------------------------------------------------*/
  819. /*                           Copy path name                           */
  820. /*--------------------------------------------------------------------*/
  821.  
  822.    if ( input[1] == ':' )
  823.       strcpy( path, input );
  824.    else
  825.       strcat( strcpy( path , drive ), input );
  826.    strlwr( path );
  827.  
  828. /*--------------------------------------------------------------------*/
  829. /*              Locate the best file match for the path               */
  830. /*--------------------------------------------------------------------*/
  831.  
  832.    while( (column = strrchr( path, '/')) != NULL )
  833.    {
  834.       int lower = 0;
  835.       int upper = securep->dirsize - 1;
  836.  
  837.       *column = '\0';
  838.       printmsg(10,"ValidateFile: Searching for %s", path);
  839.  
  840.       while( lower <= upper )
  841.       {
  842.          int midpoint = (lower + upper) / 2;
  843.          int hit = strcmp(path, securep->dirlist[midpoint].path);
  844.  
  845.          printmsg(10,"ValidateFile: Comparing %s and %s",
  846.                         path, securep->dirlist[midpoint].path);
  847.  
  848.          if ( hit == 0 )
  849.             hit = (int) needed - (int) securep->dirlist[midpoint].priv;
  850.  
  851.          if (hit > 0)
  852.             lower = midpoint + 1;
  853.          else if (hit < 0)
  854.             upper = midpoint - 1;
  855.          else {
  856.             printmsg( securep->dirlist[midpoint].grant ? 5 : 0 ,
  857.                      "ValidateFile: Found path \"%s\", access %s to \"%s\"",
  858.                      securep->dirlist[midpoint].path,
  859.                      securep->dirlist[midpoint].grant ?
  860.                                     "granted" : "denied", input);
  861.             return securep->dirlist[midpoint].grant;
  862.          }
  863.       } /* while( lower <= upper ) */
  864.    } /* while( (column = strrchr( path, '/')) != NULL ) */
  865.  
  866. /*--------------------------------------------------------------------*/
  867. /*          We didn't find the file; reject all access to it          */
  868. /*--------------------------------------------------------------------*/
  869.  
  870.    printmsg(0,"ValidateFile: No access definition found for \
  871. \"%s\", access denied",
  872.             input);
  873.    return FALSE;
  874.  
  875. } /* ValidateFile */
  876.  
  877.  
  878. /*--------------------------------------------------------------------*/
  879. /*    G e t S e c u r i t y                                           */
  880. /*                                                                    */
  881. /*    Return security structure for to use when calling out to        */
  882. /*    another system                                                  */
  883. /*--------------------------------------------------------------------*/
  884.  
  885. struct HostSecurity *GetSecurity( struct HostTable *hostp)
  886. {
  887.    if ((hostp->hsecure == NULL) && (default_security != NULL ))
  888.    {
  889.       printmsg(2,"GetSecurity: Using security for MACHINE=OTHER for \
  890. system \"%s\"", hostp->hostname );
  891.       hostp->hsecure = default_security;
  892.    } /* if  */
  893.  
  894.    return hostp->hsecure;
  895.  
  896. } /* GetSecurity */
  897.