Logo Search packages:      
Sourcecode: samhain version File versions  Download package

trustfile.c

/* debug problems        */
/* #define TRUST_DEBUG   */

/* switch off full check */
/* #define TEST_ONLY     */

/* standalone            */
/* #define TRUST_MAIN    */
/* $(CC) -DTRUST_MAIN -DSL_ALWAYS_TRUSTED=...  */

/* LINTLIBRARY */
/*
 * This is the file with all the library routines in it
 *
 * Author information:
 * Matt Bishop
 * Department of Computer Science
 * University of California at Davis
 * Davis, CA  95616-8562
 * phone (916) 752-8060
 * email bishop@cs.ucdavis.edu
 *
 * This code is placed in the public domain.  I do ask that
 * you keep my name associated with it, that you not represent
 * it as written by you, and that you preserve these comments.
 * This software is provided "as is" and without any guarantees
 * of any sort.
 *
 * Compilation notes:
 * * this does NOT use malloc(3), but fixed storage.  this means we
 *   do lots of bounds checking, but it still is faster, and smaller,
 *   than forcing inclusion of malloc.  All buffers etc. are of size
 *   MAXFILENAME (defined in trustfile.h); to get more room, recompile
 *   with this set larger.
 * * if you support the following directory semantics, define STICKY;
 *   otherwise, undefine it
 *    "if a directory is both world-writeable AND has the sticky bit
 *     set, then ONLY the owner of an existing file may delete it"
 *   On some systems (eg, IRIX), you can delete the file under these
 *   conditions if the file is world writeable.  Foor our purposes,
 *   this is irrelevant since if the file is world-writeable it is
 *   untrustworthy; either it can be replaced with another file (the
 *   IRIX version) or it can be altered (all versions).
 *   if this is true and STICKY is not set, the sticky bit is ignored
 *   and the directory will be flagged as untrustworthy, even when only
 *   a trusted user could delete the file
 * * this uses a library call to get the name of the current working
 *   directory.  Define the following to get the various versions:
 *   GETCWD for Solaris 2.x, SunOS 4.1.x, IRIX 5.x
 *                char *getcwd(char *buf, int bufsz);
 *          where buf is a buffer for the path name, and bufsz is
 *          the size of the buffer; if the size if too small, you
 *          get an error return (NULL)
 *   GETWD  for Ultrix 4.4
 *                char *getwd(char *buf)
 *          where buf is a buffer for the path name, and it is
 *          assumed to be at lease as big as MAXPATHLEN.
 *          *** IMPORTANT NOTE ***
 *          Ultrix supports getcwd as well, but it uses popen to
 *          run the command "pwd" (according to the manual).  This
 *          means it's vulnerable to a number of attacks if used
 *          in a privileged program.  YOU DON'T WANT THIS.
 * * the debugging flag DEBUG prints out each step of the file name
 *   checking, as well as info on symbolic links (if S_IFLNK defined),
 *   file name canonicalization, and user, group, and permission for
 *   each file or directory; this is useful if you want to be sure
 *   you're checking the right file
 *
 * Version information:
 * 1.0            December 28, 1995 Matt Bishop
 *
 * 2.0          March    26, 2000       Rainer Wichmann -- adapted for slib.
 */

/* --- Why strcpy is safe here: ----                                  */

/* The input path is checked once, and then either shortened [in dirz()], 
 * or safely expanded (symlinks) with bound checking.
 * I.e., the path length can never exceed (MAXFILENAME-1), while the path
 * is always copied between buffers of length MAXFILENAME.
 */

#ifndef  TRUST_MAIN
#include "config_xor.h"
#include "sh_calls.h"
#else
#define UID_CAST long
#endif

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <grp.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>


#ifndef TRUST_MAIN
#include "slib.h"
#define SH_NEED_PWD_GRP 1
#include "sh_static.h"

#else

