/*--------------------------------------------------------------------*/
/*    s e c u r i t y . c                                             */
/*                                                                    */
/*    Security routines for UUPC/extended                             */
/*                                                                    */
/*    Copyright (c) 1991, Andrew H. Derbyshire                        */
/*    See README.PRN for additional copyrights and restrictions       */
/*--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*/
/*                          RCS Information                           */
/*--------------------------------------------------------------------*/

/*
 *    $Id: SECURITY.C 1.5 1993/04/11 00:31:04 ahd Exp $
 *
 *    Revision history:
 *    $Log: SECURITY.C $
 *     Revision 1.5  1993/04/11  00:31:04  ahd
 *     Global edits for year, TEXT, etc.
 *
 *     Revision 1.4  1993/03/06  22:48:23  ahd
 *     Re-do compare of sort to void bug in some qsort() functions
 *
 * Revision 1.3  1992/11/22  20:58:55  ahd
 * Normalize directories as read
 * Use strpool to allocate const strings
 *
 * Revision 1.2  1992/11/19  02:57:31  ahd
 * drop rcsid
 *
 * Revision 1.1  1992/11/16  05:00:26  ahd
 * Initial revision
 *
 */

/*--------------------------------------------------------------------*/
/*                        System include files                        */
/*--------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>        /* Only really needed for MS C         */
#include <sys/stat.h>
#include <time.h>
#include <direct.h>

/*--------------------------------------------------------------------*/
/*                    UUPC/extended include files                     */
/*--------------------------------------------------------------------*/

#include "lib.h"
#include "hostable.h"
#include "security.h"
#include "usertabl.h"
#include "expath.h"
#include "hlib.h"

/*--------------------------------------------------------------------*/
/*                           Local defines                            */
/*--------------------------------------------------------------------*/

static boolean InitEntry( char *buf, const char *fname);

static size_t InitDir( char *directories,
         const REMOTE_ACCESS access,
         const boolean grant,
         struct HostSecurity *anchor,
         size_t max_elements );

int dircmp( const void *a , const void *b );

/*--------------------------------------------------------------------*/
/*                          Global varables                           */
/*--------------------------------------------------------------------*/

struct HostSecurity *securep = NULL;
static struct HostSecurity *default_security = NULL;
static char drive[] = "C:";

currentfile();

/*--------------------------------------------------------------------*/
/*    L o a d S e c u r i t y                                         */
/*                                                                    */
/*    Initialize security processing; returns TRUE if security        */
/*    initialized, otherewise FALSE                                   */
/*--------------------------------------------------------------------*/

