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

sh_files.c

/* SAMHAIN file system integrity testing                                   */
/* Copyright (C) 1999 Rainer Wichmann                                      */
/*                                                                         */
/*  This program is free software; you can redistribute it                 */
/*  and/or modify                                                          */
/*  it under the terms of the GNU General Public License as                */
/*  published by                                                           */
/*  the Free Software Foundation; either version 2 of the License, or      */
/*  (at your option) any later version.                                    */
/*                                                                         */
/*  This program is distributed in the hope that it will be useful,        */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
/*  GNU General Public License for more details.                           */
/*                                                                         */
/*  You should have received a copy of the GNU General Public License      */
/*  along with this program; if not, write to the Free Software            */
/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */

#include "config_xor.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#include <errno.h>

/* Must be before <utime.h> on FreeBSD
 */
#include <sys/types.h>


#include <utime.h>


#ifdef HAVE_DIRENT_H
#include <dirent.h>
#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
#else
#define dirent direct
#define NAMLEN(dirent) (dirent)->d_namlen
#ifdef HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#ifdef HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#ifdef HAVE_NDIR_H
#include <ndir.h>
#endif
#endif

#ifdef HAVE_GLOB_H
#include <glob.h>
#endif

#include "samhain.h"

#if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)) 

#include "sh_error.h"
#include "sh_utils.h"
#include "sh_unix.h"
#include "sh_files.h"
#include "sh_tiger.h"
#include "sh_hash.h"
#include "sh_ignore.h"

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


extern int flag_err_debug;
extern int flag_err_info;

int sh_files_reportonce(char * c)
{
  int i;
  SL_ENTER(_("sh_files_reportonce"));
  i = sh_util_flagval(c, &(sh.flag.reportonce));

  SL_RETURN(i, _("sh_files_reportonce"));
}
    
int sh_files_fulldetail(char * c)
{
  int i;
  SL_ENTER(_("sh_files_fulldetail"));
  i = sh_util_flagval(c, &(sh.flag.fulldetail));

  SL_RETURN((i), _("sh_files_fulldetail"));
}
    

typedef struct dir_struct {
  long    NumRegular;
  long    NumDirs;
  long    NumSymlinks;
  long    NumFifos;
  long    NumSockets;
  long    NumCDev;
  long    NumBDev;
  long    NumAll;
  long    TotalBytes;
  char    DirPath[PATH_MAX];
} dir_type;

typedef struct dirstack_entry {
  char                  * name;
  int                     class;
  unsigned long           check_mask;
  int                     rdepth;
  short                   checked;
  short                   childs_checked;
  short                   reported;
  struct dirstack_entry * next;
} dirstack_t;

/* new 1.4.8
 */
static dirstack_t * dirListOne   = NULL;
static dirstack_t * dirListTwo   = NULL;

/* static dirstack_t * dirList      = NULL; */
static dirstack_t * fileList     = NULL;

static int        sh_files_fullpath  (char * testdir, char * d_name, 
                              char * statpath);
static int        sh_files_pushdir   (int class, char * str_s);
static int        sh_files_pushfile  (int class, char * str_s);
static int        sh_files_checkdir  (int class, int rdepth, char * dirName,
                              char * relativeName);
static ShFileType sh_files_filecheck (int class, char * dirName, 
                              char * fileName, int * reported,
                              int rsrcflag);

static long MaxRecursionLevel = 0;

/* set default recursion level
 */
int sh_files_setrecursion (char * flag_s)
{
  long flag = 0;
  static int reject = 0;

  SL_ENTER( _("sh_files_setrecursion"));

  if (reject == 1)
    SL_RETURN((-1), _("sh_files_setrecursion"));

  if (sh.flag.opts == 1)  
    reject = 1;

  if (flag_s != NULL) 
    flag = (int)(atof(flag_s));

  if (flag >= 0 && flag <= 99)
    MaxRecursionLevel = flag;
  else
    SL_RETURN((-1), _("sh_files_setrecursion"));

  SL_RETURN((0), _("sh_files_setrecursion"));
}


unsigned long sh_files_chk ()
{
  char       * tmp = NULL;
  ShFileType   status;

  dirstack_t * ptr;
  char       * base;
  char       * file;

  unsigned long fcount = 0;
  
  SL_ENTER(_("sh_files_chk"));

  ptr = fileList;

  while (ptr) 
    {

      if (sig_urgent > 0) {
      SL_RETURN(fcount, _("sh_files_chk"));
      }

      if (ptr->checked == S_FALSE)
      {
        base = sh_util_basename (ptr->name);
        file = sh_util_filename (ptr->name);
#if defined(WITH_TPT)
        tmp = sh_util_safe_name (ptr->name);
#endif

        
        if (flag_err_info == SL_TRUE)
          {
#if !defined(WITH_TPT)
            tmp = sh_util_safe_name (ptr->name);
#endif
            sh_error_handle ((-1),  FIL__, __LINE__, 0, MSG_FI_CHK,
                         tmp);
          }

        BREAKEXIT(sh_files_filecheck);
        status = sh_files_filecheck (ptr->class, base, file, 
                               (int *) &(ptr->reported), 0);
        
        TPT(( 0, FIL__, __LINE__, 
            _("msg=<filecheck complete: %s> status=<%d> reported=<%d>\n"), 
            tmp, status, ptr->reported));

        if (status == SH_FILE_UNKNOWN && ptr->reported == S_FALSE) 
          {
            TPT(( 0, FIL__, __LINE__, _("msg=<file: %s> status=<%d>\n"), 
                tmp, status));

            if ( sh.flag.checkSum == SH_CHECK_INIT  || 
              sh_hash_have_it (ptr->name) >= 0)
            {
              if (S_FALSE == sh_ignore_chk_del(ptr->name))
                {
                  if (0 != hashreport_missing(ptr->name, 
                                      (ptr->class == SH_LEVEL_ALLIGNORE) ? 
                                      ShDFLevel[ptr->class] : 
                                      ShDFLevel[SH_ERR_T_FILE])) {
                  if (tmp == NULL) 
                    tmp = sh_util_safe_name (ptr->name);
                  sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ? 
                               ShDFLevel[ptr->class] : 
                               ShDFLevel[SH_ERR_T_FILE],
                               FIL__, __LINE__, 0, MSG_FI_MISS,
                               tmp);
                  }
                }
            }
            else /* not there at init, and still missing */
            {
              if (tmp == NULL) 
                tmp = sh_util_safe_name (ptr->name);
              sh_error_handle (SH_ERR_NOTICE,
                           FIL__, __LINE__, 0,
                           MSG_FI_FAIL,
                           tmp);
            }
#ifndef REPLACE_OLD
            /* this will tell that we have seen the file, and thus prevent
             * deletion from the database, resulting in an incomplete
             * message when the file reappears
             */
            if (sh.flag.checkSum != SH_CHECK_INIT) 
            sh_hash_set_visited_true(ptr->name);
#else
            if (sh.flag.checkSum != SH_CHECK_INIT) 
            sh_hash_set_missing(ptr->name);
#endif
            if (sh.flag.reportonce == S_TRUE)
            ptr->reported = S_TRUE;
          }
        else 
          {
            /* exists (status >= 0), but was missing (reported == TRUE)
             */
            if (status != SH_FILE_UNKNOWN && ptr->reported == S_TRUE)
            {
              ptr->reported = S_FALSE;
            }
            /* Catchall
             */
            else if (status == SH_FILE_UNKNOWN)
            {
              /* Thu Mar  7 15:09:40 CET 2002 Make sure missing file
               * is reported if ptr->reported == S_TRUE because the
               * file has been added.
               */
              if (sh_hash_have_it (ptr->name) >= 0)
                {
                  if (S_FALSE == sh_ignore_chk_del(ptr->name))
                  {
                    if (0 != hashreport_missing(ptr->name, 
                                          (ptr->class == SH_LEVEL_ALLIGNORE) ? 
                                          ShDFLevel[ptr->class] : 
                                          ShDFLevel[SH_ERR_T_FILE])) {
                      if (tmp == NULL) 
                        tmp = sh_util_safe_name (ptr->name);
                      sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE)? 
                                   ShDFLevel[ptr->class] : 
                                   ShDFLevel[SH_ERR_T_FILE],
                                   FIL__, __LINE__, 0, MSG_FI_MISS,
                                   tmp);
                    }
                  }
#ifndef REPLACE_OLD
                  if (sh.flag.checkSum != SH_CHECK_INIT) 
                  sh_hash_set_visited_true(ptr->name);
#else
                  /* delete from database
                   */
                  if (sh.flag.checkSum != SH_CHECK_INIT) 
                  sh_hash_set_missing(ptr->name);
#endif
                }
              else
                {
                  if (tmp == NULL) 
                  tmp = sh_util_safe_name (ptr->name);
                  sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0,
                               MSG_FI_FAIL,
                               tmp);
                  if (sh.flag.checkSum != SH_CHECK_INIT)
                  sh_hash_set_visited_true(ptr->name);
                }
            }
            ++fcount;
          }
        
        if (tmp != NULL)
          {
            SH_FREE(tmp);
            tmp = NULL;
          }
        SH_FREE(file);
        SH_FREE(base);

        ptr->checked = S_TRUE;
      }
      ptr = ptr->next;
    }

  SL_RETURN(fcount, _("sh_files_chk"));
}