#define sh_getgrgid   getgrgid
#define sh_getpwent   getpwent
#define sh_getpwnam   getpwnam
#define sh_getpwuid   getpwuid
#define sh_endpwent   endpwent

#define TRUST_DEBUG
#define SL_FALSE 0
#define SL_TRUE  1
#define SL_ENTER(string)
#define SL_IRETURN(a, b)  return a
#define retry_lstat(a,b,c,d) lstat(c,d)
#define _(string)  string 
#define N_(string) string
#define MAXFILENAME     4096
static int sl_errno = 0;
#define SL_ENONE         0
#define SL_ENULL     -1024     /* Invalid use of NULL pointer.         */
#define SL_ERANGE    -1025     /* Argument out of range.               */
#define SL_ETRUNC    -1026     /* Result truncated.                    */
#define SL_EINTERNAL -1028     /* Internal error.                      */
#define SL_EBADFILE  -1030     /* File access error. Check errno.      */
#define SL_EBADNAME  -1040     /* Invalid name.                        */
#define SL_ESTAT     -1041     /* stat of file failed. Check errno.    */
#define SL_EBADUID   -1050    /* Owner not trustworthy.              */
#define SL_EBADGID   -1051    /* Group writeable and not trustworthy.*/
#define SL_EBADOTH   -1052    /* World writeable.                    */

#endif


#if defined(__linux__) || defined(__FreeBSD__)
#define STICKY
#endif

#undef  FIL__
#define FIL__  _("trustfile.c")

/*
 * the get current working directory function
 * every version of UNIX seems to have its own
 * idea of how to do this, so we group them by
 * arguments ...
 * all must return a pointer to the right name
 */


#ifndef TRUST_MAIN

#if defined(HAVE_GETCWD) && !defined(HAVE_BROKEN_GETCWD)
#define CURDIR(buf,nbuf)      getcwd((buf), (nbuf))
#elif defined(HAVE_GETWD)
#define CURDIR(buf,nbuf)      getwd((buf))
#endif

#else

#define CURDIR(buf,nbuf)      getcwd((buf), (nbuf))

#endif



/*
 * this checks to see if there are symbolic links
 * assumes the link bit in the protection mask is called S_IFLNK
 * (seems to be true on all UNIXes with them)
 */
#ifndef S_IFLNK
#define     lstat stat
#endif


/*
 * these are useful global variables
 *
 * first set: who you gonna trust, by default?
 *    if the user does not specify a trusted or untrusted set of users,
 *    all users are considered untrusted EXCEPT:
 *    UID 0 -- root     as root can do anything on most UNIX systems, this
 *                seems reasonable
 *    tf_euid -- programmer-selectable UID
 *                if the caller specifies a specific UID by putting
 *                it in this variable, it will be trusted; this is
 *                typically used to trust the effective UID of the
 *                process (note: NOT the real UID, which will cause all
 *                sorts of problems!)  By default, this is set to -1,
 *                so if it's not set, root is the only trusted user
 */

/* modified Tue Feb 22 10:36:44 NFT 2000 Rainer Wichmann                */


#ifndef SL_ALWAYS_TRUSTED
#define SL_ALWAYS_TRUSTED  0
#endif
static uid_t test_rootonly[] = { SL_ALWAYS_TRUSTED };

#define tf_uid_neg ((uid_t)-1)

uid_t rootonly[] = { SL_ALWAYS_TRUSTED, 
                tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg, 
                tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg, 
                tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg, 
                tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg };

uid_t tf_euid = tf_uid_neg;
int EUIDSLOT = sizeof(test_rootonly)/sizeof(uid_t);
int ORIG_EUIDSLOT = sizeof(test_rootonly)/sizeof(uid_t);

char  tf_path[MAXFILENAME];         /* error path for trust function */
uid_t tf_baduid;
gid_t tf_badgid;