boolean LoadSecurity( void )
{
   char fname[FILENAME_MAX];
   char buffer[BUFSIZ*4];     /* Allows around 2K for the data       */
   struct HostTable *hostp;
   FILE *stream;

/*--------------------------------------------------------------------*/
/*      Generate a filename for the permissions file and open it      */
/*--------------------------------------------------------------------*/

   mkfilename(fname, E_confdir, PERMISSIONS);
   stream  = FOPEN( fname, "r",TEXT_MODE);

   if ( stream == NULL )      /* Did the file open?                  */
   {                          /* No --> Report failure to caller     */
      printerr( fname );
      return FALSE;
   } /* ( stream == NULL ) */

/*--------------------------------------------------------------------*/
/*              Get current drive for normalizing names               */
/*--------------------------------------------------------------------*/

   getcwd( buffer, sizeof buffer );
   *drive = *buffer;

/*--------------------------------------------------------------------*/
/*               Begin processing the PERMISSIONS file                */
/*--------------------------------------------------------------------*/

   while ( !feof( stream ) )
   {
      char *next = buffer;

/*--------------------------------------------------------------------*/
/*                Build up the buffer to be processed                 */
/*--------------------------------------------------------------------*/

      *next = '\0';
      while( fgets( next, sizeof buffer - strlen(next), stream ) != NULL)
      {
         if ((*next == '#') || (*next == '\n'))
         {
            *next = '\0';
            continue;
         }

         next = next + strlen( next ) - 1;
         if (*next == '\n')
            *next-- = '\0';
         else if (!feof( stream ))  /* Did we hit EOF?               */
         {                    /* No --> Presume the buffer overflowed*/
            printmsg(0,"LoadSecurity: buffer overflow while reading %s",
             fname);
            fclose( stream );
            return FALSE;
         }

         while( isspace( *next ))   /* Dump trailing white space     */
            *next-- = '\0';

         if (*next == '\\')
            *next = '\0';
         else
            break;
      } /* while( fgets( next, sizeof available, stream )) != NULL)) */

/*--------------------------------------------------------------------*/
/*            Done read the data; verify we had no errors             */
/*--------------------------------------------------------------------*/

      if (ferror( stream ))
      {
         printerr( fname );
         clearerr( stream );
         return FALSE;
      } /* if */

/*--------------------------------------------------------------------*/
/*              Build entries for one permissions entry               */
/*--------------------------------------------------------------------*/

      printmsg(10,"Buffer is \"%s\"", buffer );
      if ((*next != '\0') && !InitEntry( buffer , fname))
      {
         fclose( stream );
         return FALSE;
      }

   } /* while ( !feof( stream ) ) */

/*--------------------------------------------------------------------*/
/*                    Initialize local host entry                     */
/*--------------------------------------------------------------------*/

   hostp = checkname( E_nodename );
   if ( hostp == NULL )
      panic();
   hostp->hsecure = malloc( sizeof *hostp->hsecure );
   checkref( hostp->hsecure );
   memset( hostp->hsecure , '\0', sizeof *hostp->hsecure);
                              /* Clear pointers                      */
   hostp->hsecure->local = TRUE;

/*--------------------------------------------------------------------*/
/*                          Return to caller                          */
/*--------------------------------------------------------------------*/

   fclose( stream );
   return TRUE;

} /* LoadSecurity */

/*--------------------------------------------------------------------*/
/*    I n i t i a l i z e E n t r y                                   */
/*                                                                    */
/*    Initialize a single permissions file entry                      */
/*--------------------------------------------------------------------*/