int sh_files_delfilestack ()
{
  dirstack_t * old_ptr = fileList;

  SL_ENTER(_("sh_files_delfilestack"));

  while (old_ptr != NULL) 
    {
      fileList = old_ptr->next;
      SH_FREE (old_ptr->name);
      SH_FREE (old_ptr);
      old_ptr = fileList;
    }
  SL_RETURN(0, _("sh_files_delfilestack"));
}
  
int sh_files_setrec_int (dirstack_t * ptr)
{
  SL_ENTER(_("sh_files_setrec"));
  while (ptr != NULL) {
    if (ptr->rdepth < (-1) || ptr->rdepth > 99)
      {
      ptr->rdepth = MaxRecursionLevel;
      }
    if (ptr->rdepth == (-1) && sh.flag.checkSum != SH_CHECK_INIT)
      hash_remove_tree (ptr->name);
    ptr = ptr->next;
  }
  SL_RETURN(0, _("sh_files_setrec"));
}

int sh_files_setrec ()
{
  sh_files_setrec_int(dirListOne);
  return sh_files_setrec_int(dirListTwo);
}

dirstack_t * sh_files_deldirstack_int (dirstack_t * ptr)
{
  dirstack_t * old_ptr = ptr;

  SL_ENTER(_("sh_files_deldirstack"));
  while (old_ptr != NULL) {
    ptr = old_ptr->next;
    SH_FREE (old_ptr->name);
    SH_FREE (old_ptr);
    old_ptr = ptr;
  }
  SL_RETURN(ptr, _("sh_files_deldirstack"));
}

int sh_files_deldirstack ()
{
  dirListOne = sh_files_deldirstack_int(dirListOne);
  dirListTwo = sh_files_deldirstack_int(dirListTwo);
  return 0;
}

void sh_files_reset()
{
  dirstack_t * ptr = fileList;

  SL_ENTER(_("sh_files_reset"));
  while (ptr != NULL) {
    ptr->checked = 0;
    ptr = ptr->next;
  }
  SL_RET0(_("sh_files_reset"));
}

void sh_dirs_reset()
{
  dirstack_t * ptr = dirListOne;

  SL_ENTER(_("sh_dirs_reset"));
  while (ptr != NULL) {
    ptr->checked = 0;
    ptr = ptr->next;
  }
  ptr = dirListTwo;
  while (ptr != NULL) {
    ptr->checked = 0;
    ptr = ptr->next;
  }
  SL_RET0(_("sh_dirs_reset"));
}


int sh_files_pushfile_prelink (char * str_s)
{
  return (sh_files_pushfile (SH_LEVEL_PRELINK, str_s));
}

int sh_files_pushfile_user0 (char * str_s)
{
  return (sh_files_pushfile (SH_LEVEL_USER0, str_s));
}


int sh_files_pushfile_user1 (char * str_s)
{
  return (sh_files_pushfile (SH_LEVEL_USER1, str_s));
}


int sh_files_pushfile_ro (char * str_s)
{
  return (sh_files_pushfile (SH_LEVEL_READONLY, str_s));
}

int sh_files_pushfile_attr (char * str_s)
{
  return (sh_files_pushfile (SH_LEVEL_ATTRIBUTES, str_s));
}

int sh_files_pushfile_log (char * str_s)
{
  return (sh_files_pushfile (SH_LEVEL_LOGFILES, str_s));
}

int sh_files_pushfile_glog (char * str_s)
{
  return (sh_files_pushfile (SH_LEVEL_LOGGROW, str_s));
}

int sh_files_pushfile_noig (char * str_s)
{
  return (sh_files_pushfile (SH_LEVEL_NOIGNORE, str_s));
}

int sh_files_pushfile_allig (char * str_s)
{
  return (sh_files_pushfile (SH_LEVEL_ALLIGNORE, str_s));
}


static void sh_files_set_mask (unsigned long * mask, 
                         unsigned long val, int act)
{
  SL_ENTER(_("sh_files_set_mask"));

  if       (act == 0)
    (*mask)  = val;
  else if  (act > 0)
    (*mask) |= val;
  else 
    (*mask) &= ~val;

  SL_RET0(_("sh_files_set_mask"));
}

/* set mask(class)
 */
static int sh_files_parse_mask (unsigned long * mask, char * str)
{
  int l, i = 0, act = 0, k = 0;
  char  myword[64];
  
  SL_ENTER(_("sh_files_parse_mask"));

  if (str == NULL)
    {
      SL_RETURN ( (-1), _("sh_files_parse_mask"));
    }
  else
    l = sl_strlen(str);

  while (i < l) {
    if (str[i] == '\0')
      break;
    if (str[i] == ' ' || str[i] == '\t' || str[i] == ',')
      {
      ++i;
      continue;
      }

    if (str[i] == '+')
      {
      act = +1; ++i;
      continue;
      }
    else if (str[i] == '-')
      {
      act = -1; ++i;
      continue;
      }
    else /* a word */
      {
      k = 0;
      while (k < 63 && str[i] != ' ' && str[i] != '\t' && str[i] != ','
             && str[i] != '+' && str[i] != '-' && str[i] != '\0') {
        myword[k] = str[i]; 
        ++i; ++k;
      }
      myword[k] = '\0';

/* checksum     */
      if (0 == strncmp(myword, _("CHK"), 3))
        sh_files_set_mask (mask, MODI_CHK, act);
/* link         */
      if (0 == strncmp(myword, _("LNK"), 3))
        sh_files_set_mask (mask, MODI_LNK, act);
/* inode        */
      if (0 == strncmp(myword, _("RDEV"), 3))
        sh_files_set_mask (mask, MODI_RDEV, act);
/* inode        */
      if (0 == strncmp(myword, _("INO"), 3))
        sh_files_set_mask (mask, MODI_INO, act);
/* user         */
      if (0 == strncmp(myword, _("USR"), 3))
        sh_files_set_mask (mask, MODI_USR, act);
/* group        */
      if (0 == strncmp(myword, _("GRP"), 3))
        sh_files_set_mask (mask, MODI_GRP, act);
/* mtime        */
      if (0 == strncmp(myword, _("MTM"), 3))
        sh_files_set_mask (mask, MODI_MTM, act);
/* ctime        */
      if (0 == strncmp(myword, _("CTM"), 3))
        sh_files_set_mask (mask, MODI_CTM, act);
/* atime        */
      if (0 == strncmp(myword, _("ATM"), 3))
        sh_files_set_mask (mask, MODI_ATM, act);
/* size         */
      if (0 == strncmp(myword, _("SIZ"), 3))
        sh_files_set_mask (mask, MODI_SIZ, act);
/* file mode    */
      if (0 == strncmp(myword, _("MOD"), 3))
        sh_files_set_mask (mask, MODI_MOD, act);
/* hardlinks    */
      if (0 == strncmp(myword, _("HLN"), 3))
        sh_files_set_mask (mask, MODI_HLN, act);
      
      }
  }
  SL_RETURN ( (0), _("sh_files_parse_mask"));
}