static 
int dirz(char *path)
{
  register char *p = path;/* points to rest of path to clean up */
  register char *q;     /* temp pointer for skipping over stuff */

  static   char swp[MAXFILENAME];

  SL_ENTER(_("dirz"));
  /*
   * standard error checking
   */
  if (path == NULL)
    SL_IRETURN(SL_ENULL, _("dirz"));
  if (path[0] == '.')
    SL_IRETURN(SL_EINTERNAL, _("dirz"));
  
  
  /*
   * loop over the path name until everything is checked
   */
  while(*p)
    {
      /* skip 
       */
      if (*p != '/')
      {
        p++;
        continue;
      }

      /* "/./" or "/." 
       */
      if (p[1] == '.' && (p[2] == '/' || p[2] == '\0'))
      {
        /* yes -- delete "/." 
         */
        (void) strcpy(swp, &p[2]);                     /* known to fit  */
        (void) strcpy(p, swp);                         /* known to fit  */

        /* special case "/." as full path name 
         */
        if (p == path && *p == '\0')
          {
          *p++ = '/';
          *p = '\0';
        }
      }

      /* "//" 
       */
      else if (p[1] == '/')
      {
        /* yes -- skip 
         */
        for(q = &p[2]; *q == '/'; q++)
          ;
        (void) strcpy(swp, q);                         /* known to fit  */
        (void) strcpy(&p[1], swp);                     /* known to fit  */
      }

      /* "/../" or "/.." 
       */
      else if (p[1] == '.' && p[2] == '.' && (p[3] == '/' || p[3] == '\0'))
      {
        /* yes -- if it's root, delete .. only 
         */
        if (p == path)
          {
            (void) strcpy(swp, &p[3]);                 /* known to fit  */
            (void) strcpy(p, swp);                     /* known to fit  */
          }
        else
          {
            /* back up over previous component 
             */
            q = p - 1;
            while(q != path && *q != '/')
            q--;
            /* now wipe it out 
             */
            (void) strcpy(swp, &p[3]);                 /* known to fit  */
            (void) strcpy(q, swp);                     /* known to fit  */
            p = q;
          }
      }
      else
      p++;
    }
  SL_IRETURN(SL_ENONE, _("dirz"));
}
                  


static 
int getfname(char *fname, char *rbuf, int rsz)
{
#ifndef TRUST_MAIN
  register int status;
#endif

  SL_ENTER(_("getfname"));
  /*
   * do the initial checking
   * NULL pointer
   */
  if (fname == NULL || rbuf == NULL)
    SL_IRETURN(SL_ENULL, _("getfname"));
  if (rsz <= 0)
    SL_IRETURN(SL_ERANGE, _("getfname"));
  
  
  /* already a full path name */
  if (*fname == '/')
    rbuf[0] = '\0';
  else
    {
      if (CURDIR(rbuf, rsz)  == NULL)
      {
#ifdef TRUST_DEBUG
        fprintf(stderr, "trustfile: getcwd failed\n");
#endif 
        SL_IRETURN(SL_EBADNAME, _("getfname"));
      }
    }
  
  /*
   * append the file name and reduce
   */
  if (fname != NULL && *fname != '\0')
    {
#ifndef TRUST_MAIN
      status = sl_strlcat(rbuf, "/", rsz);
      if (status == SL_ENONE)
      status = sl_strlcat(rbuf, fname, rsz);
      if (status != SL_ENONE)
      SL_IRETURN(status, _("getfname"));
#else
      strncat(rbuf, "/",   rsz-strlen(rbuf));
      strncat(rbuf, fname, rsz-strlen(rbuf));
#endif
    }
  SL_IRETURN(dirz(rbuf), _("getfname"));
}