static boolean InitEntry( char *buf, const char *fname)
{

/*--------------------------------------------------------------------*/
/*                      Configuration variables                       */
/*--------------------------------------------------------------------*/

  static char *myname, *validate, *commands;

  static char *callback, *xpubdir, *machine, *noread, *nowrite;
  static char *request, *read, *sendfiles,  *write, *logname;

  static CONFIGTABLE securetable[] = {
     { "callback",      &callback,     B_TOKEN  | B_UUXQT } ,
     { "commands",      &commands,     B_CLIST  | B_UUXQT } ,
     { "logname",       &logname,      B_TOKEN  | B_UUXQT } ,
     { "machine",       &machine,      B_TOKEN  | B_UUXQT | B_MALLOC } ,
     { "myname",        &myname,       B_TOKEN  | B_UUXQT } ,
     { "pubdir",        &xpubdir,      B_PATH   | B_UUXQT } ,
     { "noread",        &noread,       B_TOKEN  | B_UUXQT | B_MALLOC } ,
     { "nowrite",       &nowrite,      B_TOKEN  | B_UUXQT | B_MALLOC } ,
     { "read",          &read,         B_TOKEN  | B_UUXQT | B_MALLOC} ,
     { "request",       &request,      B_TOKEN  | B_UUXQT } ,
     { "sendfiles",     &sendfiles,    B_TOKEN  | B_UUXQT } ,
     { "validate",      &validate,     B_CLIST  | B_UUXQT } ,
     { "write",         &write,        B_TOKEN  | B_UUXQT | B_MALLOC } ,
     { nil(char) }
}; /* securetable */

   struct HostSecurity *anchor = malloc( sizeof *anchor );

/*--------------------------------------------------------------------*/
/*                  Default list of allowed commands                  */
/*--------------------------------------------------------------------*/

   static char *command_list[] = { "rmail", "rnews" , NULL } ;

/*--------------------------------------------------------------------*/
/*                          Other variables                           */
/*--------------------------------------------------------------------*/

   boolean success = TRUE;
   CONFIGTABLE *tptr;
   char *token = buf;
   char *parameter;
   struct UserTable *userp;
   struct HostTable *hostp;
   size_t max_elements = 16;

/*--------------------------------------------------------------------*/
/*                 Initialize the security structure                  */
/*--------------------------------------------------------------------*/

   checkref( anchor );
   memset( anchor , '\0', sizeof *anchor); /* Clear pointers         */

/*--------------------------------------------------------------------*/
/*                        Initialize the table                        */
/*--------------------------------------------------------------------*/

   for (tptr = securetable; tptr->sym != nil(char); tptr++)
      if (tptr->bits & (B_TOKEN | B_STRING | B_LIST| B_CLIST))
         *(tptr->loc) = nil(char);

/*--------------------------------------------------------------------*/
/*                 Parse the information in the table                 */
/*--------------------------------------------------------------------*/

   while ( (parameter = strtok( token, WHITESPACE )) != NULL)
   {
      token = strtok( NULL, ""); /* Save for next pass               */
#ifdef _DEBUG
      printmsg(8,"InitEntry: Parameter is \"%s\"", parameter);
      if ( token != NULL )
         printmsg(10,"InitEntry: Buffer remaining is \"%s\"", token);
#endif
      if (!processconfig(parameter, SYSTEM_CONFIG,B_UUXQT,securetable,NULL))
      {
         printmsg(0,
          "Unknown keyword \"%s\" in %s ignored",parameter, fname);
         success = FALSE;
      } /* if */
   } /* while ( (parameter = strtok( token, WHITESPACE )) != NULL) */

   anchor->commands = (char **) commands;
   anchor->validate = (char **) validate;

/*--------------------------------------------------------------------*/
/*    Now we have the data procesed by keyword, break it down more    */
/*--------------------------------------------------------------------*/

   if ((logname == NULL) && (machine == NULL))
   {
      printmsg(0,"InitEntry: No machine or logname given in %s",
                  fname );
      success = FALSE;
   } /* if ((logname == NULL) && (machine == NULL)) */

/*--------------------------------------------------------------------*/
/*                        Handle a login name                         */
/*--------------------------------------------------------------------*/

   if (logname != NULL)
   {
      printmsg(10,"InitEntry: Processing logname=%s",logname );
      userp = checkuser( logname );
      if ( userp == BADUSER )
      {
         printmsg(0,"InitEntry: Invalid user id in %s, LOGNAME=%s",
                     fname, logname );
         success = FALSE;
      } /* if ( userp == BADUSER ) */
      else if (userp->hsecure == NULL)
         userp->hsecure = anchor;
      else {
         printmsg(0,"InitEntry: Duplicate user id in %s, LOGNAME=%s",
                     fname, logname );
         success = FALSE;
      } /* else */
   } /* if (logname != NULL) */

/*--------------------------------------------------------------------*/
/*                        Handle machine names                        */
/*--------------------------------------------------------------------*/

   token = machine;
   while( token != NULL )
   {
      char *host = strtok( token, ":");
      printmsg(10,"InitEntry: Processing machine=%s", host );

      token = strtok( NULL, "");
      if ( equal( host , ANY_HOST ) )
      {
         if ( default_security == NULL )
            default_security = anchor;
         else {
            printmsg(0,"InitEntry: "
                       "Multiple MACHINE entries in %s which specify OTHER",
                       fname);
            success = FALSE;
         } /* else */
      } /* if ( equal( host , ANY_HOST ) ) */
      else {
         hostp = checkreal( host );
         if ( hostp == BADUSER )
         {
            printmsg(0,"InitEntry: Invalid host id in %s, MACHINE=%s",
                        fname, host );
            success = FALSE;
         } /* if ( hostp == BADUSER ) */
         else if (hostp->hsecure == NULL)
            hostp->hsecure = anchor;
         else {
            printmsg(0,"InitEntry: Duplicate host id in %s, MACHINE=%s",
                        fname, token );
            success = FALSE;
         } /* else */
      } /* else */
   } /* while( token != NULL ) */

   if ( machine != NULL )
      free( machine );

/*--------------------------------------------------------------------*/
/*                       Handle validated names                       */
/*--------------------------------------------------------------------*/

   if ( anchor->validate != NULL )
   {
      char **plist = anchor->validate;

      while ( *plist != NULL )
      {
         hostp = checkreal( *plist );

         if ( hostp == BADUSER )
         {
            printmsg(0,"InitEntry: Invalid host id in %s, VALIDATE=%s",
                        fname, *plist);
            success = FALSE;
         } /* if ( hostp == BADUSER ) */
         else
            hostp->anylogin = FALSE;   /* Flag we must use specific
                                          login                      */

         plist++;             /* Step to next hostname in list       */

      } /* while ( *plist != NULL ) */

   } /* if ( anchor->validate != NULL ) */

/*--------------------------------------------------------------------*/
/*                          Handle CALLBACK                           */
/*--------------------------------------------------------------------*/

   if ( callback != NULL )
   {
      if (equal(strlwr(callback),"no"))
         anchor->callback = FALSE;
      else if (equal(callback,"yes"))
         anchor->callback = TRUE;
      else {
         printmsg(0,"InitEntry: Invalid value in %s, CALLBACK=%s",
                     fname, callback );
         success = FALSE;
      } /* else */
   } /* if ( callback != NULL ) */

/*--------------------------------------------------------------------*/
/*                          Handle REQUEST                            */
/*--------------------------------------------------------------------*/

   if ( request != NULL )
   {
      if (equal(strlwr(request),"no"))
         anchor->request = FALSE;
      else if (equal(request,"yes"))
         anchor->request = TRUE;
      else {
         printmsg(0,"InitEntry: Invalid value in %s, REQUEST=%s",
                     fname, request );
         success = FALSE;
      } /* else */

   } /* if ( request != NULL ) */

/*--------------------------------------------------------------------*/
/*                          Handle SENDFILES                          */
/*--------------------------------------------------------------------*/

   if ( sendfiles != NULL)
   {
      if (equal(strlwr(sendfiles),"call"))
         anchor->sendfiles = FALSE;
      else if (equal(sendfiles,"yes"))
         anchor->sendfiles = TRUE;
      else {
         printmsg(0,"InitEntry: Invalid value in %s, SENDFILES=%s",
                     fname, sendfiles );
         success = FALSE;
      } /* else */
   } /* if */

/*--------------------------------------------------------------------*/
/*                          handle commands                           */
/*--------------------------------------------------------------------*/

   if ( anchor->commands == NULL )
      anchor->commands = command_list;

/*--------------------------------------------------------------------*/
/*                 Handle local system name aliasing                  */
/*--------------------------------------------------------------------*/

   if (myname == NULL)
      anchor->myname = E_nodename;
   else
      anchor->myname = myname;

/*--------------------------------------------------------------------*/
/*                      Directory processing                          */
/*--------------------------------------------------------------------*/

   anchor->dirlist = malloc( sizeof anchor->dirlist[0] * max_elements );
   checkref( anchor->dirlist );

   max_elements = InitDir( read,    ALLOW_READ,  TRUE,  anchor,
            max_elements );
   free( read );
   max_elements = InitDir( noread,  ALLOW_READ,  FALSE, anchor,
            max_elements );
   free( noread );
   max_elements = InitDir( write,   ALLOW_WRITE, TRUE,  anchor,
            max_elements );
   free( write );
   max_elements = InitDir( nowrite, ALLOW_WRITE, FALSE, anchor,
                           max_elements );
   free( nowrite );

/*--------------------------------------------------------------------*/
/*                 Provide a default public directory                 */
/*--------------------------------------------------------------------*/

   if (xpubdir == NULL)
       anchor->pubdir = E_pubdir;
   else
       anchor->pubdir = xpubdir;

/*--------------------------------------------------------------------*/
/*    If no explicit directories given, give them access to pubdir    */
/*--------------------------------------------------------------------*/

   if ( anchor->dirsize == 0)
   {
      max_elements = InitDir( anchor->pubdir, ALLOW_READ, TRUE,
                              anchor, max_elements );
      max_elements = InitDir( anchor->pubdir, ALLOW_WRITE, TRUE,
                              anchor, max_elements );
   }

   if ( max_elements == 0 )
      success = FALSE;
   else {
      size_t subscript;
      anchor->dirlist = realloc( anchor->dirlist,
                                 anchor->dirsize * sizeof anchor->dirlist[0]);
      checkref( anchor->dirlist );
      qsort(anchor->dirlist, anchor->dirsize, sizeof(anchor->dirlist[0]),
               dircmp);
      if ( debuglevel > 4 )
      for ( subscript = 0; subscript < anchor->dirsize; subscript++ )
         printmsg(4, "InitEntry: dirlist[%d] %s\t%s\t%s",
                  subscript,
                  anchor->dirlist[subscript].grant ? "grant" : "deny" ,
                  anchor->dirlist[subscript].priv == ALLOW_WRITE ?
                           "WRITE" : "READ" ,
                  anchor->dirlist[subscript].path );
   } /* else */

/*--------------------------------------------------------------------*/
/*                          Return to caller                          */
/*--------------------------------------------------------------------*/

   return success;

} /* InitEntry */