int sh_files_redef_prelink(char * str)
{
  return (sh_files_parse_mask(&mask_PRELINK, str));
} 
int sh_files_redef_user0(char * str)
{
  return (sh_files_parse_mask(&mask_USER0, str));
} 
int sh_files_redef_user1(char * str)
{
  return (sh_files_parse_mask(&mask_USER1, str));
} 
int sh_files_redef_readonly(char * str)
{
  return (sh_files_parse_mask(&mask_READONLY, str));
} 
int sh_files_redef_loggrow(char * str)
{
  return (sh_files_parse_mask(&mask_LOGGROW, str));
} 
int sh_files_redef_logfiles(char * str)
{
  return (sh_files_parse_mask(&mask_LOGFILES, str));
} 
int sh_files_redef_attributes(char * str)
{
  return (sh_files_parse_mask(&mask_ATTRIBUTES, str));
} 
int sh_files_redef_noignore(char * str)
{
  return (sh_files_parse_mask(&mask_NOIGNORE, str));
} 
int sh_files_redef_allignore(char * str)
{
  return (sh_files_parse_mask(&mask_ALLIGNORE, str));
} 

unsigned long sh_files_maskof (int class)
{
  switch (class)
    {
    case SH_LEVEL_READONLY:
      return (unsigned long) mask_READONLY;
    case SH_LEVEL_ATTRIBUTES:
      return (unsigned long) mask_ATTRIBUTES;
    case SH_LEVEL_LOGFILES:
      return (unsigned long) mask_LOGFILES;
    case SH_LEVEL_LOGGROW:
      return (unsigned long) mask_LOGGROW;
    case SH_LEVEL_ALLIGNORE:
      return (unsigned long) mask_ALLIGNORE;
    case SH_LEVEL_NOIGNORE:
      return (unsigned long) mask_NOIGNORE;
    case SH_LEVEL_USER0:
      return (unsigned long) mask_USER0;
    case SH_LEVEL_USER1:
      return (unsigned long) mask_USER1;
    case SH_LEVEL_PRELINK:
      return (unsigned long) mask_PRELINK;
    default:
      return (unsigned long) 0;
    }
}

#ifdef HAVE_GLOB_H
int sh_files_has_metachar (const char * str)
{
  SL_ENTER(_("sh_files_has_metachar"));
  if      (NULL != strchr(str, '*'))
    SL_RETURN(1, _("sh_files_has_metachar"));
  else if (NULL != strchr(str, '?'))
    SL_RETURN(1, _("sh_files_has_metachar"));
  else if (NULL != (strchr(str, '[')))
    SL_RETURN(1, _("sh_files_has_metachar"));
  else
    SL_RETURN(0, _("sh_files_has_metachar"));
}


int sh_files_globerr (const char * epath, int errnum)
{
  char * p;

  SL_ENTER(_("sh_files_globerr"));

  p = sh_util_safe_name (epath);
  sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_FI_GLOB,
               sh_error_message (errnum), p);
  SH_FREE(p);

  SL_RETURN(0, _("sh_files_globerr"));
}

/* #ifdef HAVE_GLOB_H 
 */
#endif

int sh_files_push_file_int (int class, const char * str_s, int len)
{
  dirstack_t * new_item_ptr;
  char  * fileName;

  SL_ENTER(_("sh_files_push_file_int"));

  fileName = SH_ALLOC(len+1);
  sl_strlcpy(fileName, str_s, len+1);

  new_item_ptr = (dirstack_t *) SH_ALLOC (sizeof(dirstack_t));

  new_item_ptr->name           = fileName;
  new_item_ptr->class          = class;
  new_item_ptr->check_mask     = sh_files_maskof(class);
  new_item_ptr->rdepth         = 0;
  new_item_ptr->checked        = S_FALSE;
  new_item_ptr->reported       = S_FALSE;
  new_item_ptr->childs_checked = S_FALSE;
  new_item_ptr->next           = fileList;

  fileList = new_item_ptr;
  SL_RETURN(0, _("sh_files_push_file_int"));
}


static int sh_files_pushfile (int class, char * str_s)
{
  char  * tmp;
  int     len;
#ifdef HAVE_GLOB_H
  glob_t  pglob;
  int     globstatus = -1;
  unsigned int     gloop;
#endif

  static int reject = 0;

  SL_ENTER(_("sh_files_pushfile"));

  if (reject == 1)
    SL_RETURN((-1),_("sh_files_pushfile"));

  /* if we push a filename from the command line, make sure it
   * is the only one -- and will stay the only one
   */
  if (sh.flag.opts == 1) 
    {
      sh_files_delfilestack ();
      sh_files_deldirstack ();
      reject = 1;
    }

  if (str_s == NULL) 
    SL_RETURN((-1),_("sh_files_pushfile"));

  len = sl_strlen(str_s);

  if (len >= PATH_MAX) 
    {
      /* Name too long
       */
      tmp = sh_util_safe_name (str_s);
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_2LONG,
                   tmp);
      SH_FREE(tmp);
      SL_RETURN((-1),_("sh_files_pushfile"));
    } 
  else if (len < 1) 
    {
      /* Should not happen (str_s == NULL caught further above)
       */
      SL_RETURN((-1),_("sh_files_pushfile"));
    } 
  else if (str_s[0] != '/') 
    {
      /* Not an absolute path
       */
      tmp = sh_util_safe_name (str_s);
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NOPATH,
                   tmp);
      SH_FREE(tmp);
      SL_RETURN((-1),_("sh_files_pushfile"));
    } 
  else 
    {
      /* remove a terminating '/', take care of the 
       * special case of the root directory.
       */
      if (str_s[len-1] == '/' && len > 1)
      {
        str_s[len-1] = '\0';
        --len;
      }
      
    } 

#ifdef HAVE_GLOB_H
  if (0 == sh_files_has_metachar(str_s))
    {
      sh_files_push_file_int (class, str_s, len);
    }
  else
    {
      pglob.gl_offs = 0;
      globstatus    = glob (str_s, 0, sh_files_globerr, &pglob);

      if (globstatus == 0 && pglob.gl_pathc > 0)
      {
        for (gloop = 0; gloop < (unsigned int) pglob.gl_pathc; ++gloop)
          sh_files_push_file_int (class, pglob.gl_pathv[gloop], 
                            sl_strlen(pglob.gl_pathv[gloop]));
      }
      else
      {
        tmp = sh_util_safe_name (str_s);

        if (pglob.gl_pathc == 0
#ifdef GLOB_NOMATCH
            || globstatus == GLOB_NOMATCH
#endif
            )
          sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, 
                       globstatus, MSG_FI_GLOB,
                       _("No matches found"), tmp);
#ifdef GLOB_NOSPACE
        else if (globstatus == GLOB_NOSPACE)
          sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
                       globstatus, MSG_FI_GLOB,
                       _("Out of memory"), tmp);
#endif
#ifdef GLOB_ABORTED
        else if (globstatus == GLOB_ABORTED)
          sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
                       globstatus, MSG_FI_GLOB,
                       _("Read error"), tmp);