static 
int isin(uid_t n, uid_t *list)
{
  SL_ENTER(_("isin"));
  if (list == NULL)
    SL_IRETURN(SL_FALSE, _("isin"));

  while(*list != tf_uid_neg && *list != n)
    {
#ifdef TRUST_DEBUG
      fprintf (stderr, 
             "trustfile: owner_uid=%ld, trusted uid=%ld, no match\n", 
             (UID_CAST) n, (UID_CAST) *list);
#endif 
      list++;
    }

  if (*list == tf_uid_neg)
    {
#ifdef TRUST_DEBUG
      fprintf (stderr, 
             "trustfile: owner_uid=%ld, no match with any trusted user --> ERROR\n", 
             (UID_CAST) n);
#endif 
      SL_IRETURN(SL_FALSE, _("isin"));
    }

#ifdef TRUST_DEBUG
  fprintf (stderr, 
         "trustfile: owner_uid=%ld, trusted_uid=%ld, match found --> OK\n", 
         (UID_CAST)n, (UID_CAST)*list);
#endif 
  SL_IRETURN(SL_TRUE, _("isin"));
}

/* comment added by R. Wichmann
 *  RETURN TRUE if ANYONE in ulist is group member
 */
static 
int isingrp(gid_t grp, uid_t *ulist)
{
  register struct passwd *w;  /* info about group member */
  register uid_t *u;          /* points to current ulist member */
  register char **p;          /* points to current group member */
  register struct group *g;   /* pointer to group information */
  
  SL_ENTER(_("isingrp"));

  if ((g = sh_getgrgid(grp)) == NULL)
    {
      SL_IRETURN(SL_FALSE, _("isingrp") );
    }
  /*
  if(g->gr_mem == NULL || g->gr_mem[0] == NULL )
    SL_IRETURN(SL_FALSE, _("isingrp") );
  */

  /* this will return at the first match
   */
  for(p = g->gr_mem; *p != NULL; p++)
    {
      for(u = ulist; *u != tf_uid_neg; u++)
      {
        /* map user name to UID and compare */
#ifdef TRUST_MAIN
        if ((w = getpwnam(*p)) != NULL && *u == (uid_t)(w->pw_uid) )
          SL_IRETURN(SL_TRUE, _("isingrp"));
#else
        if ((w = sh_getpwnam(*p)) != NULL && *u == (uid_t)(w->pw_uid) )
          {
            SL_IRETURN(SL_TRUE, _("isingrp"));
          }
#endif
      }
    }
  /* added by R. Wichmann Fri Mar 30 08:16:14 CEST 2001: 
   * a user can have a GID but no entry in /etc/group
   */
  for(u = ulist; *u != tf_uid_neg; u++)
    {
#ifdef TRUST_MAIN
      if ((w = getpwuid(*u)) != NULL && grp == (gid_t)(w->pw_gid) )
      SL_IRETURN(SL_TRUE, _("isingrp"));
#else
      if ((w = sh_getpwuid(*u)) != NULL && grp == (gid_t)(w->pw_gid) )
      {
        SL_IRETURN(SL_TRUE, _("isingrp"));
      }
#endif
    }

  SL_IRETURN(SL_FALSE, _("isingrp"));
}

/* added by R. Wichmann Fri Mar 30 08:16:14 CEST 2001
 *  RETURN TRUE only if ALL group members are trusted
 */