/*--------------------------------------------------------------------*/
/*    I n i t D i r                                                   */
/*                                                                    */
/*    Initialize security table directory entries                     */
/*--------------------------------------------------------------------*/

static size_t InitDir( char *directories,
         const REMOTE_ACCESS access,
         const boolean grant,
         struct HostSecurity *anchor,
         size_t max_elements )
{
   char *field = directories;
   char *token = directories;
   struct  stat    statbuf;
   size_t subscript;

/*--------------------------------------------------------------------*/
/*    Don't process data if no input or we previously had an error    */
/*--------------------------------------------------------------------*/

   if ( (directories == NULL ) || ( max_elements == 0) )
      return max_elements;

/*--------------------------------------------------------------------*/
/*              Begin loop to process names in the path               */
/*--------------------------------------------------------------------*/

   while ( (token = NextField( field )) != NULL)
   {
      char path[FILENAME_MAX];
      if ( anchor->dirsize == max_elements )
      {
         max_elements = max_elements * 2;
         anchor->dirlist = realloc( anchor->dirlist,
                sizeof anchor->dirlist[0] * max_elements );
         checkref( anchor->dirlist );
      }

/*--------------------------------------------------------------------*/
/*                      Normalize directory name                      */
/*--------------------------------------------------------------------*/

      strcpy( path, token);
      if (isalpha(path[0]) && (path[1] != ':') && (strlen(path) == 2))
         ;                 /* Yup, do nothing for root drive names  */
      else if ( expand_path( path, ".", E_pubdir , NULL) == NULL )
      {
         printmsg(0, "Unable to expand path \"%s\"",path );
         return 0;
      } /* else */

      field = newstr( normalize( path ));

/*--------------------------------------------------------------------*/
/*               Verify it really is a valid directory                */
/*--------------------------------------------------------------------*/

      if ( strlen( field ) > 2 ) /* More than just drive/colon? (x:) */
      {                       /* Yes --> Go check disk for path      */
         if (stat(field , &statbuf) != 0)
         {
            printerr(field);
            return 0;            /* Path is invalid, give up         */
         }
         else if ((statbuf.st_mode & S_IFDIR) == 0)
         {
            printmsg(0,"InitDir: \"%s\" is a file, not a directory",field);
            return 0;            /* Path is invalid, give up         */
         }
      } /* if ( strlen( field ) > 2 ) */

/*--------------------------------------------------------------------*/
/*           Verify this directory not already in the list            */
/*--------------------------------------------------------------------*/

      for (subscript = 0; subscript < anchor->dirsize ; subscript++)
      {
         if ( (access == anchor->dirlist[subscript].priv) &&
              equali( field, anchor->dirlist[subscript].path))
         {
            printmsg(0,"InitDir: Duplicate directory %s/", field);
            return 0;
         } /* if */
      } /* for */

/*--------------------------------------------------------------------*/
/*            No conflict, add this directory to the list             */
/*--------------------------------------------------------------------*/

      printmsg(10,"InitDir: Adding \"%s\" as \"%s\"", token , field);
      anchor->dirlist[subscript].path  = field;
      anchor->dirlist[subscript].priv  = access;
      anchor->dirlist[subscript].grant = grant;
      anchor->dirsize++;

      field = NULL;           /* Look at next field next pass        */

   } /* while ( (field = NextField( field )) != NULL) */

/*--------------------------------------------------------------------*/
/*                          Return to caller                          */
/*--------------------------------------------------------------------*/

   return max_elements;
} /* InitDir */