#endif
        else 
          sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
                       globstatus, MSG_FI_GLOB,
                       _("Unknown error"), tmp);

        SH_FREE(tmp);

      }

      globfree(&pglob);
    }

#else
  sh_files_push_file_int (class, str_s, len);
#endif

  SL_RETURN((0),_("sh_files_pushfile"));
}


/* ------ directories ----- */

int sh_files_is_allignore_int (char * str, dirstack_t * ptr)
{
  SL_ENTER(_("sh_files_is_allignore"));

  while (ptr)
    {
      if (0 == strcmp(str, ptr->name))
      {
        if (ptr->class == SH_LEVEL_ALLIGNORE)
          SL_RETURN( 1, _("sh_files_is_allignore"));
        else
          SL_RETURN( 0, _("sh_files_is_allignore"));
      }
      ptr = ptr->next;
    }
  SL_RETURN( 0, _("sh_files_is_allignore"));
}

int sh_files_is_allignore (char * str)
{
  if (1 == sh_files_is_allignore_int(str, dirListOne))
    return 1;
  if (NULL == dirListTwo)
    return 0;
  return sh_files_is_allignore_int(str, dirListTwo);
}

unsigned long sh_dirs_chk (int which)
{
  dirstack_t * ptr;
  dirstack_t * dst_ptr;
  int          status;
  unsigned long dcount = 0;
  char       * tmp;
  
  SL_ENTER(_("sh_dirs_chk"));

  if (which == 1)
    ptr = dirListOne;
  else
    ptr = dirListTwo;

  while (ptr) 
    {
      if (sig_urgent > 0) {
      SL_RETURN(dcount, _("sh_dirs_chk"));
      }

      if (ptr->checked == S_FALSE)
      {
        /* 28 Aug 2001 check the top level directory
         */
        status        = S_FALSE;
        dst_ptr       = fileList;
        while (dst_ptr) 
          {
            if (0 == sl_strcmp(dst_ptr->name,  ptr->name))
            {
              if (dst_ptr->checked == S_FALSE)
                {
                  BREAKEXIT(sh_files_filecheck);
                  sh_files_filecheck (dst_ptr->class,  ptr->name,  
                                NULL,  &status, 0);
                  dst_ptr->checked = S_TRUE;
                  status           = S_TRUE;
                  break;
                }
              else
                {
                  status           = S_TRUE;
                  break;
                }
            }
            dst_ptr = dst_ptr->next;
          }
        if (status == S_FALSE)
          sh_files_filecheck (ptr->class,  ptr->name,  NULL,  &status, 0);

        BREAKEXIT(sh_files_checkdir);
        status = sh_files_checkdir (ptr->class, ptr->rdepth, ptr->name, 
                              ptr->name);

        if (status < 0 && ptr->reported == S_FALSE) 
          {
            /* directory is missing
             */
            if (S_FALSE == sh_ignore_chk_del(ptr->name))
            {
              if (0 != hashreport_missing(ptr->name, 
                                    (ptr->class == SH_LEVEL_ALLIGNORE) ? 
                                    ShDFLevel[ptr->class] : 
                                    ShDFLevel[SH_ERR_T_DIR])) {
                tmp = sh_util_safe_name (ptr->name);
                sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ? 
                             ShDFLevel[ptr->class] : 
                             ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__,
                             0, MSG_FI_MISS, tmp);
                SH_FREE(tmp);
              }
            }
            if (sh.flag.reportonce == S_TRUE)
            ptr->reported = S_TRUE;
          } 
        else 
          {
            /* exists (status >= 0), but was missing (reported == TRUE)
             */
            if (status >= 0 && ptr->reported == S_TRUE)
            {
              ptr->reported = S_FALSE;
#if 0
              /* obsoleted (really?) by the mandatory sh_files_filecheck()
               * above, which will catch missing directories anyway
               */
              tmp = sh_util_safe_name (ptr->name);
              sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ? 
                           ShDFLevel[ptr->class] : 
                           ShDFLevel[SH_ERR_T_DIR],
                           FIL__, __LINE__, 0, MSG_FI_ADD,
                           tmp);
              SH_FREE(tmp);
#endif
            }
            else if (status == SH_FILE_UNKNOWN)
            {
              /* catchall
               */
              tmp = sh_util_safe_name (ptr->name);
              sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0,
                           MSG_FI_FAIL,
                           tmp);
              SH_FREE(tmp);
              if (sh.flag.checkSum != SH_CHECK_INIT)
                sh_hash_set_visited_true(ptr->name);
            }

            ++dcount;
          }
        ptr->checked = S_TRUE;
      }

      if (sig_urgent > 0) {
      SL_RETURN(dcount, _("sh_dirs_chk"));
      }

      ptr = ptr->next;
    }
  SL_RETURN(dcount, _("sh_dirs_chk"));
}

int sh_files_pushdir_prelink (char * str_s)
{
  return (sh_files_pushdir (SH_LEVEL_PRELINK, str_s));
}

int sh_files_pushdir_user0 (char * str_s)
{
  return (sh_files_pushdir (SH_LEVEL_USER0, str_s));
}

int sh_files_pushdir_user1 (char * str_s)
{
  return (sh_files_pushdir (SH_LEVEL_USER1, str_s));
}

int sh_files_pushdir_attr (char * str_s)
{
  return (sh_files_pushdir (SH_LEVEL_ATTRIBUTES, str_s));
}

int sh_files_pushdir_ro (char * str_s)
{
  return (sh_files_pushdir (SH_LEVEL_READONLY, str_s));
}

int sh_files_pushdir_log (char * str_s)
{
  return (sh_files_pushdir (SH_LEVEL_LOGFILES, str_s));
}

int sh_files_pushdir_glog (char * str_s)
{
  return (sh_files_pushdir (SH_LEVEL_LOGGROW, str_s));
}

int sh_files_pushdir_noig (char * str_s)
{
  return (sh_files_pushdir (SH_LEVEL_NOIGNORE, str_s));
}

int sh_files_pushdir_allig (char * str_s)
{
  return (sh_files_pushdir (SH_LEVEL_ALLIGNORE, str_s));
}

static int which_dirList = 1;

int set_dirList (int which)
{
  if (which == 2)
    which_dirList = 2;
  else
    which_dirList = 1;
  return 0;
}

int sh_files_push_dir_int (int class, char * tail, int len, int rdepth)
{
  dirstack_t * new_item_ptr;
  char  * dirName;

  SL_ENTER(_("sh_files_push_dir_int"));

  dirName = SH_ALLOC(len+1);
  sl_strlcpy(dirName, tail, len+1);

  new_item_ptr = (dirstack_t * ) SH_ALLOC (sizeof(dirstack_t));

  new_item_ptr->name           = dirName;
  new_item_ptr->class          = class;
  new_item_ptr->check_mask     = sh_files_maskof(class);
  new_item_ptr->rdepth         = rdepth;
  new_item_ptr->checked        = S_FALSE;
  new_item_ptr->reported       = S_FALSE;
  new_item_ptr->childs_checked = S_FALSE;

  if (which_dirList == 1)
    {
      new_item_ptr->next           = dirListOne;
      dirListOne                   = new_item_ptr;
    }
  else
    {
      new_item_ptr->next           = dirListTwo;
      dirListTwo                   = new_item_ptr;
    }
  SL_RETURN(0, _("sh_files_push_dir_int"));
}

