/* SAMHAIN file system integrity testing */ /* Copyright (C) 1999, 2000, 2001, 2002 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" /* define this if you want version 1.3 style database file */ /* #define OLD_BUG */ /* make sure state changes of a file are always reported, even * with reportonlyonce=true */ /* #define REPLACE_OLD *//* moved to samhain.h */ #include #include #include #include #include #include #ifdef MAJOR_IN_MKDEV #include #else #ifdef MAJOR_IN_SYSMACROS #include #endif #endif #ifdef HAVE_MEMORY_H #include #endif #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) #include "sh_hash.h" #include "sh_utils.h" #include "sh_error.h" #include "sh_tiger.h" #include "sh_gpg.h" #include "sh_unix.h" #include "sh_files.h" #include "sh_ignore.h" #if defined(SH_WITH_CLIENT) #include "sh_forward.h" #endif #undef FIL__ #define FIL__ _("sh_hash.c") static char * all_items (file_type * theFile, char * fileHash, int is_new); #define QUOTE_CHAR '=' static char * unquote_string (char * str) { int i = 0, j, k = 0, len; char * tmp; SL_ENTER(_("unquote_string")); if (str == NULL) { SL_RETURN(NULL, _("unquote_string")); } len = sl_strlen(str); tmp = SH_ALLOC(len + 1); for (j = 0; j <= len; ++j) { if (str[j] == QUOTE_CHAR && j < (len-2)) { if (sh_util_hexchar(str[j+1]) >= 0 && sh_util_hexchar(str[j+2]) >= 0) { i = 16 * sh_util_hexchar(str[j+1]) + sh_util_hexchar(str[j+2]); tmp[k] = i; j += 2; } else { tmp[k] = str[j]; } } else tmp[k] = str[j]; ++k; } SL_RETURN(tmp, _("unquote_string")); } static char i2h[2]; char * int2hex (unsigned char i) { int j, k; j = i / 16; k = i - (j*16); if (j < 10) i2h[0] = '0'+j; else i2h[0] = 'A'+(j-10); if (k < 10) i2h[1] = '0'+k; else i2h[1] = 'A'+(k-10); return i2h; } static char * quote_string (char * str) { int i = 0, j, k = 0, len; char * tmp; char * tmp2; SL_ENTER(_("quote_string")); if (str == NULL) { SL_RETURN(NULL, _("quote_string")); } len = sl_strlen(str); for (j = 0; j < len; ++j) if (str[j] == '\n' || str[j] == QUOTE_CHAR) ++i; tmp = SH_ALLOC(len + 1 + 3*i); for (j = 0; j <= len; ++j) { if (str[j] == '\n') { tmp2 = int2hex((unsigned char) '\n'); /* was 'n', fixed in 1.5.4 */ tmp[k] = QUOTE_CHAR; ++k; tmp[k] = tmp2[0]; ++k; tmp[k] = tmp2[1]; } else if (str[j] == QUOTE_CHAR) { tmp2 = int2hex((unsigned char) QUOTE_CHAR); tmp[k] = QUOTE_CHAR; ++k; tmp[k] = tmp2[0]; ++k; tmp[k] = tmp2[1]; } else { tmp[k] = str[j]; } ++k; } SL_RETURN(tmp, _("quote_string")); } static UINT32 * swap_32 (UINT32 * iptr) { #ifdef WORDS_BIGENDIAN unsigned char swap; unsigned char * ii = (unsigned char *) iptr; swap = ii[0]; ii[0] = ii[3]; ii[3] = swap; swap = ii[1]; ii[1] = ii[2]; ii[2] = swap; return iptr; #else return iptr; #endif } static UINT64 * swap_64 (UINT64 * iptr) { #ifdef WORDS_BIGENDIAN #ifdef UINT64_IS_32 swap_32 ((UINT32*) iptr); #else unsigned char swap; unsigned char * ii = (unsigned char *) iptr; swap = ii[0]; ii[0] = ii[7]; ii[7] = swap; swap = ii[1]; ii[1] = ii[6]; ii[6] = swap; swap = ii[2]; ii[2] = ii[5]; ii[5] = swap; swap = ii[3]; ii[3] = ii[4]; ii[4] = swap; #endif return iptr; #else return iptr; #endif } static unsigned short * swap_short (unsigned short * iptr) { #ifdef WORDS_BIGENDIAN if (sizeof(short) == 4) swap_32 ((UINT32*) iptr); else { /* alignment problem */ unsigned char swap; static unsigned short ooop; unsigned char * ii; ooop = *iptr; ii = (unsigned char *) &ooop; /* printf("SWAP0: %hd %d\n", *iptr, sizeof(unsigned short)); */ swap = ii[0]; ii[0] = ii[1]; ii[1] = swap; /* printf("SWAP1: %hd\n", (unsigned short) ooop); */ #ifndef OLD_BUG return &ooop; #endif } return iptr; #else return iptr; #endif } /* MAX_PATH_STORE must be >= KEY_LEN */ #define MAX_PATH_STORE 12287 typedef struct store_info { /* char fullpath[MAX_PATH_STORE+2]; char linkpath[MAX_PATH_STORE+2]; */ UINT32 mode; UINT32 linkmode; UINT64 dev; UINT64 rdev; UINT32 hardlinks; UINT32 ino; UINT64 size; UINT64 atime; UINT64 mtime; UINT64 ctime; UINT32 owner; UINT32 group; #ifdef OLD_BUG #if defined(__linux__) UINT32 attributes; char c_attributes[16]; #endif #else /* #if defined(__linux__) */ UINT32 attributes; char c_attributes[16]; /* endif */ #endif unsigned short mark; char c_owner[USER_MAX+2]; char c_group[GROUP_MAX+2]; char c_mode[11]; char checksum[KEY_LEN+1]; } sh_filestore_t; typedef struct file_info { sh_filestore_t theFile; char * fullpath; char * linkpath; int visited; int reported; int allignore; unsigned long modi_mask; struct file_info * next; } sh_file_t; static char *policy[] = { N_("[]"), N_("[ReadOnly]"), N_("[LogFiles]"), N_("[GrowingLogs]"), N_("[IgnoreNone]"), N_("[IgnoreAll]"), N_("[Attributes]"), N_("[User0]"), N_("[User1]"), N_("[Prelink]"), NULL }; /********************************** * * hash table functions * ********************************** */ #include "sh_hash.h" /* must fit an int */ #define TABSIZE 2048 /* must fit an unsigned short */ /* changed for V0.8, as the */ /* database format has changed */ /* changed again for V0.9 */ /* #define REC_MAGIC 19 */ /* changed again for V1.3 */ #ifdef OLD_BUG #define REC_MAGIC 20 #else /* changed again for V1.4 */ #define REC_MAGIC 21 #endif /************************************************************** * * create a file_type from a sh_file_t * **************************************************************/ static file_type * sh_hash_create_ft (const sh_file_t * p, char * fileHash) { file_type * theFile; #if defined(__linux__) int i = 16; #endif SL_ENTER(_("sh_hash_create_ft")); theFile = SH_ALLOC(sizeof(file_type)); sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11); theFile->mode = p->theFile.mode; #if defined(__linux__) sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, i /* 16 */); theFile->attributes = p->theFile.attributes; #endif sl_strlcpy(theFile->fullpath, p->fullpath, PATH_MAX); if (p->linkpath != NULL && theFile->c_mode[0] == 'l') { sl_strlcpy(theFile->linkpath, p->linkpath, PATH_MAX); } else { theFile->linkpath[0] = '-'; theFile->linkpath[1] = '\0'; } sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1); theFile->mtime = p->theFile.mtime; theFile->ctime = p->theFile.ctime; theFile->atime = p->theFile.atime; theFile->size = p->theFile.size; sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2); theFile->group = p->theFile.group; sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2); theFile->owner = p->theFile.owner; theFile->ino = p->theFile.ino; theFile->rdev = p->theFile.rdev; theFile->dev = p->theFile.dev; theFile->hardlinks = p->theFile.hardlinks; SL_RETURN((theFile), _("sh_hash_create_ft")); } static sh_file_t * hashsearch (char * s); static sh_file_t * tab[TABSIZE]; /************************************************************** * * compute hash function * **************************************************************/ static int hashfunc(char *s) { unsigned n = 0; for ( ; *s; s++) n = 31 * n + *s; return n % TABSIZE; } int hashreport_missing( char *fullpath, int level) { sh_file_t * p; char * tmp; char fileHash[KEY_LEN + 1]; file_type * theFile; char * str; /* -------- find the entry for the file ---------------- */ if (sl_strlen(fullpath) <= MAX_PATH_STORE) p = hashsearch(fullpath); else p = hashsearch( sh_tiger_hash(fullpath, TIGER_DATA, sl_strlen(fullpath)) ); if (p == NULL) return -1; theFile = sh_hash_create_ft (p, fileHash); str = all_items(theFile, fileHash, 0); tmp = sh_util_safe_name(fullpath); sh_error_handle (level, FIL__, __LINE__, 0, MSG_FI_MISS2, tmp, str); SH_FREE(tmp); SH_FREE(str); SH_FREE(theFile); return 0; } /************************************************************** * * search for files not visited, and check whether they exist * **************************************************************/ static void hash_unvisited (int j, sh_file_t *prev, sh_file_t *p, ShErrLevel level) { struct stat buf; int i; char * tmp; char * ptr; char fileHash[KEY_LEN + 1]; file_type * theFile; char * str; SL_ENTER(_("hash_unvisited")); if (p->next != NULL) hash_unvisited (j, p, p->next, level); if (p->fullpath == NULL) { SL_RET0(_("hash_unvisited")); } /* Kernel info */ if (p->fullpath[0] == 'K') { SL_RET0(_("hash_unvisited")); } /* visited = FALSE: not seen; * visited = 99: not seen, and already checked * reported = FALSE: not reported yet * allignore = FALSE: not under IgnoreAll * * Files/directories under IgnoreAll are noticed as missing already * during the file check. */ if ((p->visited == S_FALSE || p->visited == 99) && p->reported == S_FALSE && p->allignore == S_FALSE) { i = retry_lstat(FIL__, __LINE__, p->fullpath, &buf); /* if file does not exist */ if (0 != i) { ptr = sh_util_basename (p->fullpath); if (ptr) { /* If any of the parent directories is under IgnoreAll */ if (0 != sh_files_is_allignore(ptr)) level = ShDFLevel[SH_LEVEL_ALLIGNORE]; SH_FREE(ptr); } if (p->visited != 99) { if (S_FALSE == sh_ignore_chk_del(p->fullpath)) { tmp = sh_util_safe_name(p->fullpath); theFile = sh_hash_create_ft (p, fileHash); str = all_items(theFile, fileHash, 0); sh_error_handle (level, FIL__, __LINE__, 0, MSG_FI_MISS2, tmp, str); SH_FREE(str); SH_FREE(theFile); SH_FREE(tmp); } } /* We rewrite the db on update, thus we need to push this out * if the user does not want to purge it from the db. */ if (sh.flag.checkSum == SH_CHECK_INIT && sh.flag.update == S_TRUE && S_FALSE == sh_util_ask_update(p->fullpath)) { theFile = sh_hash_create_ft (p, fileHash); sh_hash_pushdata (theFile, fileHash); SH_FREE(theFile); } if (sh.flag.reportonce == S_TRUE) { #ifdef REPLACE_OLD /* Remove the old entry */ if (prev == p) tab[j] = p->next; else prev->next = p->next; if (p->fullpath) { SH_FREE(p->fullpath); p->fullpath = NULL; } if (p->linkpath) { SH_FREE(p->linkpath); p->linkpath = NULL; } SH_FREE(p); p = NULL; SL_RET0(_("hash_unvisited")); #else p->reported = S_TRUE; #endif } } } else if (p->visited == S_TRUE && p->reported == S_TRUE && p->allignore == S_FALSE) { if (S_FALSE == sh_ignore_chk_new(p->fullpath)) { tmp = sh_util_safe_name(p->fullpath); theFile = sh_hash_create_ft (p, fileHash); str = all_items(theFile, fileHash, 0); sh_error_handle (level, FIL__, __LINE__, 0, MSG_FI_MISS2, tmp, str); SH_FREE(str); SH_FREE(theFile); SH_FREE(tmp); } p->reported = S_FALSE; } if (sh.flag.reportonce == S_FALSE) p->reported = S_FALSE; p->visited = S_FALSE; SL_RET0(_("hash_unvisited")); } /********************************************************************* * * Search for files in the database that have been deleted from disk. * *********************************************************************/ void sh_hash_unvisited (ShErrLevel level) { int i; SL_ENTER(_("sh_hash_unvisited")); for (i = 0; i < TABSIZE; ++i) { if (tab[i] != NULL) hash_unvisited (i, tab[i], tab[i], level); } SL_RET0(_("hash_unvisited")); } /********************************************************************** * * delete hash array * **********************************************************************/ static void hash_kill (sh_file_t *p) { SL_ENTER(_("hash_kill")); if (p == NULL) SL_RET0(_("hash_kill")); if (p->next != NULL) hash_kill (p->next); if (p->fullpath) { SH_FREE(p->fullpath); p->fullpath = NULL; } if (p->linkpath) { SH_FREE(p->linkpath); p->linkpath = NULL; } SH_FREE(p); p = NULL; SL_RET0(_("hash_kill")); } /*********************************************************************** * * get info out of hash array * ***********************************************************************/ static sh_file_t * hashsearch (char * s) { sh_file_t * p; SL_ENTER(_("hashsearch")); if (!s) SL_RETURN( NULL, _("hashsearch")); for (p = tab[hashfunc(s)]; p; p = p->next) if ((p->fullpath != NULL) && (0 == strcmp(s, p->fullpath))) SL_RETURN( p, _("hashsearch")); SL_RETURN( NULL, _("hashsearch")); } /*********************************************************************** * * insert into hash array * ***********************************************************************/ static void hashinsert (sh_file_t * s) { sh_file_t * p; sh_file_t * q; int key; SL_ENTER(_("hashinsert")); key = hashfunc(s->fullpath); if (tab[key] == NULL) { tab[key] = s; tab[key]->next = NULL; SL_RET0(_("hashinsert")); } else { p = tab[key]; while (1) { if (p && p->fullpath && 0 == strcmp(s->fullpath, p->fullpath) && strlen(s->fullpath) == strlen(p->fullpath)) { q = p->next; SH_FREE(p->fullpath); if(p->linkpath) SH_FREE(p->linkpath); memcpy(p, s, sizeof(sh_file_t)); p->next = q; SH_FREE(s); s = NULL; SL_RET0(_("hashinsert")); } else if (p->next == NULL) { p->next = s; p->next->next = NULL; SL_RET0(_("hashinsert")); } p = p->next; } } /* notreached */ } /****************************************************************** * * Get a single line * ******************************************************************/ static FILE * sh_fin_fd = NULL; static int sh_hash_getline (FILE * fd, char * line, int sizeofline) { register int n = 0; char * res; if (sizeofline < 2) { line[0] = '\0'; return 0; } res = fgets(line, sizeofline, fd); if (res == NULL) { line[0] = '\0'; return -1; } n = strlen(line); if (n > 1) { --n; line[n] = '\0'; } return n; } static void sh_hash_getline_end () { fclose (sh_fin_fd); sh_fin_fd = NULL; return; } /****************************************************************** * * ------- Check functions ------- * ******************************************************************/ static int IsInit = 0; /****************************************************************** * * Fast forward to start of data * ******************************************************************/ int sh_hash_setdataent (SL_TICKET fd, char * line, int size, char * file) { long i; extern int get_the_fd (SL_TICKET ticket); SL_ENTER(_("sh_hash_setdataent")); sl_rewind (fd); if (sh_fin_fd != NULL) { fclose (sh_fin_fd); sh_fin_fd = NULL; } sh_fin_fd = fdopen(get_the_fd(fd), "rb"); if (!sh_fin_fd) { dlog(1, FIL__, __LINE__, _("The file signature database: %s is not readable.\n"), (NULL == file) ? _("(null)") : file); sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA, ( (NULL == file) ? _("(null)") : file) ); aud_exit (FIL__, __LINE__, EXIT_FAILURE); } while (1) { i = sh_hash_getline (sh_fin_fd, line, size-1); if (i < 0 ) { SH_FREE(line); dlog(1, FIL__, __LINE__, _("The file signature database: %s does not\ncontain any data, or the start-of-file marker is missing (unlikely,\nunless modified by hand).\n"), (NULL == file) ? _("(null)") : file); sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA, ( (NULL == file) ? _("(null)") : file) ); aud_exit (FIL__, __LINE__, EXIT_FAILURE); } #if defined(SH_STEALTH) if (0 == sl_strncmp (line, N_("[SOF]"), 5)) #else if (0 == sl_strncmp (line, _("[SOF]"), 5)) #endif break; } SL_RETURN( 1, _("sh_hash_setdataent")); } static int sh_hash_setdataent_old (SL_TICKET fd, char * line, int size, char * file) { long i; SL_ENTER(_("sh_hash_setdataent_old")); sl_rewind (fd); while (1) { i = sh_unix_getline (fd, line, size-1); if (i < 0 ) { SH_FREE(line); dlog(1, FIL__, __LINE__, _("The file signature database: %s does not\ncontain any data, or the start-of-file marker is missing (unlikely,\nunless modified by hand).\n"), (NULL == file) ? _("(null)") : file); sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA, ( (NULL == file) ? _("(null)") : file) ); aud_exit (FIL__, __LINE__, EXIT_FAILURE); } #if defined(SH_STEALTH) if (0 == sl_strncmp (line, N_("[SOF]"), 5)) #else if (0 == sl_strncmp (line, _("[SOF]"), 5)) #endif break; } SL_RETURN( 1, _("sh_hash_setdataent_old")); } /****************************************************************** * * Read next record * ******************************************************************/ sh_file_t * sh_hash_getdataent (SL_TICKET fd, char * line, int size) { sh_file_t * p; sh_filestore_t ft; long i; char * fullpath; char * linkpath; char * tmp; SL_ENTER(_("sh_hash_getdataent")); (void) fd; /* Read next record -- Part One */ p = SH_ALLOC(sizeof(sh_file_t)); i = fread (&ft, sizeof(sh_filestore_t), 1, sh_fin_fd); /* i = sl_read(fd, &ft, sizeof(sh_filestore_t)); */ /* if ( SL_ISERROR(i) || i == 0) */ if (i < 1) { SH_FREE(p); SL_RETURN( NULL, _("sh_hash_getdataent")); } swap_32(&(ft.mode)); swap_32(&(ft.linkmode)); swap_64(&(ft.dev)); swap_64(&(ft.rdev)); swap_32(&(ft.hardlinks)); swap_32(&(ft.ino)); swap_64(&(ft.size)); swap_64(&(ft.atime)); swap_64(&(ft.mtime)); swap_64(&(ft.ctime)); swap_32(&(ft.owner)); swap_32(&(ft.group)); #if defined(__linux__) swap_32(&(ft.attributes)); #endif #ifdef OLD_BUG swap_short(&(ft.mark)); #else ft.mark = *(swap_short(&(ft.mark))); #endif if (ft.mark != REC_MAGIC) { SH_FREE(p); SL_RETURN( NULL, _("sh_hash_getdataent")); } /* Read next record -- Part Two -- Fullpath */ i = sh_hash_getline (sh_fin_fd, line, size-1); if (i < 0 ) { SH_FREE(line); SH_FREE(p); dlog(1, FIL__, __LINE__, _("There is a corrupt record in the file signature database: %s\nThe file path is missing.\n"), (NULL == file_path('D', 'R'))? _("(null)"):file_path('D', 'R')); sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA, ( (NULL == file_path('D', 'R')) ? _("(null)") : file_path('D', 'R')) ); aud_exit (FIL__, __LINE__,EXIT_FAILURE); } tmp = unquote_string (line); i = sl_strlen(tmp)+1; fullpath = SH_ALLOC(i); sl_strlcpy (fullpath, tmp, i); if (tmp) SH_FREE(tmp); if (fullpath[i-2] == '\n') fullpath[i-2] = '\0'; /* Read next record -- Part Three -- Linkpath */ i = sh_hash_getline (sh_fin_fd, line, size-1); if (i < 0 ) { SH_FREE(line); SH_FREE(fullpath); SH_FREE(p); dlog(1, FIL__, __LINE__, _("There is a corrupt record in the file signature database: %s\nThe link path (or its placeholder) is missing.\n"), (NULL == file_path('D', 'R'))? _("(null)"):file_path('D', 'R')); sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA, ( (NULL == file_path('D', 'R')) ? _("(null)") : file_path('D', 'R')) ); aud_exit (FIL__, __LINE__,EXIT_FAILURE); } tmp = unquote_string (line); i = sl_strlen(tmp)+1; linkpath = SH_ALLOC(i); sl_strlcpy (linkpath, tmp, i); if (tmp) SH_FREE(tmp); if (linkpath[i-2] == '\n') linkpath[i-2] = '\0'; /* Read next record -- Part Four -- Decode */ #if defined(SH_STEALTH) sh_do_decode(fullpath, sl_strlen(fullpath)); #if defined(__linux__) sh_do_decode(ft.c_attributes, sl_strlen(ft.c_attributes)); #endif sh_do_decode(ft.c_mode, sl_strlen(ft.c_mode)); sh_do_decode(ft.c_owner, sl_strlen(ft.c_owner)); sh_do_decode(ft.c_group, sl_strlen(ft.c_group)); sh_do_decode(ft.checksum, sl_strlen(ft.checksum)); if (ft.c_mode[0] == 'l') { sh_do_decode(linkpath, sl_strlen(linkpath)); } #endif memcpy( &(*p).theFile, &ft, sizeof(sh_filestore_t) ); p->visited = S_FALSE; p->reported = S_FALSE; p->allignore = S_FALSE; p->modi_mask = 0L; p->fullpath = fullpath; p->linkpath = linkpath; /* set to an invalid value */ ft.mark = (REC_MAGIC + 5); SL_RETURN( p, _("sh_hash_getdataent")); } /****************************************************************** * * Initialize * ******************************************************************/ void sh_hash_init () { sh_file_t * p; SL_TICKET fd = (-1); long i; int count = 0; char * line = NULL; #if defined(WITH_GPG) || defined(WITH_PGP) extern int get_the_fd (SL_TICKET ticket); FILE * fin_cp; char * buf = NULL; int bufc; int flag_pgp = S_FALSE; int flag_nohead = S_FALSE; SL_TICKET fdTmp = (-1); SL_TICKET open_tmp (void); #endif SL_ENTER(_("sh_hash_init")); if (IsInit == 1) SL_RET0(_("sh_hash_init")); for (i = 0; i < TABSIZE; ++i) tab[i] = NULL; #if defined(SH_WITH_CLIENT) /* Data file from Server */ if (fd == (-1) && 0 == sl_strcmp(file_path('D', 'R'), _("REQ_FROM_SERVER"))) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_D_DSTART); fd = sh_forward_req_file(_("DATA")); if (SL_ISERROR(fd)) { dlog(1, FIL__, __LINE__, _("Could not retrieve the file signature database from the server(errnum = %ld).\nPossible reasons include:\n - the server is not running,\n - session key negotiation failed (see the manual for proper setup), or\n - the server cannot access the file.\n"), fd); sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_EXIT_ABORT1, sh.prg_name); aud_exit (FIL__, __LINE__, EXIT_FAILURE); } sl_rewind (fd); tiger_fd = fd; sl_strlcpy (sh.data.hash, sh_tiger_hash (file_path('C', 'R'), /*irrelevant, TIGER_FD*/ TIGER_FD, 0), KEY_LEN+1); sl_rewind (fd); } else #endif /* Local data file */ if (fd == (-1)) { if ( SL_ISERROR(fd = sl_open_read(file_path('D', 'R'), SL_YESPRIV))) { TPT(( 0, FIL__, __LINE__, _("msg=\n"), file_path('D', 'R'))); dlog(1, FIL__, __LINE__, _("Could not open the local file signature database for reading because\nof the following error: %s (errnum = %ld)\nIf this is a permission problem, you need to change file permissions\nto make the file readable for the effective UID: %d\n"), sl_get_errmsg(), fd, (int) sl_ret_euid()); sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_EXIT_ABORT1, sh.prg_name); aud_exit (FIL__, __LINE__, EXIT_FAILURE); } TPT(( 0, FIL__, __LINE__, _("msg=\n"), file_path('D', 'R'))); tiger_fd = fd; if (0 != sl_strncmp(sh.data.hash, sh_tiger_hash (file_path('D', 'R'), TIGER_FD, 0), KEY_LEN) && sh.flag.checkSum != SH_CHECK_INIT) { dlog(1, FIL__, __LINE__, _("The checksum of the file signature database has changed since startup.\n")); sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_AUTH, ( (NULL == file_path('D', 'R')) ? _("(null)") : file_path('D', 'R') ) ); aud_exit (FIL__, __LINE__, EXIT_FAILURE); } sl_rewind (fd); } /* new 1.4.8 */ if (sig_termfast == 1) /* SIGTERM */ { TPT((0, FIL__, __LINE__, _("msg=\n"))); --sig_raised; --sig_urgent; aud_exit (FIL__, __LINE__, EXIT_SUCCESS); } #if defined(WITH_GPG) || defined(WITH_PGP) /* new 1.4.8: also checked for server data */ /* extract the data and copy to temporary file */ fdTmp = open_tmp(); fin_cp = fdopen(get_the_fd(fd), "rb"); buf = (char *) SH_ALLOC(8192); /* while ( (bufc = sh_unix_getline (fd, buf, 8191)) > 0) */ while (NULL != fgets(buf, 8192, fin_cp)) { bufc = 0; while (bufc < 8192) { if (buf[bufc] == '\n') { ++bufc; break; } ++bufc; } if (sig_termfast == 1) /* SIGTERM */ { TPT((0, FIL__, __LINE__, _("msg=\n"))); --sig_raised; --sig_urgent; aud_exit (FIL__, __LINE__, EXIT_SUCCESS); } if (flag_pgp == S_FALSE && (0 == sl_strcmp(buf, _("-----BEGIN PGP SIGNED MESSAGE-----\n"))|| 0 == sl_strcmp(buf, _("-----BEGIN PGP MESSAGE-----\n"))) ) { flag_pgp = S_TRUE; sl_write(fdTmp, buf, bufc); continue; } if (flag_pgp == S_TRUE && flag_nohead == S_FALSE) { if (buf[0] == '\n') { flag_nohead = S_TRUE; sl_write(fdTmp, buf, 1); continue; } else if (0 == sl_strncmp(buf, _("Hash:"), 5) || 0 == sl_strncmp(buf, _("NotDashEscaped:"), 15)) { sl_write(fdTmp, buf, bufc); continue; } else continue; } if (flag_pgp == S_TRUE && buf[0] == '\n') { sl_write(fdTmp, buf, 1); } else if (flag_pgp == S_TRUE) { /* sl_write_line(fdTmp, buf, bufc); */ sl_write(fdTmp, buf, bufc); } if (flag_pgp == S_TRUE && 0 == sl_strcmp(buf, _("-----END PGP SIGNATURE-----\n"))) break; } SH_FREE(buf); sl_close(fd); fclose(fin_cp); fd = fdTmp; sl_rewind (fd); /* Validate signature of open file. */ if (0 != sh_gpg_check_sign (0, fd, 2)) { aud_exit (FIL__, __LINE__, EXIT_FAILURE); } sl_rewind (fd); #endif /* } new 1.4.8 check sig also for files downloaded from server */ line = SH_ALLOC(MAX_PATH_STORE+1); /* fast forward to start of data */ sh_hash_setdataent(fd, line, MAX_PATH_STORE, file_path('D', 'R')); while (1) { if (sig_termfast == 1) /* SIGTERM */ { TPT((0, FIL__, __LINE__, _("msg=\n"))); --sig_raised; --sig_urgent; aud_exit (FIL__, __LINE__, EXIT_SUCCESS); } p = sh_hash_getdataent (fd, line, MAX_PATH_STORE); if (p != NULL) { hashinsert (p); ++count; } else break; } if (line != NULL) SH_FREE(line); /* Always keep db in memory, so we have no open file */ sl_close (fd); sh_hash_getline_end(); fd = -1; /* --- Initialization done successfully. --- */ IsInit = 1; SL_RET0(_("sh_hash_init")); } /***************************************************************** * * delete hash array * *****************************************************************/ void sh_hash_hashdelete () { int i; SL_ENTER(_("sh_hash_hashdelete")); if (IsInit == 0) SL_RET0(_("sh_hash_hashdelete")); for (i = 0; i < TABSIZE; ++i) if (tab[i] != NULL) { hash_kill (tab[i]); tab[i] = NULL; } IsInit = 0; SL_RET0(_("sh_hash_hashdelete")); } /****************************************************************** * * Insert a file into the database. * ******************************************************************/ static int pushdata_isfirst = 1; static SL_TICKET pushdata_fd = -1; static int pushdata_stdout = S_FALSE; static char * sh_db_version_string = NULL; int sh_hash_pushdata_stdout (char * str) { if (!str) { pushdata_stdout = S_TRUE; return 0; } return -1; } int sh_hash_version_string(char * str) { int i; if (str) { i = sl_strlen(str); if (sh_db_version_string != NULL) { SH_FREE(sh_db_version_string); } if (0 == sl_strncmp(str, _("NULL"), 4)) { sh_db_version_string = NULL; return 0; } sh_db_version_string = SH_ALLOC(i+1); sl_strlcpy(sh_db_version_string, str, i+1); return 0; } return -1; } #if 0 void sh_hash_pushdata_reset () { if (!SL_ISERROR(pushdata_fd)) { sl_close(pushdata_fd); pushdata_fd = -1; } pushdata_isfirst = 1; } #endif void sh_hash_pushdata (file_type * buf, char * fileHash) { static long p_count = 0; int status = 0; char * tmp; size_t tmp_len = 0; size_t old_len = 0; sh_filestore_t p; struct stat sbuf; char * fullpath = NULL; char * linkpath = NULL; char * line = NULL; char timestring[81]; char * timep; #if !defined(__linux__) int i; #endif SL_ENTER(_("sh_hash_pushdata")); fullpath = SH_ALLOC(MAX_PATH_STORE+1); linkpath = SH_ALLOC(MAX_PATH_STORE+1); linkpath[0] = '-'; linkpath[1] = '\0'; fullpath[0] = '-'; fullpath[1] = '\0'; if (!buf) { memset(&p, '\0', sizeof(sh_filestore_t)); } if ((pushdata_stdout == S_TRUE) && (sh.flag.update == S_TRUE)) { dlog(1, FIL__, __LINE__, _("You cannot write the database to stdout when you use update rather than init.\n")); sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS, _("Writing database to stdout with update"), sh.prg_name, _("sh_hash_pushdata")); aud_exit(FIL__, __LINE__, EXIT_FAILURE); } if ((pushdata_stdout == S_TRUE) && (sl_is_suid())) { dlog(1, FIL__, __LINE__, _("You cannot write the database to stdout when running with suid privileges.\n")); sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS, _("Writing database to stdout when suid"), sh.prg_name, _("sh_hash_pushdata")); aud_exit(FIL__, __LINE__, EXIT_FAILURE); } if ((pushdata_stdout == S_FALSE) && ( (NULL == file_path('D', 'W')) || (0 == sl_strcmp(file_path('D', 'W'), _("REQ_FROM_SERVER"))) )) { dlog(1, FIL__, __LINE__, _("You need to configure a local path for initializing the database\nlike ./configure --with-data-file=REQ_FROM_SERVER/some/local/path\n")); sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS, _("No local path for database specified"), sh.prg_name, _("sh_hash_pushdata")); aud_exit(FIL__, __LINE__, EXIT_FAILURE); } if ((pushdata_stdout == S_FALSE) && (pushdata_isfirst == 1)) { /* Warn that file already exists; file_path != NULL here because * checked above */ if (0 == retry_lstat(FIL__, __LINE__, file_path('D', 'W'), &sbuf)) { if (sh.flag.update == S_FALSE) { sh_error_handle((-1), FIL__, __LINE__, 0, MSG_FI_DBEX, file_path('D', 'W')); } } } if (sh.flag.update == S_FALSE) { if (pushdata_stdout == S_FALSE) { pushdata_fd = -1; if ( SL_ISERROR(pushdata_fd = sl_open_write(file_path('D', 'W'), SL_YESPRIV))) { SH_FREE(fullpath); SH_FREE(linkpath); sh_error_handle((-1), FIL__, __LINE__, pushdata_fd, MSG_E_ACCESS, geteuid(), file_path('D', 'W')); SL_RET0(_("sh_hash_pushdata")); } if ( SL_ISERROR(status = sl_forward(pushdata_fd))) { SH_FREE(fullpath); SH_FREE(linkpath); sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH, _("Fast forward failed"), _("sh_hash_pushdata"), file_path('D', 'W')); SL_RET0(_("sh_hash_pushdata")); } } } else /* update == TRUE */ { if (pushdata_isfirst == 1) { TPT((0, FIL__, __LINE__, _("msg=\n"))) if ( SL_ISERROR(pushdata_fd = sl_open_rdwr(file_path('D', 'W'), SL_YESPRIV))){ SH_FREE(fullpath); SH_FREE(linkpath); sh_error_handle((-1), FIL__, __LINE__, pushdata_fd, MSG_E_ACCESS, geteuid(), file_path('D', 'W')); SL_RET0(_("sh_hash_pushdata")); } line = SH_ALLOC(MAX_PATH_STORE+1); if (SL_ISERROR(sh_hash_setdataent_old (pushdata_fd, line, MAX_PATH_STORE, file_path('D', 'W')))) { SH_FREE(fullpath); SH_FREE(linkpath); SH_FREE(line); SL_RET0(_("sh_hash_pushdata")); } SH_FREE(line); } } if (buf != NULL && buf->fullpath != NULL) { old_len = sl_strlen(buf->fullpath); #if defined(SH_STEALTH) sh_do_encode(buf->fullpath, old_len); #endif tmp = quote_string(buf->fullpath); tmp_len = sl_strlen(tmp); #if defined(SH_STEALTH) sh_do_decode(buf->fullpath, old_len); #endif if (tmp_len <= MAX_PATH_STORE) { sl_strlcpy(fullpath, buf->fullpath, MAX_PATH_STORE+1); /* if (sl_strlen(buf->fullpath) < (MAX_PATH_STORE-3)) { fullpath[MAX_PATH_STORE-2] = '\0'; fullpath[MAX_PATH_STORE-1] = '\n'; } */ } else { sl_strlcpy(fullpath, sh_tiger_hash (buf->fullpath, TIGER_DATA, old_len), KEY_LEN+1); } SH_FREE(tmp); } #if defined(SH_STEALTH) sh_do_encode(fullpath, sl_strlen(fullpath)); #endif tmp = quote_string(fullpath); sl_strlcpy(fullpath, tmp, MAX_PATH_STORE+1); SH_FREE(tmp); if (buf != NULL && buf->c_mode[0] == 'l' && buf->linkpath != NULL) { old_len = sl_strlen(buf->linkpath); #if defined(SH_STEALTH) sh_do_encode(buf->linkpath, old_len); #endif tmp = quote_string(buf->linkpath); tmp_len = sl_strlen(tmp); #if defined(SH_STEALTH) sh_do_decode(buf->linkpath, old_len); #endif if (tmp_len <= MAX_PATH_STORE) { sl_strlcpy(linkpath, buf->linkpath, MAX_PATH_STORE+1); } else { sl_strlcpy(linkpath, sh_tiger_hash (buf->linkpath, TIGER_DATA, old_len), KEY_LEN+1); } SH_FREE(tmp); #if defined(SH_STEALTH) sh_do_encode(linkpath, sl_strlen(linkpath)); #endif tmp = quote_string(linkpath); sl_strlcpy(linkpath, tmp, MAX_PATH_STORE+1); SH_FREE(tmp); } if (buf != NULL) { p.mark = REC_MAGIC; sl_strlcpy(p.c_mode, buf->c_mode, 11); sl_strlcpy(p.c_group, buf->c_group, GROUP_MAX+1); sl_strlcpy(p.c_owner, buf->c_owner, USER_MAX+1); if (fileHash) { sl_strlcpy(p.checksum, fileHash, KEY_LEN+1); } #if defined(__linux__) sl_strlcpy(p.c_attributes, buf->c_attributes, 13); #else for (i = 0; i < 12; ++i) p.c_attributes[i] = '-'; p.c_attributes[12] = '\0'; #endif #if defined(SH_STEALTH) sh_do_encode(p.c_mode, sl_strlen(p.c_mode)); sh_do_encode(p.c_owner, sl_strlen(p.c_owner)); sh_do_encode(p.c_group, sl_strlen(p.c_group)); sh_do_encode(p.checksum, sl_strlen(p.checksum)); sh_do_encode(p.c_attributes, sl_strlen(p.c_attributes)); #endif #if defined(__linux__) p.attributes = (UINT32) buf->attributes; #else p.attributes = 0; #endif p.linkmode = (UINT32) buf->linkmode; p.hardlinks = (UINT32) buf->hardlinks; p.dev = (UINT64) buf->dev; p.rdev = (UINT64) buf->rdev; p.mode = (UINT32) buf->mode; p.ino = (UINT32) buf->ino; p.size = (UINT64) buf->size; p.mtime = (UINT64) buf->mtime; p.atime = (UINT64) buf->atime; p.ctime = (UINT64) buf->ctime; p.owner = (UINT32) buf->owner; p.group = (UINT32) buf->group; swap_32(&(p.mode)); swap_32(&(p.linkmode)); swap_64(&(p.dev)); swap_64(&(p.rdev)); swap_32(&(p.hardlinks)); swap_32(&(p.ino)); swap_64(&(p.size)); swap_64(&(p.atime)); swap_64(&(p.mtime)); swap_64(&(p.ctime)); swap_32(&(p.owner)); swap_32(&(p.group)); swap_32(&(p.attributes)); #ifdef OLD_BUG swap_short(&(p.mark)); #else p.mark = *(swap_short(&(p.mark))); #endif } /* write the start marker */ if (pushdata_isfirst == 1) { if (sh.flag.update == S_FALSE) { if (sh_db_version_string != NULL) { if (pushdata_stdout == S_FALSE) { sl_write (pushdata_fd, _("\n#Host "), 7); sl_write (pushdata_fd, sh.host.name, sl_strlen(sh.host.name)); sl_write (pushdata_fd, _(" Version "), 9); sl_write (pushdata_fd, sh_db_version_string, sl_strlen(sh_db_version_string)); sl_write (pushdata_fd, _(" Date "), 6); timep = sh_unix_time(0); sl_strlcpy(timestring, timep, sizeof(timestring)); sl_write (pushdata_fd, timestring, sl_strlen(timestring)); sl_write (pushdata_fd, "\n", 1); } else { printf (_("\n#Host ")); printf ("%s", sh.host.name); printf (_(" Version ")); printf ("%s", sh_db_version_string); printf (_(" Date ")); timep = sh_unix_time(0); sl_strlcpy(timestring, timep, sizeof(timestring)); printf ("%s\n", timestring); } } if (pushdata_stdout == S_FALSE) { #if defined(SH_STEALTH) sl_write (pushdata_fd, "\n", 1); sl_write_line (pushdata_fd, N_("[SOF]"), 5); #else sl_write_line (pushdata_fd, _("\n[SOF]"), 6); #endif } else { #if defined(SH_STEALTH) printf ("\n%s\n", N_("[SOF]")); #else printf ("%s\n", _("\n[SOF]")); #endif } } pushdata_isfirst = 0; } if (pushdata_stdout == S_FALSE) { sl_write (pushdata_fd, &p, sizeof(sh_filestore_t)); sl_write_line (pushdata_fd, fullpath, sl_strlen(fullpath)); sl_write_line (pushdata_fd, linkpath, sl_strlen(linkpath)); } else { fwrite (&p, sizeof(sh_filestore_t), 1, stdout); printf ("%s\n", fullpath); printf ("%s\n", linkpath); } ++p_count; if ((sh.flag.update != S_TRUE) && (pushdata_stdout == S_FALSE)) { sl_close (pushdata_fd); pushdata_fd = -1; } SH_FREE(fullpath); SH_FREE(linkpath); SL_RET0(_("sh_hash_pushdata")); } int sh_hash_writeout() { sh_file_t * p; int i; file_type * f; char fileHash[KEY_LEN + 1]; SL_ENTER(_("sh_hash_writeout")); if (S_TRUE == file_is_remote()) { sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGEN, _("Baseline database is remote"), _("sh_hash_writeout")); SL_RETURN (1, _("sh_hash_writeout")); } if (!SL_ISERROR(pushdata_fd)) { sl_close(pushdata_fd); pushdata_fd = -1; } pushdata_isfirst = 1; for (i = 0; i < TABSIZE; ++i) { for (p = tab[i]; p; p = p->next) { f = sh_hash_create_ft (p, fileHash); sh_hash_pushdata (f, fileHash); SH_FREE(f); } } if (!SL_ISERROR(pushdata_fd)) { sl_close(pushdata_fd); pushdata_fd = -1; } pushdata_isfirst = 1; SL_RETURN (0, _("sh_hash_writeout")); } /********************************************************************* * * Check whether a file is present in the database. * *********************************************************************/ static sh_file_t * sh_hash_have_it_int (char * newname) { sh_file_t * p; SL_ENTER(_("sh_hash_have_it")); if (newname == NULL) SL_RETURN( (NULL), _("sh_hash_have_it")); if (IsInit != 1) sh_hash_init(); if (sl_strlen(newname) <= MAX_PATH_STORE) p = hashsearch(newname); else p = hashsearch ( sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname)) ); if (p == NULL) SL_RETURN( (NULL), _("sh_hash_have_it")); /* if (p->allignore == S_FALSE && (p->modi_mask & MODI_CHK) != 0 && (p->modi_mask & MODI_MOD) != 0) SL_RETURN( (1), _("sh_hash_have_it")); */ SL_RETURN( (p), _("sh_hash_have_it")); } int sh_hash_have_it (char * newname) { sh_file_t * p = sh_hash_have_it_int (newname); if (!p) return (-1); if (p->allignore == S_FALSE && (p->modi_mask & MODI_CHK) != 0 && (p->modi_mask & MODI_MOD) != 0) return 1; return 0; } int sh_hash_get_it (char * newname, file_type * tmpFile) { sh_file_t * p = sh_hash_have_it_int (newname); if (!p) return (-1); sl_strlcpy(tmpFile->fullpath, p->fullpath, PATH_MAX); sl_strlcpy(tmpFile->linkpath, p->linkpath, PATH_MAX); tmpFile->size = p->theFile.size; tmpFile->mtime = p->theFile.mtime; tmpFile->ctime = p->theFile.ctime; return 0; } /***************************************************************** * * Set a file's status to 'visited'. This is required for * files that should be ignored, and may be present in the * database, but not on disk. * *****************************************************************/ static int sh_hash_set_visited_int (char * newname, int flag) { sh_file_t * p; SL_ENTER(_("sh_hash_set_visited_int")); if (newname == NULL) SL_RETURN((-1), _("sh_hash_set_visited_int")); if (IsInit != 1) sh_hash_init(); if (sl_strlen(newname) <= MAX_PATH_STORE) p = hashsearch(newname); else p = hashsearch (sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname))); if (p == NULL) SL_RETURN((-1), _("sh_hash_set_visited_int")); if (flag == 99) { p->visited = 99; p->reported = S_FALSE; } else { p->visited = S_TRUE; p->reported = flag; } SL_RETURN((0), _("sh_hash_set_visited_int")); } /* cause the record to be deleted without a 'missing' message */ int sh_hash_set_missing (char * newname) { int i; SL_ENTER(_("sh_hash_set_visited")); i = sh_hash_set_visited_int(newname, 99); SL_RETURN(i, _("sh_hash_set_visited")); } int sh_hash_set_visited (char * newname) { int i; SL_ENTER(_("sh_hash_set_visited")); i = sh_hash_set_visited_int(newname, S_TRUE); SL_RETURN(i, _("sh_hash_set_visited")); } int sh_hash_set_visited_true (char * newname) { int i; SL_ENTER(_("sh_hash_set_visited_true")); i = sh_hash_set_visited_int(newname, S_FALSE); SL_RETURN(i, _("sh_hash_set_visited_true")); } /****************************************************************** * * Data entry for arbitrary data into database * ******************************************************************/ static char * sh_hash_charhex( unsigned char i ) { static char i2h[2]; int j, k; j = i / 16; k = i - (j*16); if (j < 10) i2h[0] = '0'+j; else i2h[0] = 'A'+(j-10); if (k < 10) i2h[1] = '0'+k; else i2h[1] = 'A'+(k-10); return i2h; } void sh_hash_push2db (char * key, unsigned long val1, unsigned long val2, unsigned long val3, unsigned char * str, int size) { file_type tmpFile; int i = 0; char * p; sl_strlcpy(tmpFile.fullpath, key, PATH_MAX); tmpFile.size = val1; tmpFile.mtime = val2; tmpFile.ctime = val3; tmpFile.atime = 0; tmpFile.mode = 0; tmpFile.owner = 0; tmpFile.group = 0; sl_strlcpy(tmpFile.c_owner, _("root"), 5); sl_strlcpy(tmpFile.c_group, _("root"), 5); if ((str != NULL) && (size < (PATH_MAX/2)-1)) { tmpFile.c_mode[0] = 'l'; tmpFile.c_mode[1] = 'r'; tmpFile.c_mode[2] = 'w'; tmpFile.c_mode[3] = 'x'; tmpFile.c_mode[4] = 'r'; tmpFile.c_mode[5] = 'w'; tmpFile.c_mode[6] = 'x'; tmpFile.c_mode[7] = 'r'; tmpFile.c_mode[8] = 'w'; tmpFile.c_mode[9] = 'x'; tmpFile.c_mode[10] = '\0'; for (i = 0; i < size; ++i) { p = sh_hash_charhex (str[i]); tmpFile.linkpath[2*i] = p[0]; tmpFile.linkpath[2*i+1] = p[1]; tmpFile.linkpath[2*i+2] = '\0'; } } else { tmpFile.c_mode[0] = '-'; tmpFile.c_mode[1] = '-'; tmpFile.c_mode[2] = '-'; tmpFile.c_mode[3] = '-'; tmpFile.c_mode[4] = '-'; tmpFile.c_mode[5] = '-'; tmpFile.c_mode[6] = '-'; tmpFile.c_mode[7] = '-'; tmpFile.c_mode[8] = '-'; tmpFile.c_mode[9] = '-'; tmpFile.c_mode[10] = '\0'; tmpFile.linkpath[0] = '-'; tmpFile.linkpath[1] = '\0'; } if (sh.flag.checkSum == SH_CHECK_CHECK && sh.flag.update == S_TRUE) sh_hash_pushdata_memory (&tmpFile, _("000000000000000000000000000000000000000000000000")); else sh_hash_pushdata (&tmpFile, _("000000000000000000000000000000000000000000000000")); return; } extern int sh_util_hextobinary (char * binary, char * hex, int bytes); char * sh_hash_db2pop (char * key, unsigned long * val1, unsigned long * val2, unsigned long * val3, int * size) { file_type tmpFile; size_t len; char * p; int i; *size = 0; if (0 == sh_hash_get_it (key, &tmpFile)) { *val1 = tmpFile.size; *val2 = tmpFile.mtime; *val3 = tmpFile.ctime; if (tmpFile.linkpath[0] != '-') { len = strlen(tmpFile.linkpath); p = SH_ALLOC((len/2)+1); i = sh_util_hextobinary (p, tmpFile.linkpath, len); if (i == 0) { *size = (len/2); p[*size] = '\0'; return p; } else { SH_FREE(p); *size = 0; return NULL; } } else { *size = 0; return NULL; } } else { *size = -1; *val1 = 0; *val2 = 0; *val3 = 0; return NULL; } } /****************************************************************** * * Data entry in hash table * ******************************************************************/ sh_file_t * sh_hash_push_int (file_type * buf, char * fileHash) { sh_file_t * fp; sh_filestore_t p; long i; char * fullpath; char * linkpath; SL_ENTER(_("sh_hash_push_int")); fp = SH_ALLOC(sizeof(sh_file_t)); p.mark = REC_MAGIC; sl_strlcpy(p.c_mode, buf->c_mode, 11); sl_strlcpy(p.c_group, buf->c_group, GROUP_MAX+1); sl_strlcpy(p.c_owner, buf->c_owner, USER_MAX+1); sl_strlcpy(p.checksum, fileHash, KEY_LEN+1); #if defined(__linux__) sl_strlcpy(p.c_attributes, buf->c_attributes, 13); #endif #if defined(__linux__) p.attributes = (UINT32) buf->attributes; #endif p.linkmode = (UINT32) buf->linkmode; p.hardlinks = (UINT32) buf->hardlinks; p.mode = (UINT32) buf->mode; p.ino = (UINT32) buf->ino; p.size = (UINT64) buf->size; p.mtime = (UINT64) buf->mtime; p.atime = (UINT64) buf->atime; p.ctime = (UINT64) buf->ctime; p.owner = (UINT32) buf->owner; p.group = (UINT32) buf->group; memcpy( &(*fp).theFile, &p, sizeof(sh_filestore_t) ); fp->visited = S_FALSE; fp->reported = S_FALSE; fp->allignore = S_FALSE; fp->modi_mask = 0L; i = sl_strlen(buf->fullpath); if (i <= MAX_PATH_STORE) { fullpath = SH_ALLOC(i+ 1); sl_strlcpy(fullpath, buf->fullpath, i+1); } else { fullpath = SH_ALLOC(KEY_LEN + 1); sl_strlcpy(fullpath, sh_tiger_hash (buf->fullpath, TIGER_DATA, i), KEY_LEN+1); } fp->fullpath = fullpath; if (buf->c_mode[0] == 'l') { i = sl_strlen(buf->linkpath); if (i <= MAX_PATH_STORE) { linkpath = SH_ALLOC(i+ 1); sl_strlcpy(linkpath, buf->linkpath, i+1); } else { linkpath = SH_ALLOC(KEY_LEN + 1); sl_strlcpy(linkpath, sh_tiger_hash (buf->linkpath, TIGER_DATA, i), KEY_LEN+1); } fp->linkpath = linkpath; } else fp->linkpath = NULL; SL_RETURN( fp, _("sh_hash_push_int")); } #ifdef HAVE_INTTYPES_H #include #else #ifdef HAVE_STDINT_H #include #endif #endif #ifndef PRIi64 #define PRIi64 "lld" #endif char * sh_hash_size_format() { static char form_rval[81]; SL_ENTER(_("sh_hash_size_format")); #ifdef SH_USE_XML sl_snprintf(form_rval, 80, _("%s%s%s%s%s"), _("size_old=\"%"), PRIi64, _("\" size_new=\"%"), PRIi64, "\" "); #else sl_snprintf(form_rval, 80, _("%s%s%s%s%s"), _("size_old=<%"), PRIi64, _(">, size_new=<%"), PRIi64, ">, "); #endif SL_RETURN( form_rval, _("sh_hash_size_format")); } #ifdef SH_USE_XML static char * all_items (file_type * theFile, char * fileHash, int is_new) { char timstr1c[32]; char timstr1a[32]; char timstr1m[32]; char * tmp_lnk; char * format; char * tmp = SH_ALLOC(SH_BUFSIZE); char * msg = SH_ALLOC(SH_BUFSIZE); tmp[0] = '\0'; msg[0] = '\0'; #if defined(__linux__) if (is_new) format = _("mode_new=\"%s\" attr_new=\"%s\" imode_new=\"%ld\" iattr_new=\"%ld\" "); else format = _("mode_old=\"%s\" attr_old=\"%s\" imode_old=\"%ld\" iattr_old=\"%ld\" "); sl_snprintf(tmp, SH_BUFSIZE, format, theFile->c_mode, theFile->c_attributes, (long) theFile->mode, (long) theFile->attributes ); #else if (is_new) format = _("mode_new=\"%s\" imode_new=\"%ld\" "); else format = _("mode_old=\"%s\" imode_old=\"%ld\" "); sl_snprintf(tmp, SH_BUFSIZE, format, theFile->c_mode, (long) theFile->mode ); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) format = _("hardlinks_new=\"%ld\" "); else format = _("hardlinks_old=\"%ld\" "); sl_snprintf(tmp, SH_BUFSIZE, format, (unsigned long) theFile->hardlinks); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) format = _("idevice_new=\"%ld\" "); else format = _("idevice_old=\"%ld\" "); sl_snprintf(tmp, SH_BUFSIZE, format, (unsigned long) theFile->rdev); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) format = _("inode_new=\"%ld\" "); else format = _("inode_old=\"%ld\" "); sl_snprintf(tmp, SH_BUFSIZE, format, (unsigned long) theFile->ino); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) format = _("owner_new=\"%s\" iowner_new=\"%ld\" "); else format = _("owner_old=\"%s\" iowner_old=\"%ld\" "); sl_snprintf(tmp, SH_BUFSIZE, format, theFile->c_owner, (long) theFile->owner); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) format = _("group_new=\"%s\" igroup_new=\"%ld\" "); else format = _("group_old=\"%s\" igroup_old=\"%ld\" "); sl_snprintf(tmp, SH_BUFSIZE, format, theFile->c_group, (long) theFile->group); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) sl_snprintf(tmp, SH_BUFSIZE, sh_hash_size_format(), (UINT64) 0, (UINT64) theFile->size); else sl_snprintf(tmp, SH_BUFSIZE, sh_hash_size_format(), (UINT64) theFile->size, (UINT64) 0); sl_strlcat(msg, tmp, SH_BUFSIZE); sl_strlcpy (timstr1c, sh_unix_gmttime (theFile->ctime), 32); if (is_new) sl_snprintf(tmp, SH_BUFSIZE, _("ctime_new=\"%s\" "), timstr1c); else sl_snprintf(tmp, SH_BUFSIZE, _("ctime_old=\"%s\" "), timstr1c); sl_strlcat(msg, tmp, SH_BUFSIZE); sl_strlcpy (timstr1a, sh_unix_gmttime (theFile->atime), 32); if (is_new) sl_snprintf(tmp, SH_BUFSIZE, _("atime_new=\"%s\" "), timstr1a); else sl_snprintf(tmp, SH_BUFSIZE, _("atime_old=\"%s\" "), timstr1a); sl_strlcat(msg, tmp, SH_BUFSIZE); sl_strlcpy (timstr1m, sh_unix_gmttime (theFile->mtime), 32); if (is_new) sl_snprintf(tmp, SH_BUFSIZE, _("mtime_new=\"%s\" "), timstr1m); else sl_snprintf(tmp, SH_BUFSIZE, _("mtime_old=\"%s\" "), timstr1m); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) sl_snprintf(tmp, SH_BUFSIZE, _("chksum_new=\"%s\" "), fileHash); else sl_snprintf(tmp, SH_BUFSIZE, _("chksum_old=\"%s\" "), fileHash); sl_strlcat(msg, tmp, SH_BUFSIZE); if (theFile->c_mode[0] == 'l') { tmp_lnk = sh_util_safe_name(theFile->linkpath); if (tmp_lnk) { if (is_new) sl_snprintf(tmp, SH_BUFSIZE, _("link_new=\"%s\" "), tmp_lnk); else sl_snprintf(tmp, SH_BUFSIZE, _("link_old=\"%s\" "), tmp_lnk); SH_FREE(tmp_lnk); sl_strlcat(msg, tmp, SH_BUFSIZE); } } SH_FREE(tmp); return (msg); } #else static char * all_items (file_type * theFile, char * fileHash, int is_new) { char timstr1c[32]; char timstr1a[32]; char timstr1m[32]; char * tmp_lnk; char * format; char * tmp = SH_ALLOC(SH_BUFSIZE); char * msg = SH_ALLOC(SH_BUFSIZE); tmp[0] = '\0'; msg[0] = '\0'; #if defined(__linux__) if (is_new) format = _("mode_new=<%s>, attr_new=<%s>, imode_new=<%ld>, iattr_new=<%ld>, "); else format = _("mode_old=<%s>, attr_old=<%s>, imode_old=<%ld>, iattr_old=<%ld>, "); sl_snprintf(tmp, SH_BUFSIZE, format, theFile->c_mode, theFile->c_attributes, (long) theFile->mode, (long) theFile->attributes ); #else if (is_new) format = _("mode_new=<%s>, imode_new=<%ld>, "); else format = _("mode_old=<%s>, imode_old=<%ld>, "); sl_snprintf(tmp, SH_BUFSIZE, format, theFile->c_mode, (long) theFile->mode ); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) format = _("hardlinks_new=<%ld>, "); else format = _("hardlinks_old=<%ld>, "); sl_snprintf(tmp, SH_BUFSIZE, format, (unsigned long) theFile->hardlinks); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) format = _("idevice_new=<%ld>, "); else format = _("idevice_old=<%ld>, "); sl_snprintf(tmp, SH_BUFSIZE, format, (unsigned long) theFile->rdev); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) format = _("inode_new=<%ld>, "); else format = _("inode_old=<%ld>, "); sl_snprintf(tmp, SH_BUFSIZE, format, (unsigned long) theFile->ino); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) format = _("owner_new=<%s>, iowner_new=<%ld>, "); else format = _("owner_old=<%s>, iowner_old=<%ld>, "); sl_snprintf(tmp, SH_BUFSIZE, format, theFile->c_owner, (long) theFile->owner); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) format = _("group_new=<%s>, igroup_new=<%ld>, "); else format = _("group_old=<%s>, igroup_old=<%ld>, "); sl_snprintf(tmp, SH_BUFSIZE, format, theFile->c_group, (long) theFile->group); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) sl_snprintf(tmp, SH_BUFSIZE, sh_hash_size_format(), (UINT64) 0, (UINT64) theFile->size); else sl_snprintf(tmp, SH_BUFSIZE, sh_hash_size_format(), (UINT64) theFile->size, (UINT64) 0); sl_strlcat(msg, tmp, SH_BUFSIZE); sl_strlcpy (timstr1c, sh_unix_gmttime (theFile->ctime), 32); if (is_new) sl_snprintf(tmp, SH_BUFSIZE, _("ctime_new=<%s>, "), timstr1c); else sl_snprintf(tmp, SH_BUFSIZE, _("ctime_old=<%s>, "), timstr1c); sl_strlcat(msg, tmp, SH_BUFSIZE); sl_strlcpy (timstr1a, sh_unix_gmttime (theFile->atime), 32); if (is_new) sl_snprintf(tmp, SH_BUFSIZE, _("atime_new=<%s>, "), timstr1a); else sl_snprintf(tmp, SH_BUFSIZE, _("atime_old=<%s>, "), timstr1a); sl_strlcat(msg, tmp, SH_BUFSIZE); sl_strlcpy (timstr1m, sh_unix_gmttime (theFile->mtime), 32); if (is_new) sl_snprintf(tmp, SH_BUFSIZE, _("mtime_new=<%s>, "), timstr1m); else sl_snprintf(tmp, SH_BUFSIZE, _("mtime_old=<%s>, "), timstr1m); sl_strlcat(msg, tmp, SH_BUFSIZE); if (is_new) sl_snprintf(tmp, SH_BUFSIZE, _("chksum_new=<%s>"), fileHash); else sl_snprintf(tmp, SH_BUFSIZE, _("chksum_old=<%s>"), fileHash); sl_strlcat(msg, tmp, SH_BUFSIZE); if (theFile->c_mode[0] == 'l') { tmp_lnk = sh_util_safe_name(theFile->linkpath); if (tmp_lnk) { if (is_new) sl_snprintf(tmp, SH_BUFSIZE, _(", link_new=<%s> "), tmp_lnk); else sl_snprintf(tmp, SH_BUFSIZE, _(", link_old=<%s> "), tmp_lnk); SH_FREE(tmp_lnk); sl_strlcat(msg, tmp, SH_BUFSIZE); } } SH_FREE(tmp); return (msg); } #endif void sh_hash_pushdata_memory (file_type * theFile, char * fileHash) { sh_file_t * p; SL_ENTER(_("sh_hash_pushdata_memory")); p = sh_hash_push_int(theFile, fileHash); if (p) { hashinsert (p); p->modi_mask = theFile->check_mask; } SL_RET0(_("sh_hash_pushdata_memory")); } /***************************************************************** * * Compare a file with the database status. * *****************************************************************/ int sh_hash_compdata (int class, file_type * theFile, char * fileHash, char * policy_override, int severity_override) { char * msg; sh_file_t * p; char * tmp; char * tmp_path; char * tmp_lnk; char * tmp_lnk_old; char * str; char timstr1c[32]; char timstr2c[32]; char timstr1a[32]; char timstr2a[32]; char timstr1m[32]; char timstr2m[32]; char linkHash[KEY_LEN+1]; int maxcomp; char change_code[16]; int i; unsigned long modi_mask = 0; char log_policy[32]; int log_severity; SL_ENTER(_("sh_hash_compdata")); if (IsInit != 1) sh_hash_init(); if (severity_override < 0) log_severity = ShDFLevel[class]; else log_severity = severity_override; if (policy_override != NULL) sl_strlcpy (log_policy, policy_override, 32); /* -------- find the entry for the file ---------------- */ if (sl_strlen(theFile->fullpath) <= MAX_PATH_STORE) p = hashsearch(theFile->fullpath); else p = hashsearch( sh_tiger_hash(theFile->fullpath, TIGER_DATA, sl_strlen(theFile->fullpath)) ); /* --------- Not found in database. ------------ */ if (p == NULL) { if (sh.flag.reportonce == S_TRUE) { p = sh_hash_push_int(theFile, fileHash); hashinsert (p); if (p) p->modi_mask = theFile->check_mask; } if (S_FALSE == sh_ignore_chk_new(theFile->fullpath)) { tmp = sh_util_safe_name(theFile->fullpath); str = all_items (theFile, fileHash, 1); sh_error_handle (log_severity, FIL__, __LINE__, 0, MSG_FI_ADD2, tmp, str); SH_FREE(str); SH_FREE(tmp); } if (p) p->visited = S_TRUE; if (sh.flag.reportonce == S_TRUE) theFile->reported = S_TRUE; if (sh.flag.isdaemon == S_FALSE && sh.flag.update == S_TRUE ) { if (S_FALSE == sh_util_ask_update (theFile->fullpath)) { SL_RETURN(1, _("sh_hash_compdata")); } } SL_RETURN(0, _("sh_hash_compdata")); } else { p->modi_mask = theFile->check_mask; } /* initialize change_code */ for (i = 0; i < 15; ++i) change_code[i] = '-'; change_code[15] = '\0'; TPT ((0, FIL__, __LINE__, _("file=<%s>, cs_old=<%s>, cs_new=<%s>\n"), theFile->fullpath, fileHash, p->theFile.checksum)); if ( (fileHash != NULL) && (p->theFile.checksum != NULL) && (strncmp (fileHash, p->theFile.checksum, 50) != 0) && (theFile->check_mask & MODI_CHK) != 0) { modi_mask |= MODI_CHK; change_code[0] = 'C'; TPT ((0, FIL__, __LINE__, _("mod="))); } if (p->theFile.c_mode[0] == 'l') { if (sl_strlen(theFile->linkpath) >= MAX_PATH_STORE) { sl_strlcpy(linkHash, sh_tiger_hash(theFile->linkpath, TIGER_DATA, sl_strlen(theFile->linkpath)), MAX_PATH_STORE+1); maxcomp = MAX_PATH_STORE; } else { sl_strlcpy(linkHash, theFile->linkpath, KEY_LEN + 1); maxcomp = KEY_LEN; } if ( sl_strncmp (linkHash, p->linkpath, maxcomp) != 0 && (theFile->check_mask & MODI_LNK) != 0) { modi_mask |= MODI_LNK; change_code[1] = 'L'; TPT ((0, FIL__, __LINE__, _("mod="))); } } if (p->theFile.c_mode[0] == 'c' || p->theFile.c_mode[0] == 'b') { if ( ( major(theFile->rdev) != major((dev_t)p->theFile.rdev) || minor(theFile->rdev) != minor((dev_t)p->theFile.rdev) ) && (theFile->check_mask & MODI_RDEV) != 0) { modi_mask |= MODI_RDEV; change_code[2] = 'D'; TPT ((0, FIL__, __LINE__, _("mod="))); } } /* cast to UINT32 in case ino_t is not 32bit */ if ( (UINT32) theFile->ino != (UINT32) p->theFile.ino && (theFile->check_mask & MODI_INO) != 0) { modi_mask |= MODI_INO; change_code[3] = 'I'; TPT ((0, FIL__, __LINE__, _("mod="))); } if ( theFile->hardlinks != (nlink_t) p->theFile.hardlinks && (theFile->check_mask & MODI_HLN) != 0) { modi_mask |= MODI_HLN; change_code[4] = 'H'; TPT ((0, FIL__, __LINE__, _("mod="))); } if ( ( (theFile->mode != p->theFile.mode) #if defined(__linux__) || (theFile->attributes != p->theFile.attributes) #endif ) && (theFile->check_mask & MODI_MOD) != 0) { modi_mask |= MODI_MOD; change_code[5] = 'M'; TPT ((0, FIL__, __LINE__, _("mod="))); /* * report link path if switch link/no link */ if ((theFile->check_mask & MODI_LNK) != 0 && (theFile->c_mode[0] != p->theFile.c_mode[0]) && (theFile->c_mode[0] == 'l' || p->theFile.c_mode[0] == 'l')) { modi_mask |= MODI_LNK; change_code[1] = 'L'; TPT ((0, FIL__, __LINE__, _("mod="))); } } if ( theFile->owner != (uid_t) p->theFile.owner && (theFile->check_mask & MODI_USR) != 0) { modi_mask |= MODI_USR; change_code[6] = 'U'; TPT ((0, FIL__, __LINE__, _("mod="))); } if ( theFile->group != (gid_t) p->theFile.group && (theFile->check_mask & MODI_GRP) != 0) { modi_mask |= MODI_GRP; change_code[7] = 'G'; TPT ((0, FIL__, __LINE__, _("mod="))); } if ( theFile->mtime != (time_t) p->theFile.mtime && (theFile->check_mask & MODI_MTM) != 0) { modi_mask |= MODI_MTM; change_code[8] = 'T'; TPT ((0, FIL__, __LINE__, _("mod="))); } if ( theFile->atime != (time_t) p->theFile.atime && (theFile->check_mask & MODI_ATM) != 0) { modi_mask |= MODI_ATM; change_code[8] = 'T'; TPT ((0, FIL__, __LINE__, _("mod="))); } /* Resetting the access time will set a new ctime. Thus, either we ignore * the access time or the ctime for NOIGNORE */ if ( theFile->ctime != (time_t) p->theFile.ctime && (theFile->check_mask & MODI_CTM) != 0) { modi_mask |= MODI_CTM; change_code[8] = 'T'; TPT ((0, FIL__, __LINE__, _("mod="))); } if ( theFile->size != (off_t) p->theFile.size && (theFile->check_mask & MODI_SIZ) != 0) { if (class == SH_LEVEL_LOGGROW && theFile->size < (off_t) p->theFile.size) { modi_mask |= MODI_SIZ; change_code[9] = 'S'; TPT ((0, FIL__, __LINE__, _("mod="))); } else if (class != SH_LEVEL_LOGGROW) { modi_mask |= MODI_SIZ; change_code[9] = 'S'; TPT ((0, FIL__, __LINE__, _("mod="))); } } change_code[10] = '\0'; /* --- Report full details. --- */ if (modi_mask != 0 && sh.flag.fulldetail == S_TRUE) { if ((theFile->check_mask & MODI_ATM) == 0) modi_mask = MASK_READONLY_; else modi_mask = MASK_NOIGNORE_; } /* --- Report on modified files. --- */ if (modi_mask != 0 && p->reported == S_FALSE) { tmp = SH_ALLOC(SH_BUFSIZE); msg = SH_ALLOC(SH_BUFSIZE); msg[0] = '\0'; if ( ((modi_mask & MODI_MOD) != 0) #if defined(HAVE_LIBPRELUDE) && defined(HAVE_LIBPRELUDE_9) || ((modi_mask & MODI_USR) != 0) || ((modi_mask & MODI_GRP) != 0) #endif ) { #if defined(__linux__) sl_snprintf(tmp, SH_BUFSIZE, #ifdef SH_USE_XML _("mode_old=\"%s\" mode_new=\"%s\" attr_old=\"%s\" attr_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" iattr_old=\"%ld\" iattr_new=\"%ld\" "), #else _("mode_old=<%s>, mode_new=<%s>, attr_old=<%s>, attr_new=<%s>, "), #endif p->theFile.c_mode, theFile->c_mode, p->theFile.c_attributes, theFile->c_attributes #ifdef SH_USE_XML , (long) p->theFile.mode, (long) theFile->mode, (long) p->theFile.attributes, (long) theFile->attributes #endif ); #else #ifdef SH_USE_XML sl_snprintf(tmp, SH_BUFSIZE, _("mode_old=\"%s\" mode_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" "), #else sl_snprintf(tmp, SH_BUFSIZE, _("mode_old=<%s>, mode_new=<%s>, "), #endif p->theFile.c_mode, theFile->c_mode #ifdef SH_USE_XML , (long) p->theFile.mode, (long) theFile->mode #endif ); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if ((modi_mask & MODI_MOD) != 0) { /* * We postpone update if sh.flag.update == S_TRUE because * in interactive mode the user may not accept the change. */ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) { sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11); p->theFile.mode = theFile->mode; #if defined(__linux__) sl_strlcpy(p->theFile.c_attributes,theFile->c_attributes,16); p->theFile.attributes = theFile->attributes; #endif } } #endif } if ((modi_mask & MODI_HLN) != 0) { sl_snprintf(tmp, SH_BUFSIZE, #ifdef SH_USE_XML _("hardlinks_old=\"%ld\" hardlinks_new=\"%ld\" "), #else _("hardlinks_old=<%ld>, hardlinks_new=<%ld>, "), #endif (unsigned long) p->theFile.hardlinks, (unsigned long) theFile->hardlinks); sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) p->theFile.hardlinks = theFile->hardlinks; #endif } if ((modi_mask & MODI_RDEV) != 0) { sl_snprintf(tmp, SH_BUFSIZE, #ifdef SH_USE_XML _("device_old=\"%ld,%ld\" device_new=\"%ld,%ld\" idevice_old=\"%ld\" idevice_new=\"%ld\" "), #else _("device_old=<%ld,%ld>, device_new=<%ld,%ld>, "), #endif (unsigned long) major(p->theFile.rdev), (unsigned long) minor(p->theFile.rdev), (unsigned long) major(theFile->rdev), (unsigned long) minor(theFile->rdev) #ifdef SH_USE_XML , (unsigned long) p->theFile.rdev, (unsigned long) theFile->rdev #endif ); sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) p->theFile.rdev = theFile->rdev; #endif } if ((modi_mask & MODI_INO) != 0) { sl_snprintf(tmp, SH_BUFSIZE, #ifdef SH_USE_XML _("inode_old=\"%ld\" inode_new=\"%ld\" "), #else _("inode_old=<%ld>, inode_new=<%ld>, "), #endif (unsigned long) p->theFile.ino, (unsigned long) theFile->ino); sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) p->theFile.ino = theFile->ino; #endif } if ( ((modi_mask & MODI_USR) != 0) #if defined(HAVE_LIBPRELUDE) && defined(HAVE_LIBPRELUDE_9) || ((modi_mask & MODI_MOD) != 0) #endif ) { #ifdef SH_USE_XML sl_snprintf(tmp, SH_BUFSIZE, _("owner_old=\"%s\" owner_new=\"%s\" iowner_old=\"%ld\" iowner_new=\"%ld\" "), #else sl_snprintf(tmp, SH_BUFSIZE, _("owner_old=<%s>, owner_new=<%s>, "), #endif p->theFile.c_owner, theFile->c_owner #ifdef SH_USE_XML , (long) p->theFile.owner, (long) theFile->owner #endif ); sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if ((modi_mask & MODI_USR) != 0) { if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) { sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2); p->theFile.owner = theFile->owner; } } #endif } if ( ((modi_mask & MODI_GRP) != 0) #if defined(HAVE_LIBPRELUDE) && defined(HAVE_LIBPRELUDE_9) || ((modi_mask & MODI_MOD) != 0) #endif ) { #ifdef SH_USE_XML sl_snprintf(tmp, SH_BUFSIZE, _("group_old=\"%s\" group_new=\"%s\" igroup_old=\"%ld\" igroup_new=\"%ld\" "), p->theFile.c_group, theFile->c_group, (long) p->theFile.group, (long) theFile->group); #else sl_snprintf(tmp, SH_BUFSIZE, _("group_old=<%s>, group_new=<%s>, "), p->theFile.c_group, theFile->c_group); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if ((modi_mask & MODI_GRP) != 0) { if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) { sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2); p->theFile.group = theFile->group; } } #endif } if ((modi_mask & MODI_SIZ) != 0) { sl_snprintf(tmp, SH_BUFSIZE, sh_hash_size_format(), (UINT64) p->theFile.size, (UINT64) theFile->size); sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) p->theFile.size = theFile->size; #endif } if ((modi_mask & MODI_CTM) != 0) { sl_strlcpy (timstr1c, sh_unix_gmttime (p->theFile.ctime), 32); sl_strlcpy (timstr2c, sh_unix_gmttime (theFile->ctime), 32); #ifdef SH_USE_XML sl_snprintf(tmp, SH_BUFSIZE, _("ctime_old=\"%s\" ctime_new=\"%s\" "), timstr1c, timstr2c); #else sl_snprintf(tmp, SH_BUFSIZE, _("ctime_old=<%s>, ctime_new=<%s>, "), timstr1c, timstr2c); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) p->theFile.ctime = theFile->ctime; #endif } if ((modi_mask & MODI_ATM) != 0) { sl_strlcpy (timstr1a, sh_unix_gmttime (p->theFile.atime), 32); sl_strlcpy (timstr2a, sh_unix_gmttime (theFile->atime), 32); #ifdef SH_USE_XML sl_snprintf(tmp, SH_BUFSIZE, _("atime_old=\"%s\" atime_new=\"%s\" "), timstr1a, timstr2a); #else sl_snprintf(tmp, SH_BUFSIZE, _("atime_old=<%s>, atime_new=<%s>, "), timstr1a, timstr2a); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) p->theFile.atime = theFile->atime; #endif } if ((modi_mask & MODI_MTM) != 0) { sl_strlcpy (timstr1m, sh_unix_gmttime (p->theFile.mtime), 32); sl_strlcpy (timstr2m, sh_unix_gmttime (theFile->mtime), 32); #ifdef SH_USE_XML sl_snprintf(tmp, SH_BUFSIZE, _("mtime_old=\"%s\" mtime_new=\"%s\" "), timstr1m, timstr2m); #else sl_snprintf(tmp, SH_BUFSIZE, _("mtime_old=<%s>, mtime_new=<%s>, "), timstr1m, timstr2m); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) p->theFile.mtime = theFile->mtime; #endif } if ((modi_mask & MODI_CHK) != 0) { sl_snprintf(tmp, SH_BUFSIZE, #ifdef SH_USE_XML _("chksum_old=\"%s\" chksum_new=\"%s\" "), #else _("chksum_old=<%s>, chksum_new=<%s>, "), #endif p->theFile.checksum, fileHash); sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1); #endif } if ((modi_mask & MODI_LNK) != 0 && theFile->c_mode[0] == 'l') { tmp_lnk = sh_util_safe_name(theFile->linkpath); tmp_lnk_old = sh_util_safe_name(p->linkpath); #ifdef SH_USE_XML sl_snprintf(tmp, SH_BUFSIZE, _("link_old=\"%s\" link_new=\"%s\" "), tmp_lnk_old, tmp_lnk); #else sl_snprintf(tmp, SH_BUFSIZE, _("link_old=<%s>, link_new=<%s>"), tmp_lnk_old, tmp_lnk); #endif SH_FREE(tmp_lnk); SH_FREE(tmp_lnk_old); sl_strlcat(msg, tmp, SH_BUFSIZE); #ifdef REPLACE_OLD if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) { if (p->linkpath != NULL) SH_FREE(p->linkpath); p->linkpath = (char*)SH_ALLOC (sl_strlen(theFile->linkpath) + 1); sl_strlcpy(p->linkpath, theFile->linkpath, sl_strlen(theFile->linkpath) + 1); } #endif } tmp_path = sh_util_safe_name(theFile->fullpath); sh_error_handle(log_severity, FIL__, __LINE__, (long) modi_mask, MSG_FI_CHAN, (policy_override == NULL) ? _(policy[class]):log_policy, change_code, tmp_path, msg); SH_FREE(tmp_path); SH_FREE(tmp); SH_FREE(msg); #ifndef REPLACE_OLD p->reported = S_TRUE; #endif if (S_TRUE == sh.flag.update) { if (S_FALSE == sh_util_ask_update(theFile->fullpath)) { /* user does not want to update, thus we replace * with data from the baseline database */ sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11); theFile->mode = p->theFile.mode; #if defined(__linux__) sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, 16); theFile->attributes = p->theFile.attributes; #endif if (theFile->c_mode[0] == 'l') /* c_mode is already copied */ { sl_strlcpy(theFile->linkpath, p->linkpath, PATH_MAX); } else { theFile->linkpath[0] = '-'; theFile->linkpath[1] = '\0'; } sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1); theFile->mtime = p->theFile.mtime; theFile->ctime = p->theFile.ctime; theFile->atime = p->theFile.atime; theFile->size = p->theFile.size; sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2); theFile->group = p->theFile.group; sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2); theFile->owner = p->theFile.owner; theFile->ino = p->theFile.ino; theFile->rdev = p->theFile.rdev; theFile->dev = p->theFile.dev; theFile->hardlinks = p->theFile.hardlinks; p->visited = S_TRUE; SL_RETURN(1, _("sh_hash_compdata")); } else if (sh.flag.reportonce == S_TRUE) { /* we replace the data in the in-memory copy of the * baseline database, because otherwise we would get * another warning if the suidcheck runs */ sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11); p->theFile.mode = theFile->mode; #if defined(__linux__) sl_strlcpy(p->theFile.c_attributes, theFile->c_attributes, 16); p->theFile.attributes = theFile->attributes; #endif if (theFile->c_mode[0] == 'l') { if (p->linkpath != NULL) SH_FREE(p->linkpath); p->linkpath = SH_ALLOC(1 + strlen(theFile->linkpath)); sl_strlcpy(p->linkpath, theFile->linkpath, 1 + strlen(theFile->linkpath)); } else { if (p->linkpath != NULL) { p->linkpath[0] = '-'; p->linkpath[1] = '\0'; } else { p->linkpath = SH_ALLOC(2); p->linkpath[0] = '-'; p->linkpath[1] = '\0'; } } sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1); p->theFile.mtime = theFile->mtime; p->theFile.ctime = theFile->ctime; p->theFile.atime = theFile->atime; p->theFile.size = theFile->size; sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2); p->theFile.group = theFile->group; sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2); p->theFile.owner = theFile->owner; p->theFile.ino = theFile->ino; p->theFile.rdev = theFile->rdev; p->theFile.dev = theFile->dev; p->theFile.hardlinks = theFile->hardlinks; } } } p->visited = S_TRUE; SL_RETURN(0, _("sh_hash_compdata")); } int hash_full_tree () { sh_file_t * p; int i; SL_ENTER(_("sh_hash_compdata")); if (IsInit != 1) SL_RETURN(0, _("sh_hash_compdata")); for (i = 0; i < TABSIZE; ++i) { for (p = tab[i]; p; p = p->next) p->allignore = S_FALSE; } SL_RETURN (0, _("sh_hash_compdata")); } int hash_remove_tree (char * s) { sh_file_t * p; int len; int i; SL_ENTER(_("hash_remove_tree")); if (!s) SL_RETURN ((-1), _("hash_remove_tree")); else len = sl_strlen(s); if (IsInit != 1) sh_hash_init(); for (i = 0; i < TABSIZE; ++i) { for (p = tab[i]; p; p = p->next) { if (sl_strncmp(s, p->fullpath, len) == 0) { p->allignore = S_TRUE; } } } SL_RETURN ((0), _("hash_remove_tree")); } #if TIME_WITH_SYS_TIME #include #include #else #if HAVE_SYS_TIME_H #include #else #include #endif #endif static int ListFullDetail = S_FALSE; static int ListWithDelimiter = S_FALSE; int set_full_detail (char * c) { ListFullDetail = S_TRUE; /* warning: unused parameter `c' */ if (c) return 0; else return 0; } int set_list_delimited (char * c) { ListFullDetail = S_TRUE; ListWithDelimiter = S_TRUE; /* warning: unused parameter `c' */ if (c) return 0; else return 0; } void sh_hash_list_db_entry_full_detail (sh_file_t * p) { char * tmp; char str[81]; if (ListWithDelimiter == S_TRUE) { printf(_("%7ld, %10s, %5d, %12s, %5d, %3d, %-8s, %5d, %-8s, %5d, "), (unsigned long) p->theFile.ino, p->theFile.c_mode, (int) p->theFile.mode, p->theFile.c_attributes, (int) p->theFile.attributes, (int) p->theFile.hardlinks, p->theFile.c_owner, (int) p->theFile.owner, p->theFile.c_group, (int) p->theFile.group); } else { printf(_("%7ld %10s %5d %12s %5d %3d %-8s %5d %-8s %5d "), (unsigned long) p->theFile.ino, p->theFile.c_mode, (int) p->theFile.mode, p->theFile.c_attributes, (int) p->theFile.attributes, (int) p->theFile.hardlinks, p->theFile.c_owner, (int) p->theFile.owner, p->theFile.c_group, (int) p->theFile.group); } if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0]) sl_snprintf(str, 80, "%"PRIi64, p->theFile.rdev); else sl_snprintf(str, 80, "%"PRIi64, p->theFile.size); printf( _(" %8s"), str); if (ListWithDelimiter == S_TRUE) putchar(','); printf( _(" %s"), sh_unix_gmttime (p->theFile.ctime)); if (ListWithDelimiter == S_TRUE) putchar(','); printf( _(" %s"), sh_unix_gmttime (p->theFile.mtime)); if (ListWithDelimiter == S_TRUE) putchar(','); printf( _(" %s"), sh_unix_gmttime (p->theFile.atime)); if (ListWithDelimiter == S_TRUE) putchar(','); printf( _(" %s"), p->theFile.checksum); if (ListWithDelimiter == S_TRUE) putchar(','); tmp = sh_util_safe_name(p->fullpath); printf( _(" %s"), tmp); SH_FREE(tmp); if (ListWithDelimiter == S_TRUE) putchar(','); if ('l' == p->theFile.c_mode[0]) { tmp = sh_util_safe_name(p->linkpath); if (ListWithDelimiter == S_TRUE) printf(_(" %s\n"), tmp); else printf(_(" -> %s\n"), tmp); SH_FREE(tmp); } else printf("\n"); return; } void sh_hash_list_db_entry (sh_file_t * p) { char nowtime[128]; char thetime[128]; char * tmp; time_t now = time(NULL); time_t then = (time_t) p->theFile.mtime; strftime(thetime, 127, _("%b %d %Y"), gmtime(&then)); strftime(nowtime, 127, _("%b %d %Y"), gmtime(&now)); if (0 == strncmp(&nowtime[7], &thetime[7], 4)) strftime(thetime, 127, _("%b %d %H:%M"), gmtime(&then)); tmp = sh_util_safe_name(p->fullpath); if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0]) printf(_("%10s %3d %-8s %-8s %3d,%4d %s %s"), p->theFile.c_mode, (int) p->theFile.hardlinks, p->theFile.c_owner, p->theFile.c_group, (int) major((dev_t)p->theFile.rdev), (int) minor((dev_t)p->theFile.rdev), thetime, tmp); else printf(_("%10s %3d %-8s %-8s %8ld %s %s"), p->theFile.c_mode, (int) p->theFile.hardlinks, p->theFile.c_owner, p->theFile.c_group, (long) p->theFile.size, thetime, tmp); SH_FREE(tmp); if ('l' == p->theFile.c_mode[0]) { tmp = sh_util_safe_name(p->linkpath); printf(_(" -> %s\n"), tmp); SH_FREE(tmp); } else printf("\n"); return; } int sh_hash_list_db (char * db_file) { sh_file_t * p; SL_TICKET fd; char * line; if (!db_file) { _exit(EXIT_FAILURE); return -1; } if (sl_is_suid()) { fprintf(stderr, _("ERROR: insufficient privilege\n")); _exit (EXIT_FAILURE); return -1; /* for Mac OSX compiler */ } if (0 == strcmp(db_file, _("default"))) db_file = file_path('D', 'W'); if (!db_file) { _exit(EXIT_FAILURE); return -1; } line = SH_ALLOC(MAX_PATH_STORE+1); if ( SL_ISERROR(fd = sl_open_read(db_file, SL_YESPRIV))) { fprintf(stderr, _("ERROR: can't open %s for read (errnum = %ld)\n"), db_file, fd); _exit(EXIT_FAILURE); return -1; } /* fast forward to start of data */ sh_hash_setdataent(fd, line, MAX_PATH_STORE, db_file); while (1) { p = sh_hash_getdataent (fd, line, MAX_PATH_STORE); if ((p != NULL) && (p->fullpath[0] != 'K')) { if (ListFullDetail == S_FALSE) sh_hash_list_db_entry (p); else sh_hash_list_db_entry_full_detail (p); } else if (p == NULL) { break; } } if (line != NULL) SH_FREE(line); sl_close (fd); fflush(NULL); _exit(EXIT_SUCCESS); return 0; } /* if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */ #endif