/* 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 #include #include #include #include /* Must be before on FreeBSD */ #include #include #include #ifdef HAVE_DIRENT_H #include #define NAMLEN(dirent) sl_strlen((dirent)->d_name) #else #define dirent direct #define NAMLEN(dirent) (dirent)->d_namlen #ifdef HAVE_SYS_NDIR_H #include #endif #ifdef HAVE_SYS_DIR_H #include #endif #ifdef HAVE_NDIR_H #include #endif #endif #ifdef HAVE_GLOB_H #include #endif #include "samhain.h" #if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)) #include "sh_pthread.h" #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" #include "zAVLTree.h" #undef FIL__ #define FIL__ _("sh_files.c") extern int flag_err_debug; extern int flag_err_info; int sh_files_reportonce(const 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(const 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 NumDoor; long NumPort; 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 is_reported; /* struct dirstack_entry * next; */ } dirstack_t; /* the destructor */ void free_dirstack (void * inptr) { dirstack_t * here; SL_ENTER(_("free_dirstack")); if (inptr == NULL) SL_RET0(_("free_dirstack")); else here = (dirstack_t *) inptr; if (here->name != NULL) SH_FREE(here->name); SH_FREE(here); SL_RET0(_("free_dirstack")); } /* Function to return the key for indexing * the argument */ zAVLKey zdirstack_key (void const * arg) { const dirstack_t * sa = (const dirstack_t *) arg; return (zAVLKey) sa->name; } static zAVLTree * zdirListOne = NULL; static zAVLTree * zdirListTwo = NULL; static zAVLTree * zfileList = NULL; static int sh_files_fullpath (char * testdir, char * d_name, char * statpath); static int sh_files_pushdir (int class, const char * str_s); static int sh_files_pushfile (int class, const 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 (const 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 () { zAVLCursor cursor; ShFileType status; unsigned long fcount = 0; char * tmp = NULL; dirstack_t * ptr; char * dir; char * file; int tmp_reported; SL_ENTER(_("sh_files_chk")); for (ptr = (dirstack_t *) zAVLFirst(&cursor, zfileList); ptr; ptr = (dirstack_t *) zAVLNext(&cursor)) { if (sig_urgent > 0) { SL_RETURN(fcount, _("sh_files_chk")); } if (ptr->checked == S_FALSE) { dir = sh_util_dirname (ptr->name); file = sh_util_basename (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); tmp_reported = ptr->is_reported; /* fix aliasing warning */ status = sh_files_filecheck (ptr->class, dir, file, &tmp_reported, 0); ptr->is_reported = tmp_reported; TPT(( 0, FIL__, __LINE__, _("msg= status=<%d> reported=<%d>\n"), tmp, status, ptr->is_reported)); if (status == SH_FILE_UNKNOWN && (!SH_FFLAG_REPORTED_SET(ptr->is_reported))) { TPT(( 0, FIL__, __LINE__, _("msg= 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) SET_SH_FFLAG_REPORTED(ptr->is_reported); } else { /* exists (status >= 0), but was missing (reported == TRUE) */ if (status != SH_FILE_UNKNOWN && SH_FFLAG_REPORTED_SET(ptr->is_reported)) { CLEAR_SH_FFLAG_REPORTED(ptr->is_reported); } /* 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; } if (file) SH_FREE(file); if (dir) SH_FREE(dir); ptr->checked = S_TRUE; } } SL_RETURN(fcount, _("sh_files_chk")); } int sh_files_delfilestack () { SL_ENTER(_("sh_files_delfilestack")); zAVLFreeTree (zfileList, free_dirstack); zfileList = NULL; SL_RETURN(0, _("sh_files_delfilestack")); } int sh_files_setrec_int (zAVLTree * tree) { dirstack_t * ptr; zAVLCursor avlcursor; SL_ENTER(_("sh_files_setrec")); if (tree != NULL) { for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr; ptr = (dirstack_t *) zAVLNext(&avlcursor)) { 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); } } SL_RETURN(0, _("sh_files_setrec")); } int sh_files_setrec () { sh_files_setrec_int(zdirListOne); return sh_files_setrec_int(zdirListTwo); } zAVLTree * sh_files_deldirstack_int (zAVLTree * ptr) { SL_ENTER(_("sh_files_deldirstack")); zAVLFreeTree (ptr, free_dirstack); SL_RETURN(NULL, _("sh_files_deldirstack")); } int sh_files_deldirstack () { zdirListOne = sh_files_deldirstack_int(zdirListOne); zdirListTwo = sh_files_deldirstack_int(zdirListTwo); return 0; } void sh_files_reset() { dirstack_t * ptr; zAVLCursor avlcursor; SL_ENTER(_("sh_files_reset")); for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, zfileList); ptr; ptr = (dirstack_t *) zAVLNext(&avlcursor)) ptr->checked = 0; SL_RET0(_("sh_files_reset")); } void sh_dirs_reset() { dirstack_t * ptr; zAVLCursor avlcursor1; zAVLCursor avlcursor2; SL_ENTER(_("sh_dirs_reset")); for (ptr = (dirstack_t *) zAVLFirst(&avlcursor1, zdirListOne); ptr; ptr = (dirstack_t *) zAVLNext(&avlcursor1)) ptr->checked = 0; for (ptr = (dirstack_t *) zAVLFirst(&avlcursor2, zdirListTwo); ptr; ptr = (dirstack_t *) zAVLNext(&avlcursor2)) ptr->checked = 0; SL_RET0(_("sh_dirs_reset")); } int sh_files_pushfile_prelink (const char * str_s) { return (sh_files_pushfile (SH_LEVEL_PRELINK, str_s)); } int sh_files_pushfile_user0 (const char * str_s) { return (sh_files_pushfile (SH_LEVEL_USER0, str_s)); } int sh_files_pushfile_user1 (const char * str_s) { return (sh_files_pushfile (SH_LEVEL_USER1, str_s)); } int sh_files_pushfile_user2 (const char * str_s) { return (sh_files_pushfile (SH_LEVEL_USER2, str_s)); } int sh_files_pushfile_user3 (const char * str_s) { return (sh_files_pushfile (SH_LEVEL_USER3, str_s)); } int sh_files_pushfile_user4 (const char * str_s) { return (sh_files_pushfile (SH_LEVEL_USER4, str_s)); } int sh_files_pushfile_ro (const char * str_s) { return (sh_files_pushfile (SH_LEVEL_READONLY, str_s)); } int sh_files_pushfile_attr (const char * str_s) { return (sh_files_pushfile (SH_LEVEL_ATTRIBUTES, str_s)); } int sh_files_pushfile_log (const char * str_s) { return (sh_files_pushfile (SH_LEVEL_LOGFILES, str_s)); } int sh_files_pushfile_glog (const char * str_s) { return (sh_files_pushfile (SH_LEVEL_LOGGROW, str_s)); } int sh_files_pushfile_noig (const char * str_s) { return (sh_files_pushfile (SH_LEVEL_NOIGNORE, str_s)); } int sh_files_pushfile_allig (const 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, const 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); /* size may grow */ if (0 == strncmp(myword, _("GROW"), 3)) sh_files_set_mask (mask, MODI_SGROW, act); /* use prelink */ if (0 == strncmp(myword, _("PRE"), 3)) sh_files_set_mask (mask, MODI_PREL, act); } } SL_RETURN ( (0), _("sh_files_parse_mask")); } int sh_files_redef_prelink(const char * str) { return (sh_files_parse_mask(&mask_PRELINK, str)); } int sh_files_redef_user0(const char * str) { return (sh_files_parse_mask(&mask_USER0, str)); } int sh_files_redef_user1(const char * str) { return (sh_files_parse_mask(&mask_USER1, str)); } int sh_files_redef_user2(const char * str) { return (sh_files_parse_mask(&mask_USER2, str)); } int sh_files_redef_user3(const char * str) { return (sh_files_parse_mask(&mask_USER3, str)); } int sh_files_redef_user4(const char * str) { return (sh_files_parse_mask(&mask_USER4, str)); } int sh_files_redef_readonly(const char * str) { return (sh_files_parse_mask(&mask_READONLY, str)); } int sh_files_redef_loggrow(const char * str) { return (sh_files_parse_mask(&mask_LOGGROW, str)); } int sh_files_redef_logfiles(const char * str) { return (sh_files_parse_mask(&mask_LOGFILES, str)); } int sh_files_redef_attributes(const char * str) { return (sh_files_parse_mask(&mask_ATTRIBUTES, str)); } int sh_files_redef_noignore(const char * str) { return (sh_files_parse_mask(&mask_NOIGNORE, str)); } int sh_files_redef_allignore(const 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_USER2: return (unsigned long) mask_USER2; case SH_LEVEL_USER3: return (unsigned long) mask_USER3; case SH_LEVEL_USER4: return (unsigned long) mask_USER4; 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")); if (errnum == ENOTDIR || errnum == ENOENT) { SL_RETURN(0, _("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, size_t len) { dirstack_t * new_item_ptr; char * fileName; int ret; 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->is_reported = 0; new_item_ptr->childs_checked = S_FALSE; if (zfileList == NULL) { zfileList = zAVLAllocTree (zdirstack_key); if (zfileList == NULL) { (void) safe_logger (0, 0, NULL); aud__exit(FIL__, __LINE__, EXIT_FAILURE); } } ret = zAVLInsert (zfileList, new_item_ptr); if (-1 == ret) { (void) safe_logger (0, 0, NULL); aud__exit(FIL__, __LINE__, EXIT_FAILURE); } if (3 == ret) sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE, fileName); SL_RETURN(0, _("sh_files_push_file_int")); } static int sh_files_pushfile (int class, const char * str_s) { size_t len; char * tmp; char * p; #ifdef HAVE_GLOB_H int globstatus = -1; unsigned int gloop; glob_t pglob; #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. */ p = sh_util_strdup (str_s); if (p[len-1] == '/' && len > 1) { p[len-1] = '\0'; --len; } } #ifdef HAVE_GLOB_H if (0 == sh_files_has_metachar(p)) { sh_files_push_file_int (class, p, len); } else { pglob.gl_offs = 0; globstatus = glob (p, 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 (p); 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, p, len); #endif SH_FREE(p); SL_RETURN((0),_("sh_files_pushfile")); } /* ------ directories ----- */ int sh_files_is_allignore_int (char * str, zAVLTree * tree) { dirstack_t * ptr; SL_ENTER(_("sh_files_is_allignore")); if (tree) { ptr = zAVLSearch(tree, str); if (ptr) { if (ptr->class == SH_LEVEL_ALLIGNORE) SL_RETURN( 1, _("sh_files_is_allignore")); else SL_RETURN( 0, _("sh_files_is_allignore")); } } SL_RETURN( 0, _("sh_files_is_allignore")); } int sh_files_is_allignore (char * str) { if (1 == sh_files_is_allignore_int(str, zdirListOne)) return 1; if (NULL == zdirListTwo) return 0; return sh_files_is_allignore_int(str, zdirListTwo); } unsigned long sh_dirs_chk (int which) { zAVLTree * tree; zAVLCursor cursor; dirstack_t * ptr; dirstack_t * dst_ptr; int status; unsigned long dcount = 0; char * tmp; SL_ENTER(_("sh_dirs_chk")); if (which == 1) tree = zdirListOne; else tree = zdirListTwo; for (ptr = (dirstack_t *) zAVLFirst(&cursor, tree); ptr; ptr = (dirstack_t *) zAVLNext(&cursor)) { 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 = zAVLSearch(zfileList, ptr->name); if (dst_ptr) { 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; } else { status = S_TRUE; } } 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 && (!SH_FFLAG_REPORTED_SET(ptr->is_reported))) { /* 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) SET_SH_FFLAG_REPORTED(ptr->is_reported); } else { /* exists (status >= 0), but was missing (reported == TRUE) */ if (status >= 0 && SH_FFLAG_REPORTED_SET(ptr->is_reported)) { CLEAR_SH_FFLAG_REPORTED(ptr->is_reported); #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; ptr->childs_checked = S_TRUE; } if (sig_urgent > 0) { SL_RETURN(dcount, _("sh_dirs_chk")); } } SL_RETURN(dcount, _("sh_dirs_chk")); } int sh_files_pushdir_prelink (const char * str_s) { return (sh_files_pushdir (SH_LEVEL_PRELINK, str_s)); } int sh_files_pushdir_user0 (const char * str_s) { return (sh_files_pushdir (SH_LEVEL_USER0, str_s)); } int sh_files_pushdir_user1 (const char * str_s) { return (sh_files_pushdir (SH_LEVEL_USER1, str_s)); } int sh_files_pushdir_user2 (const char * str_s) { return (sh_files_pushdir (SH_LEVEL_USER2, str_s)); } int sh_files_pushdir_user3 (const char * str_s) { return (sh_files_pushdir (SH_LEVEL_USER3, str_s)); } int sh_files_pushdir_user4 (const char * str_s) { return (sh_files_pushdir (SH_LEVEL_USER4, str_s)); } int sh_files_pushdir_attr (const char * str_s) { return (sh_files_pushdir (SH_LEVEL_ATTRIBUTES, str_s)); } int sh_files_pushdir_ro (const char * str_s) { return (sh_files_pushdir (SH_LEVEL_READONLY, str_s)); } int sh_files_pushdir_log (const char * str_s) { return (sh_files_pushdir (SH_LEVEL_LOGFILES, str_s)); } int sh_files_pushdir_glog (const char * str_s) { return (sh_files_pushdir (SH_LEVEL_LOGGROW, str_s)); } int sh_files_pushdir_noig (const char * str_s) { return (sh_files_pushdir (SH_LEVEL_NOIGNORE, str_s)); } int sh_files_pushdir_allig (const 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, size_t len, int rdepth) { zAVLTree * tree; dirstack_t * new_item_ptr; char * dirName; int ret; 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->is_reported = 0; new_item_ptr->childs_checked = S_FALSE; if (which_dirList == 1) { tree = zdirListOne; } else { tree = zdirListTwo; } if (tree == NULL) { tree = zAVLAllocTree (zdirstack_key); if (tree == NULL) { (void) safe_logger (0, 0, NULL); aud__exit(FIL__, __LINE__, EXIT_FAILURE); } if (which_dirList == 1) zdirListOne = tree; else zdirListTwo = tree; } ret = zAVLInsert (tree, new_item_ptr); if (-1 == ret) { (void) safe_logger (0, 0, NULL); aud__exit(FIL__, __LINE__, EXIT_FAILURE); } if (3 == ret) sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE, dirName); SL_RETURN(0, _("sh_files_push_dir_int")); } static int sh_files_pushdir (int class, const char * str_s) { char * tmp; size_t len; int rdepth = 0; char * tail = NULL; char * p; #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")); p = sh_util_strdup (str_s); if (p[0] != '/') { rdepth = strtol(p, &tail, 10); if (tail == p) { SH_FREE(p); SL_RETURN((-1), _("sh_files_pushdir")); } } else tail = p; if (rdepth < (-1) || tail == p || 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); SH_FREE(p); SL_RETURN((-1), _("sh_files_pushdir")); } else if (len < 1) { SH_FREE(p); 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); SH_FREE(p); 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 SH_FREE(p); SL_RETURN((0), _("sh_files_pushdir")); } /** struct sh_dirent { char * sh_d_name; struct sh_dirent * next; }; **/ 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 */ struct sh_dirent * addto_sh_dirlist (struct dirent * thisEntry, struct sh_dirent * dirlist) { struct sh_dirent * this; size_t len; if (thisEntry == NULL) return dirlist; len = sl_strlen(thisEntry->d_name); if (len == 0) return dirlist; ++len; this = SH_ALLOC(sizeof(struct sh_dirent)); if (!this) return dirlist; this->sh_d_name = SH_ALLOC(len); sl_strlcpy(this->sh_d_name, thisEntry->d_name, len); 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 (const 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 (const 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; static unsigned int state = 1; 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; dirstack_t * tmp_ptr; int hardlink_num = 0; #if !defined(HOST_IS_DARWIN) size_t len; #endif 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); } if (flag_err_info == SL_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); theFile.attr_string = NULL; (void) relativeName; status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_DIR], iname, &theFile, NULL, iclass); if ((sig_termfast == 1) || (sig_terminate == 1)) { if (theFile.attr_string) SH_FREE(theFile.attr_string); SL_RETURN((0), _("sh_files_checkdir")); } if (status == -1) { SH_FREE(tmpname); if (theFile.attr_string) SH_FREE(theFile.attr_string); 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); if (theFile.attr_string) SH_FREE(theFile.attr_string); 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); if (theFile.attr_string) SH_FREE(theFile.attr_string); 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.NumDoor = 0; theDir.NumPort = 0; theDir.NumAll = 0; theDir.TotalBytes = 0; sl_strlcpy (theDir.DirPath, iname, PATH_MAX); /* ---- read ---- */ SH_MUTEX_LOCK(readdir_lock); 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); SH_MUTEX_UNLOCK(readdir_lock); closedir (thisDir); ++sh.statistics.dirs_checked; dirlist_orig = dirlist; do { /* If the directory is empty, dirlist = NULL */ if (!dirlist) break; if (sig_termfast == 1) { if (theFile.attr_string) SH_FREE(theFile.attr_string); SL_RETURN((0), _("sh_files_checkdir")); } BREAKEXIT(sh_derr); #if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_RAND_R) if (0 == (rand_r(&state) % 5)) (void) sh_derr(); #else if (0 == state * (rand() % 5)) (void) sh_derr(); #endif /* ---- 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 = (dirstack_t *) zAVLSearch(zdirListOne, tmpcat); if (dst_ptr) { /* 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; } if (checked_flag == -1) { dst_ptr = (dirstack_t *) zAVLSearch(zdirListTwo, tmpcat); if (dst_ptr) { /* 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; } } dst_ptr = (dirstack_t *) zAVLSearch(zfileList, tmpcat); if (dst_ptr) { /* 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; /* not set, hence always FALSE */ /* cchecked_flag = dst_ptr->childs_checked; */ } /* ---- 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->is_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->is_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; tmp_ptr = (dirstack_t *) zAVLSearch(zdirListOne, tmpcat); if (tmp_ptr) { TPT((0, FIL__, __LINE__, _("msg=<%s -> recursion depth %d\n>"), tmp_ptr->name, tmp_ptr->rdepth)); rdepth_next = tmp_ptr->rdepth; class_next = tmp_ptr->class; /* 28. Aug 2001 reversed */ cchecked_flag = tmp_ptr->childs_checked; checked_flag = tmp_ptr->checked; } if (checked_flag == -1) { tmp_ptr = (dirstack_t *) zAVLSearch(zdirListTwo, tmpcat); if (tmp_ptr) { TPT((0, FIL__, __LINE__, _("msg=<%s -> recursion depth %d\n>"), tmp_ptr->name, tmp_ptr->rdepth)); rdepth_next = tmp_ptr->rdepth; class_next = tmp_ptr->class; /* 28. Aug 2001 reversed */ cchecked_flag = tmp_ptr->childs_checked; checked_flag = tmp_ptr->checked; } } if (cchecked_flag == S_FALSE) { sh_files_checkdir (class_next, rdepth_next, tmpcat, dirlist->sh_d_name); tmp_ptr->childs_checked = S_TRUE; /* * 04. Feb 2006 avoid double checking */ tmp_ptr->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; else if (checkit == SH_FILE_DOOR) ++theDir.NumDoor; else if (checkit == SH_FILE_PORT) ++theDir.NumPort; SH_FREE(tmpcat); if ((sig_termfast == 1) || (sig_terminate == 1)) { if (theFile.attr_string) SH_FREE(theFile.attr_string); SL_RETURN((0), _("sh_files_checkdir")); } dirlist = dirlist->next; if (dst_ptr) dst_ptr->childs_checked = S_TRUE; } 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)) { len = strlen(tmpname); if (sl_ok_adds(len, 256)) len += 256; tmpcat = SH_ALLOC(len); sl_snprintf(tmpcat, len, _("%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 if (theFile.attr_string) SH_FREE(theFile.attr_string); 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 * infileName, int * reported, int rsrcflag) { /* 28 Aug 2001 allow NULL fileName */ char fullpath[PATH_MAX]; char fileHash[2*(KEY_LEN + 1)]; int status; file_type theFile; char * tmpdir; char * tmpname; char * fileName; struct utimbuf utime_buf; static unsigned int state = 1; SL_ENTER(_("sh_files_filecheck")); BREAKEXIT(sh_derr); #if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_RAND_R) if (0 == (rand_r(&state) % 2)) (void) sh_derr(); #else if (0 == state * (rand() % 2)) (void) sh_derr(); #endif if (dirName && infileName && (dirName[0] == '/') && (dirName[1] == '\0') && (infileName[0] == '/') && (infileName[1] == '\0')) { fileName = NULL; } else { fileName = infileName; } /* 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.file_reported = (*reported); theFile.attr_string = NULL; TPT(( 0, FIL__, __LINE__, _("msg=\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= status=<%d>\n"), fullpath, status)); if (class == SH_LEVEL_ALLIGNORE && sh.flag.checkSum != SH_CHECK_INIT) sh_hash_set_visited_true (fullpath); if (theFile.attr_string) SH_FREE(theFile.attr_string); 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_CHECK /* && theFile.c_mode[0] == '-' */ /* && class != SH_LEVEL_ALLIGNORE */ ) { sh_hash_compdata (class, &theFile, fileHash, NULL, -1); } (*reported) = theFile.file_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 (S_TRUE == sh_unix_file_exists (testpath)) { sh_files_filecheck (class, fullpath, rsrc, &dummy, 1); } } } #else (void) rsrcflag; /* avoid compiler warning */ #endif ret_point: if (theFile.attr_string) SH_FREE(theFile.attr_string); 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 'D': SL_RETURN(SH_FILE_DOOR, _("sh_files_filecheck")); case 'P': SL_RETURN(SH_FILE_PORT, _("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; zAVLCursor cursor; SL_ENTER(_("check_file")); if (SH_FILE_DIRECTORY == sh_unix_get_ftype(name)) SL_RETURN(0, _("check_file")); for (pfilL = (dirstack_t *) zAVLFirst (&cursor, zfileList); pfilL; pfilL = (dirstack_t *) zAVLNext (&cursor)) { 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")); } SL_RETURN((-1), _("check_file")); } int sh_files_test_setup_int (zAVLTree * tree) { int dlen, flen; zAVLCursor cursor1; zAVLCursor cursor2; dirstack_t * pdirL; dirstack_t * pfilL; SL_ENTER(_("sh_files_test_setup")); for (pdirL = (dirstack_t *) zAVLFirst (&cursor1, tree); pdirL; pdirL = (dirstack_t *) zAVLNext (&cursor1)) { dlen = strlen(pdirL->name); for (pfilL = (dirstack_t *) zAVLFirst (&cursor2, zfileList); pfilL; pfilL = (dirstack_t *) zAVLNext (&cursor2)) { 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); } } } } } SL_RETURN((0), _("sh_files_test_setup")); } int sh_files_test_double (zAVLTree * firstList, zAVLTree * secondList) { int count; int retval = 0; zAVLCursor cursor; dirstack_t * first; for (first = (dirstack_t *) zAVLFirst (&cursor, firstList); first; first = (dirstack_t *) zAVLNext (&cursor)) { if (NULL != zAVLSearch(secondList, first->name)) { ++count; sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE, first->name); retval = 1; } } 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 (zdirListOne); sh_files_test_setup_int (zdirListTwo); /* Test for files/dirz defined twice */ retval = sh_files_test_double (zdirListOne, zdirListTwo); if (retval != 0) aud_exit(FIL__, __LINE__, EXIT_FAILURE); retval = sh_files_test_double (zdirListTwo, zdirListOne); if (retval != 0) aud_exit(FIL__, __LINE__, EXIT_FAILURE); /* retval = sh_files_test_double (zfileList, NULL); if (retval != 0) aud_exit(FIL__, __LINE__, EXIT_FAILURE); */ return 0; } #endif