static int sh_files_pushdir (int class, char * str_s)
{
  char  * tmp;
  int     len;
  int     rdepth = 0;
  char  * tail = NULL;

#ifdef HAVE_GLOB_H
  glob_t  pglob;
  int     globstatus = -1;
  unsigned int     gloop;
#endif

  SL_ENTER(_("sh_files_pushdir"));

  if (sh.flag.opts == 1) {
    sh_files_delfilestack ();
    sh_files_deldirstack ();
  }

  if (str_s == NULL)
    SL_RETURN((-1), _("sh_files_pushdir"));
  

  if (str_s[0] != '/')
    {
      rdepth = strtol(str_s, &tail, 10);
      if (tail == str_s)
      SL_RETURN((-1), _("sh_files_pushdir"));
    }
  else
    tail   = str_s;
  

  if (rdepth < (-1) || tail == str_s || rdepth > 99)
    rdepth = (-2);

  len = sl_strlen(tail);

  if (len >= PATH_MAX) 
    {
      tmp = sh_util_safe_name (tail);
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_2LONG,
                   tmp);
      SH_FREE(tmp);
      SL_RETURN((-1), _("sh_files_pushdir"));
    } 
  else if (len < 1) 
    {
      SL_RETURN((-1), _("sh_files_pushdir"));
    } 
  else if (tail[0] != '/') 
    {
      tmp = sh_util_safe_name (tail);
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NOPATH,
                   tmp);
      SH_FREE(tmp);
      SL_RETURN((-1), _("sh_files_pushdir"));
    } 
  else 
    {
      
      if (tail[len-1] == '/' && len > 1)
      {
        tail[len-1] = '\0';
        --len;
      }
      
    } 

#ifdef HAVE_GLOB_H
  if (0 == sh_files_has_metachar(tail))
    {
      sh_files_push_dir_int (class, tail, len, rdepth);
    }
  else
    {
      pglob.gl_offs = 0;
      globstatus    = glob (tail, 0, sh_files_globerr, &pglob);

      if (globstatus == 0 && pglob.gl_pathc > 0)
      {
        for (gloop = 0; gloop < (unsigned int) pglob.gl_pathc; ++gloop)
          sh_files_push_dir_int (class, 
                           pglob.gl_pathv[gloop], 
                           sl_strlen(pglob.gl_pathv[gloop]), 
                           rdepth);
      }
      else
      {
        tmp = sh_util_safe_name (tail);

        if (pglob.gl_pathc == 0
#ifdef GLOB_NOMATCH
            || globstatus == GLOB_NOMATCH
#endif
            )
          sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, 
                       globstatus, MSG_FI_GLOB,
                       _("No matches found"), tmp);
#ifdef GLOB_NOSPACE
        else if (globstatus == GLOB_NOSPACE)
          sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
                       globstatus, MSG_FI_GLOB,
                       _("Out of memory"), tmp);
#endif
#ifdef GLOB_ABORTED
        else if (globstatus == GLOB_ABORTED)
          sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
                       globstatus, MSG_FI_GLOB,
                       _("Read error"), tmp);
#endif
        else 
          sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
                       globstatus, MSG_FI_GLOB,
                       _("Unknown error"), tmp);
        SH_FREE(tmp);
      }

      globfree(&pglob);
    }
#else  
  sh_files_push_dir_int (class, tail, len, rdepth);
#endif

  SL_RETURN((0), _("sh_files_pushdir"));
}  

struct sh_dirent {
  /* char               sh_d_name[NAME_MAX + 2]; */
  char             * sh_d_name;
  struct sh_dirent * next;
};

static void kill_sh_dirlist (struct sh_dirent * dirlist)
{
  struct sh_dirent * this;

  while (dirlist)
    {
      this    = dirlist->next;
      SH_FREE(dirlist->sh_d_name);
      SH_FREE(dirlist);
      dirlist = this;
    }
  return;
}
  
/* -- add an entry to a directory listing
 */
static struct sh_dirent * addto_sh_dirlist (struct dirent * thisEntry, 
                                  struct sh_dirent * dirlist)
{
  struct sh_dirent * this;
  int i;

  if (thisEntry == NULL)
    return dirlist;
  
  i = sl_strlen(thisEntry->d_name);
  if (i == 0)
    return dirlist;
  ++i;
  
  this = SH_ALLOC(sizeof(struct sh_dirent));
  if (!this)
    return dirlist;

  this->sh_d_name = SH_ALLOC(i);
  sl_strlcpy(this->sh_d_name, thisEntry->d_name, i);

  this->next = dirlist;
  return this;
}

static int sh_check_hardlinks = S_TRUE;

/* Simply sets our boolean as to whether this check is active 
 */
int sh_files_check_hardlinks (char * opt)
{
  int i;
  SL_ENTER(_("sh_files_check_hardlinks"));
  i = sh_util_flagval(opt, &sh_check_hardlinks);
  SL_RETURN(i, _("sh_files_check_hardlinks"));
}

struct sh_hle_struct {
  long   offset;
  char * path;
  struct sh_hle_struct * next;
};

static struct sh_hle_struct * sh_hl_exc = NULL;

int sh_files_hle_reg (char * str)
{
  long   offset;
  size_t len;
  char * path;
  
  struct sh_hle_struct * tmp = sh_hl_exc;

  SL_ENTER(_("sh_files_hle_reg"));

  /* Free the linked list if called with NULL argument
   */
  if (str == NULL)
    {
      while (tmp)
      {
        sh_hl_exc = tmp->next;
        SH_FREE(tmp->path);
        SH_FREE(tmp);
        tmp = sh_hl_exc;
      }
      sh_hl_exc = NULL;
      SL_RETURN(0, _("sh_files_hle_reg"));
    }

  /* We expect 'offset:/path'
   */
  offset = strtol(str, &path, 0);
  if ((path == NULL) || (*path == '\0') || (*path != ':') || (path[1] != '/'))
    {
      SL_RETURN(-1, _("sh_files_hle_reg"));
    }
  ++path;
  len = 1 + sl_strlen(path);

  tmp         = SH_ALLOC(sizeof(struct sh_hle_struct));
  tmp->path   = SH_ALLOC(len);
  sl_strlcpy (tmp->path, path, len);
  tmp->offset = offset;
  tmp->next   = sh_hl_exc;
  sh_hl_exc   = tmp;

  SL_RETURN(0, _("sh_files_hle_reg"));
}

#if !defined(HOST_IS_DARWIN)
static int sh_files_hle_test (int offset, char * path)
{
  struct sh_hle_struct * tmp = sh_hl_exc;

  SL_ENTER(_("sh_files_hle_reg"));

  while(tmp)
    {
      if ((offset == tmp->offset) && (0 == strcmp(path, tmp->path)))
      {
        SL_RETURN(0, _("sh_files_hle_test"));
      }
      tmp = tmp->next;
    }
  SL_RETURN(-1, _("sh_files_hle_test"));
}
#endif

/* -- check a single directory and its content
 */