static 
int onlytrustedingrp(gid_t grp, uid_t *ulist)
{
  register struct passwd *w;  /* info about group member */
  register uid_t *u;          /* points to current ulist member */
  register char **p;          /* points to current group member */
  register struct group *g;   /* pointer to group information */
  register int flag = -1;       /* group member found */

  SL_ENTER(_("onlytrustedingrp"));

#ifdef TRUST_DEBUG
  fprintf(stderr, "trustfile: group writeable, group_gid: %ld\n", 
        (UID_CAST)grp); 
#endif

  if ((g = sh_getgrgid(grp)) == NULL)
    {
#ifdef TRUST_DEBUG
      fprintf(stderr, 
            "trustfile: group_gid: %ld, no such group --> ERROR\n", 
            (UID_CAST)grp); 
#endif
      SL_IRETURN(SL_FALSE, _("onlytrustedingrp") );
    }

  /* empty group -> no problem
   
  if(g->gr_mem == NULL || g->gr_mem[0] == NULL )
    SL_IRETURN(SL_TRUE, _("onlytrustedingrp") );
  */

  /* check for untrusted members of the group
   */
  for(p = g->gr_mem; *p != NULL; p++)
    {
      flag = -1;
#ifdef TRUST_DEBUG
      fprintf(stderr, "trustfile: group_member: %s\n", *p); 
#endif
      /* map user name to UID and compare 
       */
      w = sh_getpwnam(*p);
#ifndef TRUST_MAIN
      if (!w)
      w = sh_getpwnam(*p);
#endif
      if (w == NULL)    /* not a valid user, ignore    */
      {
        flag = 0; 
      }
      else              /* check list of trusted users */
      {
#ifdef TRUST_DEBUG
        fprintf (stderr, 
               "trustfile: uid=%ld, checking whether it is trusted\n",
               (UID_CAST)(w->pw_uid));
#endif 
        for(u = ulist; *u != tf_uid_neg; u++)
          {
            if (*u == (w->pw_uid) )
            {
#ifdef TRUST_DEBUG
              fprintf (stderr, 
                     "trustfile: uid=%ld, trusted_uid=%ld, match found --> OK\n", 
                     (UID_CAST)(w->pw_uid), (UID_CAST)*u);
#endif 
              flag = 0;
              break;
            }
            else
            {
#ifdef TRUST_DEBUG
              fprintf (stderr, 
                     "trustfile: uid=%ld, trusted_uid=%ld, no match\n", 
                     (UID_CAST)(w->pw_uid), (UID_CAST)*u);
#endif 
              ;
            }
          }
      }
      /* not found 
       */
      if (flag == -1)
      {
#ifdef TRUST_DEBUG
        fprintf (stderr, 
               "trustfile: user=%s (gid %ld), not a trusted user --> ERROR\n", *p, (UID_CAST)grp);
#endif 
        tf_baduid = w->pw_uid;
        SL_IRETURN(SL_FALSE, _("onlytrustedingrp"));
      }
    }

#ifndef TEST_ONLY 
#ifdef HAVE_GETPWENT
  /* now check ALL users for their GID !!!
   */
  while (NULL != (w = sh_getpwent())) 
    {
      if (grp == (gid_t)(w->pw_gid))
      {
#ifdef TRUST_DEBUG
        fprintf(stderr, "trustfile: checking group member %s, uid %ld\n", 
              w->pw_name, (UID_CAST)w->pw_uid); 
#endif
        /* is it a trusted user ?
         */
        flag = -1;
        for(u = ulist; *u != tf_uid_neg; u++)
          {
            if (*u == (uid_t)(w->pw_uid))
            {
#ifdef TRUST_DEBUG
              fprintf (stderr, 
                     "trustfile: uid=%ld, trusted_uid=%ld, match found --> OK\n", 
                     (UID_CAST)(w->pw_uid), *u);
#endif 
              flag = 0;
              break;
            }
            else
            {
#ifdef TRUST_DEBUG
              fprintf (stderr, 
                     "trustfile: uid=%ld, trusted_uid=%ld, no match\n", 
                     (UID_CAST)(w->pw_uid), (UID_CAST)*u);
#endif 
              ;
            }
          }
        /* not found */
        if (flag == -1)
          {
#ifdef TRUST_DEBUG
            fprintf(stderr,"trustfile: group member %s not found in trusted users --> ERROR\n", w->pw_name); 
#endif
            tf_baduid = w->pw_uid;
            SL_IRETURN(SL_FALSE, _("onlytrustedingrp"));
          }
      }
    }

#ifdef HAVE_ENDPWENT
  sh_endpwent();
#endif
  /* TEST_ONLY */
#endif

  /* #ifdef HAVE_GETPWENT */
#endif

#ifdef TRUST_DEBUG
  fprintf(stderr,
        "trustfile: group %ld:  all members are trusted users --> OK\n", 
        (UID_CAST)grp);
#endif
  /* all found
   */
  SL_IRETURN(SL_TRUE, _("onlytrustedingrp"));
}