/*--------------------------------------------------------------------*/
/*    d i r c m p                                                     */
/*                                                                    */
/*                                                                    */
/*    Compares two directory structures for sorting                   */
/*--------------------------------------------------------------------*/

int dircmp( const void *a , const void *b )
{
   struct DIRLIST *x = (struct DIRLIST*) a;
   struct DIRLIST *y = (struct DIRLIST*) b;

   int result = strcmp(x->path, y->path);

   if (result == 0 && (x->priv != y->priv))
      result = ( x->priv < y->priv ) ? -1 : 1;

   return result;
}  /*dircmp*/

/*--------------------------------------------------------------------*/
/*    V a l i d a t e H o s t                                         */
/*                                                                    */
/*    Determine that a host is allowed for a specific login           */
/*--------------------------------------------------------------------*/

boolean ValidateHost( const char *host )
{
   char **target;

/*--------------------------------------------------------------------*/
/*      If this host has no security profile, reject the access       */
/*--------------------------------------------------------------------*/

   if ( securep == NULL )
      return FALSE;

/*--------------------------------------------------------------------*/
/*    If we allow any host on this user id, use it if the calling     */
/*    host is not supported any other profile                         */
/*--------------------------------------------------------------------*/

   target = securep->validate;
   if ( target == NULL )      /* No validate list for this user?     */
   {                          /* Correct --> Use if none for host    */
      struct HostTable *hostp = checkreal( host );
      if ( hostp == BADHOST ) /* Host exist?                         */
         panic();             /* No --> Internal error, abort        */

      return hostp->anylogin; /* Allow action if generic access
                                 allowed for host                    */
   }  /* if ( target == NULL ) */

/*--------------------------------------------------------------------*/
/*          Determine if this host is allowed for this login          */
/*--------------------------------------------------------------------*/

   while (*target != NULL)
   {
      if ( equal(*target++, host ))
         return TRUE;
   } /* (*target != NULL) */

/*--------------------------------------------------------------------*/
/*                 We didn't find the host; reject it                 */
/*--------------------------------------------------------------------*/

   return FALSE;

} /* ValidateHost */