static int sh_files_checkdir (int iclass, int idepth, char * iname, 
                        char * relativeName)
{
  struct sh_dirent * dirlist = NULL;
  struct sh_dirent * dirlist_orig = NULL;

  DIR *           thisDir = NULL;
  struct dirent * thisEntry;
  int             status;
  int             dummy = S_FALSE;
  dir_type        theDir;
  ShFileType      checkit;


  file_type       theFile;
  char          * tmpname;
  char          * tmpcat;

  int             rdepth = 0;
  int             class  = 0;
  int             rdepth_next;
  int             class_next;
  int             file_class_next;

  int             checked_flag  = S_FALSE;
  int             cchecked_flag = S_FALSE;

  dirstack_t *    dst_ptr;

  int             hardlink_num = 0;


  SL_ENTER(_("sh_files_checkdir"));

  if (sig_urgent > 0) {
    SL_RETURN((0), _("sh_files_checkdir"));
  }

  if (iname == NULL || idepth < (-1))
    SL_RETURN((-1), _("sh_files_checkdir"));
  
  if (idepth < 0)
    {
      /* hash_remove_tree (iname); */
      SL_RETURN((0), _("sh_files_checkdir"));
    }
  
  rdepth = idepth;
  class  = iclass;
  
  tmpname = sh_util_safe_name (iname);

  /* ---- check for obscure name ----
   */
  if (iclass != SH_LEVEL_ALLIGNORE)
    {
      sh_util_obscurename (ShDFLevel[SH_ERR_T_NAME], iname, S_TRUE);
    }

  sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_CHK,
               tmpname);
  
  /* ---- check input ----
   */
  if ( sl_strlen(iname) >= PATH_MAX) 
    {
      sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
                   MSG_FI_2LONG,
                   tmpname);
      SH_FREE(tmpname);
      SL_RETURN((-1), _("sh_files_checkdir"));
    }
  
  /* ---- check for absolute path ---- */
  if ( iname[0] != '/') 
    {
      sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
                   MSG_FI_NOPATH,
                   tmpname);
      SH_FREE(tmpname);
      SL_RETURN((-1), _("sh_files_checkdir"));
    }
    
    
  /* ---- stat the directory ----
   */
  sl_strlcpy (theFile.fullpath, iname, PATH_MAX);

  (void) relativeName;
  status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_DIR], 
                      iname,
                      &theFile, NULL, iclass);

  if ((sig_termfast == 1) || (sig_terminate == 1)) 
    {
      SL_RETURN((0), _("sh_files_checkdir"));
    }

  if (status == -1)
    {
      SH_FREE(tmpname); 
      SL_RETURN((-1), _("sh_files_checkdir"));
    }

  if (theFile.c_mode[0] != 'd') 
    { 
      sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
                   MSG_FI_NODIR,
                   tmpname);
      SH_FREE(tmpname); 
      SL_RETURN((-1), _("sh_files_checkdir"));
    }

  hardlink_num = theFile.hardlinks;


  /* ---- open directory for reading ---- 
   *
   * opendir() will fail with ENOTDIR if the path has been changed
   * to a non-directory in between lstat() and opendir().
   */
  thisDir = opendir (iname);

  if (thisDir == NULL) 
    {
      status = errno;
      sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
                   MSG_E_OPENDIR,
                   sh_error_message (status), tmpname);
      SH_FREE(tmpname); 

      SL_RETURN((-1), _("sh_files_checkdir"));
    }

  theDir.NumRegular  = 0;
  theDir.NumDirs     = 0;
  theDir.NumSymlinks = 0;
  theDir.NumFifos    = 0;
  theDir.NumSockets  = 0;
  theDir.NumCDev     = 0;
  theDir.NumBDev     = 0;
  theDir.NumAll      = 0;
  theDir.TotalBytes  = 0;
  sl_strlcpy (theDir.DirPath, iname, PATH_MAX); 


  /* ---- read ----
   */
  do {
      thisEntry = readdir (thisDir);
      if (thisEntry != NULL) 
      {
        ++theDir.NumAll;
        if (sl_strcmp (thisEntry->d_name, ".") == 0)
          { 
            ++theDir.NumDirs;
            continue;
          }
        if (sl_strcmp (thisEntry->d_name, "..") == 0)
          {
            ++theDir.NumDirs;
            continue;
          }
        dirlist = addto_sh_dirlist (thisEntry, dirlist);
      }
  } while (thisEntry != NULL);

  closedir (thisDir);

  ++sh.statistics.dirs_checked;

  dirlist_orig = dirlist;

  do {

    /* If the directory is empty, dirlist = NULL
     */
    if (!dirlist)
      break;

    if (sig_termfast == 1) 
      {
      SL_RETURN((0), _("sh_files_checkdir"));
      }

    BREAKEXIT(sh_derr);
    if (0 == (rand() % 5))
      (void) sh_derr();
    
    /* ---- Check the file. ---- 
     */
    tmpcat = SH_ALLOC(PATH_MAX);
    sl_strlcpy(tmpcat, iname,                   PATH_MAX);
    if (sl_strlen(tmpcat) > 1 || tmpcat[0] != '/')
      sl_strlcat(tmpcat, "/",                   PATH_MAX);
    sl_strlcat(tmpcat, dirlist->sh_d_name,      PATH_MAX);
    
    rdepth_next     = rdepth - 1;
    class_next      = class;
    file_class_next = class;
    checked_flag    = -1;
    cchecked_flag   = -1;

    /* Wed Aug 24 2005 compare against dirListOne, dirListTwo
     * this fixes the problem that the directory special file
     * is checked with the policy of the parent directory
     */
    dst_ptr         = dirListOne;
    while (dst_ptr) 
      {
      if (0 == sl_strcmp(dst_ptr->name,  tmpcat))
        {
          /* Tue Aug  6 22:13:27 CEST 2002 introduce file_class_next
           * this fixes the problem that a policy for the directory
           * inode erroneously becomes a policy for the directory itself.
           */
          file_class_next    = dst_ptr->class;
          checked_flag       = dst_ptr->checked;
          cchecked_flag      = dst_ptr->childs_checked;
          break;
        }
      dst_ptr = dst_ptr->next;
      }

    if (checked_flag == -1)
      {
      dst_ptr         = dirListTwo;
      while (dst_ptr) 
        {
          if (0 == sl_strcmp(dst_ptr->name,  tmpcat))
            {
            /* Tue Aug  6 22:13:27 CEST 2002 introduce file_class_next
             * this fixes the problem that a policy for the directory
             * inode erroneously becomes a policy for the directory itself.
             */
            file_class_next    = dst_ptr->class;
            checked_flag       = dst_ptr->checked;
            cchecked_flag      = dst_ptr->childs_checked;
            break;
            }
          dst_ptr = dst_ptr->next;
        }
      }

    dst_ptr         = fileList;
    while (dst_ptr) 
      {
      if (0 == sl_strcmp(dst_ptr->name,  tmpcat))
        {
          /* Tue Aug  6 22:13:27 CEST 2002 introduce file_class_next
           * this fixes the problem that a policy for the directory
           * inode erroneously becomes a policy for the directory itself.
           */
          file_class_next    = dst_ptr->class;
          checked_flag       = dst_ptr->checked;
          cchecked_flag      = dst_ptr->childs_checked;
          break;
        }
      dst_ptr = dst_ptr->next;
      }
    
    /* ---- Has been checked already. ----
     */
    if (checked_flag == S_TRUE && cchecked_flag == S_TRUE)
      {
      /* Mar 11 2004 get ftype for complete directory count
       */
      checkit = sh_unix_get_ftype(tmpcat);
      if (checkit == SH_FILE_DIRECTORY) 
        {
          ++theDir.NumDirs;
        }
      SH_FREE(tmpcat);
      dirlist = dirlist->next;
      continue;
      }
    
    /* --- May be true, false, or not found. --- 
     */
    if (checked_flag == S_TRUE)
      {
      /* -- need only the file type --
       */
      checkit = sh_unix_get_ftype(tmpcat);
      }
    else
      {
      /* -- need to check the file itself --
       */
      if (dst_ptr && sh.flag.reportonce == S_TRUE)
        dummy = dst_ptr->reported;

      checkit = sh_files_filecheck (file_class_next, 
                              iname, 
                              dirlist->sh_d_name,
                              &dummy, 0);

      if (dst_ptr && checked_flag == S_FALSE)
        dst_ptr->checked = S_TRUE;
      /* Thu Mar  7 15:09:40 CET 2002 Propagate the 'reported' flag
       */
      if (dst_ptr && sh.flag.reportonce == S_TRUE)
        dst_ptr->reported = dummy;
      }
    
    if      (checkit == SH_FILE_REGULAR)   
      ++theDir.NumRegular;
    
    else if (checkit == SH_FILE_DIRECTORY) 
      {
      ++theDir.NumDirs;
      if (rdepth_next >= 0 && cchecked_flag != S_TRUE) 
        {
          rdepth_next = rdepth - 1;
          
          /* check whether the new directory is in the
           * list with a recursion depth already defined
           */
          checked_flag  = -1;
          cchecked_flag = -1;
          
          dst_ptr     = dirListOne;
          while (dst_ptr) 
            {
            if (0 == sl_strcmp(dst_ptr->name, tmpcat))
              {
                TPT((0, FIL__, __LINE__, 
                   _("msg=<%s -> recursion depth %d\n>"),
                   dst_ptr->name, dst_ptr->rdepth));
                rdepth_next   = dst_ptr->rdepth;
                class_next    = dst_ptr->class;
                /* 28. Aug 2001 reversed
                 */
                cchecked_flag = dst_ptr->childs_checked;
                checked_flag  = dst_ptr->checked;
                break;
              }
            dst_ptr = dst_ptr->next;
            }
          
          if (checked_flag == -1)
            {
            dst_ptr     = dirListTwo;
            while (dst_ptr) 
              {
                if (0 == sl_strcmp(dst_ptr->name, tmpcat))
                  {
                  TPT((0, FIL__, __LINE__, 
                       _("msg=<%s -> recursion depth %d\n>"),
                       dst_ptr->name, dst_ptr->rdepth));
                  rdepth_next   = dst_ptr->rdepth;
                  class_next    = dst_ptr->class;
                  /* 28. Aug 2001 reversed
                   */
                  cchecked_flag = dst_ptr->childs_checked;
                  checked_flag  = dst_ptr->checked;
                  break;
                  }
                dst_ptr = dst_ptr->next;
              }
            }
          
          if (cchecked_flag == S_FALSE)
            {
            sh_files_checkdir (class_next, rdepth_next, tmpcat, 
                           dirlist->sh_d_name);
            dst_ptr->childs_checked = S_TRUE;
            }
          else if (checked_flag == -1)
            sh_files_checkdir (class_next, rdepth_next, tmpcat, 
                         dirlist->sh_d_name);
          
        }
      }
    
    else if (checkit == SH_FILE_SYMLINK)   ++theDir.NumSymlinks;
    else if (checkit == SH_FILE_FIFO)      ++theDir.NumFifos;
    else if (checkit == SH_FILE_SOCKET)    ++theDir.NumSockets;
    else if (checkit == SH_FILE_CDEV)      ++theDir.NumCDev;
    else if (checkit == SH_FILE_BDEV)      ++theDir.NumBDev;
    
    SH_FREE(tmpcat);
    
    if ((sig_termfast == 1) || (sig_terminate == 1)) 
      {
      SL_RETURN((0), _("sh_files_checkdir"));
      }
    
    dirlist = dirlist->next;
    
  } while (dirlist != NULL);

  if (flag_err_info == SL_TRUE)
    {
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DSUM,
                   theDir.NumDirs,
                   theDir.NumRegular,
                   theDir.NumSymlinks,
                   theDir.NumFifos,
                   theDir.NumSockets,
                   theDir.NumCDev,
                   theDir.NumBDev);
    }

  kill_sh_dirlist (dirlist_orig);