int sl_trustfile(char *fname, uid_t *okusers, uid_t *badusers)
{
  char fexp[MAXFILENAME];     /* file name fully expanded        */
  register char *p = fexp;      /* used to hold name to be checked */
  struct stat stbuf;            /* used to check file permissions  */
  char c;               /* used to hold temp char          */
  
  SL_ENTER(_("sl_trustfile"));
  if (fname == NULL)
    SL_IRETURN(SL_EBADFILE, _("sl_trustfile"));

  /*
   * next expand to the full file name
   * getfname sets sl_errno as appropriate
   */
#ifdef TRUST_MAIN
  sl_errno = getfname(fname, fexp, MAXFILENAME);
  if (sl_errno != 0)
    return sl_errno;
#else
  if (SL_ISERROR(getfname(fname, fexp, MAXFILENAME)))
      SL_IRETURN(sl_errno, _("sl_trustfile"));
#endif

  if (okusers == NULL && badusers == NULL)
    {
      okusers = rootonly;
      rootonly[EUIDSLOT] = tf_euid;
    }

  /*
   * now loop through the path a component at a time
   * note we have to special-case root
   */
  while(*p)
    {
      /*
       * get next component
       */
      while(*p && *p != '/')
      p++;

      /* save where you are 
       */
      if (p == fexp)
      {
        /* keep the / if it's the root dir 
         */
        c    = p[1];
        p[1] = '\0';
      }
      else
      {
        /* clobber the / if it isn't the root dir 
         */
        c  = *p;
        *p = '\0';
      }

      /*
       * now get the information
       */
      if (retry_lstat(FIL__, __LINE__, fexp, &stbuf) < 0)
      {
        (void) strcpy(tf_path, fexp);                  /* known to fit  */
#ifdef TRUST_MAIN
        fprintf(stderr, "---------------------------------------------\n");
            fprintf(stderr, "trustfile: ESTAT: stat(%s) failed, maybe the file does not exist\n",
                  fexp);
        fprintf(stderr, "---------------------------------------------\n");
#endif
        SL_IRETURN(SL_ESTAT, _("sl_trustfile"));
      }

#ifdef S_IFLNK
      /* 
       * if it's a symbolic link, recurse
       */
      if ((stbuf.st_mode & S_IFLNK) == S_IFLNK)
      {
        /*
         * this is tricky
         * if the symlink is to an absolute path
         * name, just call trustfile on it; but
         * if it's a relative path name, it's 
         * interpreted WRT the current working
         * directory AND NOT THE FILE NAME!!!!!
         * so, we simply put /../ at the end of
         * the file name, then append the symlink
         * contents; trustfile will canonicalize
         * this, and the /../ we added "undoes"
         * the name of the symlink to put us in
         * the current working directory, at
         * which point the symlink contents (appended
         * to the CWD) are interpreted correctly.
         * got it?
         */
        char csym[MAXFILENAME];     /* contents of symlink file  */
        char full[MAXFILENAME];     /* "full" name of symlink    */
        register char *b, *t;         /* used to copy stuff around */
        register int lsym;            /* num chars in symlink ref  */
        register int i;       /* trustworthy or not?       */

        /*
         * get what the symbolic link points to
         *
         * The original code does not check the return code of readlink(),
         * and has an off-by-one error 
         * (MAXFILENAME instead of MAXFILENAME-1)
         * R.W. Tue May 29 22:05:16 CEST 2001
         */
        lsym = readlink(fexp, csym, MAXFILENAME-1);
        if (lsym >= 0) 
          csym[lsym] = '\0';
        else
          {
#ifdef TRUST_MAIN
            fprintf(stderr, "---------------------------------------------\n");
            fprintf(stderr, "trustfile: EBADNAME: readlink(%s) failed\n",
                  fexp);
            fprintf(stderr, "---------------------------------------------\n");
#endif
            SL_IRETURN(SL_EBADNAME, _("sl_trustfile"));
          }

        /*
         * relative or absolute referent?
         */
        if (csym[0] != '/')
          {
            /* initialize pointers 
             */
            b = full;

            /* copy in base path 
             */
            t = fexp;
            while(*t && b < &full[MAXFILENAME])
            *b++ = *t++;

            /* smack on the /../ 
             */
            t = "/../";
            while(*t && b < &full[MAXFILENAME])
            *b++ = *t++;

            /* append the symlink referent 
             */
            t = csym;
            while(*t && b < &full[MAXFILENAME])
            *b++ = *t++;

            /* see if we're too big 
             */
            if (*t || b == &full[MAXFILENAME])
            {
              /* yes -- error 
               */
              (void) strcpy(tf_path, fexp);          /* known to fit  */
#ifdef TRUST_MAIN
              fprintf(stderr, "---------------------------------------------\n");
              fprintf(stderr, 
                    "trustfile: ETRUNC: normalized path too long (%s)\n",
                    fexp);
              fprintf(stderr, "---------------------------------------------\n");
#endif
              SL_IRETURN(SL_ETRUNC, _("sl_trustfile"));
            }
            *b = '\0';
          }
        else
          {
            /* absolute -- just copy                */
            /* overflow can't occur as the arrays   */
            /* are the same size                */
            (void) strcpy(full, csym);                 /* known to fit  */
          }
        /*
         * now check out this file and its ancestors
         */
        if ((i = sl_trustfile(full, okusers, badusers)) != SL_ENONE)
          SL_IRETURN(i, _("sl_trustfile"));

        /*
         * okay, this part is valid ... let's check the rest
         * put the / back
         */
        if (p == fexp)
          {
            /* special case for root */
            p[1] = c;
            p++;
          }
        else
          {
            /* ordinary case for everything else */
            *p = c;
            if (*p)
            p++;
          }
        continue;
      }
#endif

                  
#ifdef TRUST_DEBUG
      fprintf(stderr, "\ntrustfile: checking path=%s\n", fexp); 
#endif 
      /*
       * if the owner is not trusted then -- as the owner can
       * change protection modes -- he/she can write to the
       * file regardless of permissions, so bomb
       */
      if (((okusers != NULL && SL_FALSE == isin((uid_t)stbuf.st_uid,okusers))||
         (badusers != NULL && SL_TRUE == isin((uid_t)stbuf.st_uid,badusers))))
      {
#ifdef TRUST_DEBUG
        fprintf(stderr, "---------------------------------------------\n");
        fprintf(stderr, "trustfile: EBADUID %s (owner not trusted)\n", 
              fexp); 
        fprintf(stderr, "The owner of this file/directory is not in samhains\n"); 
        fprintf(stderr, "list of trusted users.\n");
        fprintf(stderr, "Please run ./configure again with the option\n");
        fprintf(stderr, " ./configure [more options] --with-trusted=0,...,UID\n"); 
        fprintf(stderr, "where UID is the UID of the (yet) untrusted user.\n"); 
        fprintf(stderr, "---------------------------------------------\n");
#endif 
        (void) strcpy(tf_path, fexp);                  /* known to fit  */
        tf_baduid = (uid_t) stbuf.st_uid;
        SL_IRETURN(SL_EBADUID, _("sl_trustfile"));
      }

      /*
       * if a group member can write but the
       * member is not trusted, bomb; but if
       * sticky bit semantics are honored, it's
       * okay
       */
      /* Thu Mar 29 21:10:28 CEST 2001 Rainer Wichmann
       * replace !isingrp() with onlytrustedingrp(), as isingrp()
       * will return at the first trusted user, even if there are additional
       * (untrusted) users in the group
       */
      if (((stbuf.st_mode & S_IWGRP) == S_IWGRP) &&
        ((okusers != NULL && !onlytrustedingrp((gid_t)stbuf.st_gid,okusers))||
         (badusers != NULL && isingrp((gid_t)stbuf.st_gid, badusers)))
#ifdef STICKY
        && ((stbuf.st_mode&S_IFDIR) != S_IFDIR ||
            (stbuf.st_mode&S_ISVTX) != S_ISVTX)
#endif
        )
      {
#ifdef TRUST_DEBUG
        fprintf(stderr, "---------------------------------------------\n");
        fprintf(stderr, 
              "trustfile: EBADGID %ld %s (group member not trusted)\n", 
              (UID_CAST)stbuf.st_gid, fexp);
        fprintf(stderr, "This file/directory is group writeable, and one of the group members\n");
        fprintf(stderr, "is not in samhains list of trusted users.\n"); 
        fprintf(stderr, "Please run ./configure again with the option\n");
        fprintf(stderr, " ./configure [more options] --with-trusted=0,...,UID\n"); 
        fprintf(stderr, "where UID is the UID of the (yet) untrusted user.\n"); 
        fprintf(stderr, "---------------------------------------------\n");
#endif 
        (void) strcpy(tf_path, fexp);                  /* known to fit  */
        tf_badgid = (gid_t) stbuf.st_gid;
        SL_IRETURN(SL_EBADGID, _("sl_trustfile"));
      }
      /*
       * if other can write, bomb; but if the sticky
       * bit semantics are honored, it's okay
       */
      if (((stbuf.st_mode & S_IWOTH) == S_IWOTH)
#ifdef STICKY
        && ((stbuf.st_mode&S_IFDIR) != S_IFDIR ||
            (stbuf.st_mode&S_ISVTX) != S_ISVTX)
#endif
        )
      {
#ifdef TRUST_DEBUG
        fprintf(stderr, "---------------------------------------------\n");
        fprintf(stderr, "trustfile: EBADOTH (world writeable): %s\n", 
              fexp);
        fprintf(stderr, "This file/directory is world writeable.\n");
        fprintf(stderr, "---------------------------------------------\n");
#endif 
        (void) strcpy(tf_path, fexp);                  /* known to fit  */
        SL_IRETURN(SL_EBADOTH, _("sl_trustfile"));
      }
      /*
       * put the / back
       */
      if (p == fexp)
      {
        /* special case for root */
        p[1] = c;
        p++;
      }
      else
      {
        /* ordinary case for everything else */
        *p = c;
        if (*p)
          p++;
      }
    }
  /*
   * yes, it can be trusted
   */
  (void) strcpy(tf_path, fexp);                      /* known to fit  */
  SL_IRETURN(SL_ENONE, _("sl_trustfile"));
}

#ifdef TRUST_MAIN
int main (int argc, char * argv[])
{
  int status;
#if defined(SH_WITH_SERVER)
  struct passwd * pass;
#endif

  if (argc < 2) {
    fprintf(stderr, "%s: Usage: %s <fullpath>\n", argv[0], argv[0]);
    return 1;
  }

  tf_path[0] = '\0';
#if defined(SH_WITH_SERVER)
  pass = getpwnam(SH_IDENT);
  if (pass != NULL)
    tf_euid = pass->pw_uid;
  else
    {
      fprintf(stderr, "trustfile: ERROR: getpwnam(%s) failed\n",
            SH_IDENT);
      return 1;
    }
#else
  tf_euid = geteuid();
#endif

  status = sl_trustfile(argv[1], NULL, NULL);
  if (status != SL_ENONE)
    {
      fprintf(stderr, "trustfile: ERROR: not a trusted path: %s\n",
            argv[1]);
      return 1;
    }
  return 0;
}
#endif




Generated by  Doxygen 1.6.0   Back to index