/*--------------------------------------------------------------------*/
/*    V a l i d a t e F i l e                                         */
/*                                                                    */
/*    Allow or reject access to a file by name                        */
/*--------------------------------------------------------------------*/

boolean ValidateFile( const char *input,  /* Full path name          */
                      const REMOTE_ACCESS needed )
{
   char path[FILENAME_MAX];
   char *column;

/*--------------------------------------------------------------------*/
/*                  Validate the length of the name                   */
/*--------------------------------------------------------------------*/

   printmsg(5,"ValidateFile: Checking %s access for file \"%s\"",
            (needed == ALLOW_WRITE) ? "WRITE" : "READ" , input);

   if ( strlen( input ) >= sizeof path)   /* Reject all invalid names*/
   {
      printmsg(0,"ValidateFile: Access rejected, name too long: %s",
                 input);
      return FALSE;
   }

/*--------------------------------------------------------------------*/
/*     Validate format of name; we don't allow parent directories     */
/*--------------------------------------------------------------------*/

   if ( strstr( input, "..") )            /* Games with parent dir?  */
   {
      printmsg(0,"ValidateFile: Access rejected, name not normalized: %s",
                 input);
      return FALSE;
   }

/*--------------------------------------------------------------------*/
/*                Validate the security table is okay                 */
/*--------------------------------------------------------------------*/

   if ( securep == NULL )
      panic();

/*--------------------------------------------------------------------*/
/*                        Handle local system                         */
/*--------------------------------------------------------------------*/

   if ( securep->local )      /* Local system?                       */
      return TRUE;            /* Yes --> Bless the request           */

/*--------------------------------------------------------------------*/
/*       Determine if the user is allowed to request files            */
/*--------------------------------------------------------------------*/

   if ((needed == ALLOW_READ) && !securep->request)
   {
      printmsg(0,"ValidateFile: access rejected, "
                 "REQUEST not enabled in permissions file");
      return FALSE;
   }

/*--------------------------------------------------------------------*/
/*                           Copy path name                           */
/*--------------------------------------------------------------------*/

   if ( input[1] == ':' )
      strcpy( path, input );
   else
      strcat( strcpy( path , drive ), input );
   strlwr( path );

/*--------------------------------------------------------------------*/
/*              Locate the best file match for the path               */
/*--------------------------------------------------------------------*/

   while( (column = strrchr( path, '/')) != NULL )
   {
      int lower = 0;
      int upper = securep->dirsize - 1;

      *column = '\0';
      printmsg(10,"ValidateFile: Searching for %s", path);

      while( lower <= upper )
      {
         int midpoint = (lower + upper) / 2;
         int hit = strcmp(path, securep->dirlist[midpoint].path);

         printmsg(10,"ValidateFile: Comparing %s and %s",
                        path, securep->dirlist[midpoint].path);

         if ( hit == 0 )
            hit = (int) needed - (int) securep->dirlist[midpoint].priv;

         if (hit > 0)
            lower = midpoint + 1;
         else if (hit < 0)
            upper = midpoint - 1;
         else {
            printmsg( securep->dirlist[midpoint].grant ? 5 : 0 ,
                     "ValidateFile: Found path \"%s\", access %s to \"%s\"",
                     securep->dirlist[midpoint].path,
                     securep->dirlist[midpoint].grant ?
                                    "granted" : "denied", input);
            return securep->dirlist[midpoint].grant;
         }
      } /* while( lower <= upper ) */
   } /* while( (column = strrchr( path, '/')) != NULL ) */

/*--------------------------------------------------------------------*/
/*          We didn't find the file; reject all access to it          */
/*--------------------------------------------------------------------*/

   printmsg(0,"ValidateFile: No access definition found for \
\"%s\", access denied",
            input);
   return FALSE;

} /* ValidateFile */


/*--------------------------------------------------------------------*/
/*    G e t S e c u r i t y                                           */
/*                                                                    */
/*    Return security structure for to use when calling out to        */
/*    another system                                                  */
/*--------------------------------------------------------------------*/

struct HostSecurity *GetSecurity( struct HostTable *hostp)
{
   if ((hostp->hsecure == NULL) && (default_security != NULL ))
   {
      printmsg(2,"GetSecurity: Using security for MACHINE=OTHER for \
system \"%s\"", hostp->hostname );
      hostp->hsecure = default_security;
   } /* if  */

   return hostp->hsecure;

} /* GetSecurity */