#if !defined(HOST_IS_DARWIN)
  /* 
   * Hardlink check; not done on MacOS X because of resource forks
   */
  if ((sh_check_hardlinks == S_TRUE) && (hardlink_num != theDir.NumDirs)) 
    {
      if (0 != sh_files_hle_test(hardlink_num-theDir.NumDirs, iname))
      {
        tmpcat = SH_ALLOC(strlen(tmpname) + 256);
        sl_snprintf(tmpcat, strlen(tmpname) + 256, 
                  _("%s: subdirectory count (%d) != hardlinks (%d)"),
                  tmpname, theDir.NumDirs, hardlink_num);
        sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
                     MSG_E_SUBGEN, tmpcat, _("sh_files_checkdir"));
        SH_FREE(tmpcat);
      }
    }
#endif

  SH_FREE(tmpname);

  SL_RETURN((0), _("sh_files_checkdir"));
}

int get_the_fd (SL_TICKET ticket);


static ShFileType sh_files_filecheck (int class, char * dirName, 
                              char * fileName,
                              int * reported, 
                              int rsrcflag)
{
  /* 28 Aug 2001 allow NULL fileName
   */
  char            fullpath[PATH_MAX];
  char            fileHash[KEY_LEN + 1];
  int             status;
  file_type       theFile;
  char          * tmpdir;
  char          * tmpname;
  struct utimbuf  utime_buf;

  SL_ENTER(_("sh_files_filecheck"));

  BREAKEXIT(sh_derr);
  if (0 == (rand() % 2))
    (void) sh_derr();

  /* fileName may be NULL if this is a directory
   */
  if (dirName == NULL /* || fileName == NULL */)
    {
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NULL);
      SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
    }

  if ((fileName != NULL) && (class != SH_LEVEL_ALLIGNORE) && 
      (0 != sh_util_obscurename (ShDFLevel[SH_ERR_T_NAME], 
                         fileName, S_FALSE))) 
    {
      if ((dirName != NULL) && (dirName[0] == '/') && (dirName[1] == '\0')) 
      {
        tmpname = sh_util_safe_name (fileName);
        sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, 0,
                     MSG_FI_OBSC2,
                     "", tmpname);
        SH_FREE(tmpname);
      }
      else
      {
        tmpdir  = sh_util_safe_name (dirName);
        tmpname = sh_util_safe_name (fileName);
        sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, 0,
                     MSG_FI_OBSC2,
                     tmpdir, tmpname);
        SH_FREE(tmpname);
        SH_FREE(tmpdir);
      }
    }    

  /* sh_files_fullpath accepts NULL fileName
   */
  if (0 != sh_files_fullpath (dirName, fileName, fullpath)) 
    { 
      tmpdir  = sh_util_safe_name (dirName);
      tmpname = sh_util_safe_name (fileName);
      sh_error_handle (ShDFLevel[SH_ERR_T_FILE],  FIL__, __LINE__, 0,
                   MSG_FI_2LONG2,
                   tmpdir, tmpname);
      SH_FREE(tmpname);
      SH_FREE(tmpdir);
      SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
    } 


  /* stat the file and determine checksum (if a regular file)
   */
  sl_strlcpy (theFile.fullpath, fullpath, PATH_MAX);
  theFile.check_mask = sh_files_maskof(class);
  theFile.reported   = (*reported);

  TPT(( 0, FIL__, __LINE__, _("msg=<checking file: %s>\n"),  fullpath));

  status = sh_unix_getinfo ( (class == SH_LEVEL_ALLIGNORE) ? 
                       ShDFLevel[class] : ShDFLevel[SH_ERR_T_FILE], 
                       fileName,
                       &theFile, fileHash, class);
  
  if (status != 0)
    {
      TPT(( 0, FIL__, __LINE__, _("msg=<file: %s> status=<%d>\n"), 
          fullpath, status));
      if (class == SH_LEVEL_ALLIGNORE && sh.flag.checkSum != SH_CHECK_INIT)
        sh_hash_set_visited_true (fullpath);
      SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
    }
  
  if (sig_termfast == 1) {
    goto ret_point;
  }

  /* report
   */
  if ((flag_err_debug == SL_TRUE) && (theFile.c_mode[0] == '-'))
    {
      tmpname = sh_util_safe_name (fullpath); /* fixed in 1.5.4 */
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_CSUM,
                   fileHash, tmpname);
      SH_FREE(tmpname);
    } 
  ++sh.statistics.files_checked;
      
  if      ( sh.flag.checkSum == SH_CHECK_INIT && sh.flag.update == S_FALSE ) 
    {
      sh_hash_pushdata (&theFile, fileHash);
    }
  else if (sh.flag.checkSum == SH_CHECK_INIT && sh.flag.update == S_TRUE )
    {
      if (0 == sh_hash_compdata (class, &theFile, fileHash, NULL, -1))
      {
        sh_hash_pushdata (&theFile, fileHash);
      }
    }
  else if (sh.flag.checkSum == SH_CHECK_CHECK 
         /* && theFile.c_mode[0] == '-' */
         /* && class != SH_LEVEL_ALLIGNORE */
         ) 
    {
      sh_hash_compdata (class, &theFile, fileHash, NULL, -1);
    }
  
  (*reported) = theFile.reported;

  /* reset the access time 
   */
  if (class == SH_LEVEL_NOIGNORE && (theFile.check_mask & MODI_ATM) != 0)
    {
      utime_buf.actime   = (time_t) theFile.atime;
      utime_buf.modtime  = (time_t) theFile.mtime;
#if !defined(O_NOATIME)
      retry_aud_utime (FIL__, __LINE__, fullpath, &utime_buf);
#endif
    }
  
#ifdef HOST_IS_DARWIN
  /*
   * Check for resource fork
   */
  if ( (theFile.c_mode[0] != 'd') && (rsrcflag == 0) )
    {
      int  dummy;
      static int rsrc_init = 0;
      static char rsrc[17];
      char testpath[PATH_MAX];

      if (rsrc_init == 0) {
      sl_strlcpy(rsrc, _("..namedfork/rsrc"), 17);
      rsrc_init = 1;
      }
      sl_strlcpy (testpath, fullpath, PATH_MAX);
      sl_strlcat (testpath,      "/", PATH_MAX);
      sl_strlcat (testpath,     rsrc, PATH_MAX);

      if (sl_strlen(testpath) == (17 + sl_strlen(fullpath)))
      {
        if (0 == sh_unix_file_stat (testpath))
          {
            sh_files_filecheck (class, fullpath, rsrc, &dummy, 1);
          }
      }
    }
#else
      (void) rsrcflag; /* avoid compiler warning */
#endif

 ret_point:

  switch (theFile.c_mode[0]) 
    {
    case '-': SL_RETURN(SH_FILE_REGULAR, _("sh_files_filecheck"));   
    case 'l': SL_RETURN(SH_FILE_SYMLINK, _("sh_files_filecheck"));   
    case 'd': SL_RETURN(SH_FILE_DIRECTORY, _("sh_files_filecheck")); 
    case 'c': SL_RETURN(SH_FILE_CDEV, _("sh_files_filecheck"));      
    case 'b': SL_RETURN(SH_FILE_BDEV, _("sh_files_filecheck"));      
    case '|': SL_RETURN(SH_FILE_FIFO, _("sh_files_filecheck"));      
    case 's': SL_RETURN(SH_FILE_SOCKET, _("sh_files_filecheck"));    
    default:  SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));   
    }
  
  /* notreached */
}

/* concatenate statpath = testdir"/"d_name
 */
static int sh_files_fullpath (char * testdir, char * d_name, char * statpath)
{
  int llen = 0;

  SL_ENTER(_("sh_files_fullpath"));

  if (testdir != NULL) 
    {
      if ( (llen = sl_strlen(testdir)) > (PATH_MAX-2) ) 
      SL_RETURN((-1),_("sh_files_fullpath"));
      sl_strlcpy(statpath, testdir,    PATH_MAX - 1);
    }
  if (d_name != NULL) 
    {
      if (llen > 1 || statpath[0] != '/')
      sl_strlcat(statpath, "/",   PATH_MAX);
      if ((sl_strlen(d_name) + sl_strlen(statpath)) >= PATH_MAX)
      SL_RETURN((-1),_("sh_files_fullpath"));
      sl_strlcat(statpath, d_name,   PATH_MAX);
    }
  if (statpath == NULL) 
    SL_RETURN((-1),_("sh_files_fullpath"));
  SL_RETURN((0),_("sh_files_fullpath"));
}


/* -----------------------------------
 * 
 *  The following two routines serve to
 *  verify that the user has selected
 *  a proper setup for file policies.
 *
 * -----------------------------------
 */
static int check_file(char * name)
{
  dirstack_t * pfilL = fileList;

  SL_ENTER(_("check_file"));

  if (SH_FILE_DIRECTORY == sh_unix_get_ftype(name))
    SL_RETURN(0, _("check_file"));

  while (pfilL)
    {
      if (0 == strcmp(name, pfilL->name) &&
        (pfilL->check_mask & MODI_ATM) == 0 &&
        (pfilL->check_mask & MODI_CTM) == 0 &&
        (pfilL->check_mask & MODI_MTM) == 0)
      SL_RETURN(0, _("check_file"));
      pfilL = pfilL->next;
    }
  SL_RETURN((-1), _("check_file"));
}
  
int sh_files_test_setup_int (dirstack_t * pdirL)
{
  int dlen, flen;

  /* dirstack_t * pdirL = dirList; */ 
  dirstack_t * pfilL = fileList;

  SL_ENTER(_("sh_files_test_setup"));

  while (pdirL)
    {
      dlen = strlen(pdirL->name);
      pfilL = fileList;
      while (pfilL)
      {
        flen = strlen(pfilL->name);

        /* check whether file is in tree of dir
         */
        if ((pfilL->class == SH_LEVEL_READONLY) ||
            (pfilL->class == SH_LEVEL_NOIGNORE))
          {
            ;  /* do nothing */
          }
        else
          {
            if ((flen > (dlen+1)) && 
              (pfilL->name[dlen] == '/') &&
                  (NULL == strchr(&(pfilL->name[dlen+1]), '/')) && /*30-5-01*/
              (0 == strncmp(pfilL->name, pdirL->name, dlen)))
            {
              if ((pdirL->check_mask & MODI_ATM) != 0  ||
                  (pdirL->check_mask & MODI_MTM) != 0  ||
                  (pdirL->check_mask & MODI_CTM) != 0)
                {
                  if (check_file (pdirL->name) != 0)
                  sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_COLL,
                               pdirL->name, pfilL->name);
                }
            }
          }
        
        pfilL = pfilL->next;
      }

      pdirL = pdirL->next;
    }

  SL_RETURN((0), _("sh_files_test_setup"));
}
      
int sh_files_test_double (dirstack_t * firstList, dirstack_t * secondList)
{
  int          count;
  int          retval = 0;

  dirstack_t * saveList = firstList;
  dirstack_t * tempList;

  while (firstList)
    {
      tempList = saveList;
      count    = 0;

      while (tempList)
      {
        if (0 == sl_strcmp(firstList->name, tempList->name))
          {
            ++count;
          }
        tempList = tempList->next;
      }
      tempList = secondList;
      while (tempList)
      {
        if (0 == sl_strcmp(firstList->name, tempList->name))
          {
            ++count;
          }
        tempList = tempList->next;
      }
      if (count > 1) 
      {
        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
                     firstList->name);
        retval = 1;
      }
      firstList = firstList->next;
    }
  return retval;
}

extern void     aud_exit   (char * file, int line, int fd);
      
int sh_files_test_setup ()
{
  int retval = 0;

  /* Test for modifications allowed in ReadOnly directory
   */  
  sh_files_test_setup_int (dirListOne);
  sh_files_test_setup_int (dirListTwo);

  /* Test for files/dirz defined twice
   */  
  retval = sh_files_test_double (dirListOne, dirListTwo);
  if (retval != 0)
    aud_exit(FIL__, __LINE__, EXIT_FAILURE);

  retval = sh_files_test_double (dirListTwo, dirListOne);
  if (retval != 0)
    aud_exit(FIL__, __LINE__, EXIT_FAILURE);

  retval = sh_files_test_double (fileList,   NULL);
  if (retval != 0)
    aud_exit(FIL__, __LINE__, EXIT_FAILURE);
  return 0;
}

#endif

Generated by  Doxygen 1.6.0   Back to index