/* aide, Advanced Intrusion Detection Environment * * Copyright (C) 1999-2007,2010-2013,2015,2016 Rami Lehti, Pablo Virolainen, * Richard van den Berg, Mike Markley, Hannes von Haugwitz * $Id$ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "aide.h" #include #include #include #include #include #ifdef WITH_AUDIT #include #ifdef HAVE_SYSLOG #include #endif #endif #include "base64.h" #include "report.h" #include "db_config.h" #include "gen_list.h" #include "list.h" #include "db.h" #include "util.h" #include "commandconf.h" #include "gen_list.h" #include "compare_db.h" /*for locale support*/ #include "locale-aide.h" /*for locale support*/ #include "md.h" /*************/ /* construction area for report lines */ const int width_details = 80; const char time_format[] = "%Y-%m-%d %H:%M:%S %z"; const int time_string_len = 26; long ntotal, nadd, nrem, nchg = 0; const char* report_top_format = "\n\n---------------------------------------------------\n%s:\n---------------------------------------------------\n"; DB_ATTR_TYPE ignored_added_attrs, ignored_removed_attrs, ignored_changed_attrs, forced_attrs; const DB_ATTR_TYPE summary_attributes[] = { DB_FTYPE, DB_LINKNAME, DB_SIZE|DB_SIZEG, DB_BCOUNT, DB_PERM, DB_UID, DB_GID, DB_ATIME, DB_MTIME, DB_CTIME, DB_INODE, DB_LNKCOUNT, DB_HASHES #ifdef WITH_ACL , DB_ACL #endif #ifdef WITH_XATTR , DB_XATTRS #endif #ifdef WITH_SELINUX , DB_SELINUX #endif #ifdef WITH_E2FSATTRS , DB_E2FSATTRS #endif }; const char summary_char[] = { '!' ,'l', '>', 'b', 'p', 'u', 'g', 'a', 'm', 'c', 'i', 'n', 'C' #ifdef WITH_ACL , 'A' #endif #ifdef WITH_XATTR , 'X' #endif #ifdef WITH_SELINUX , 'S' #endif #ifdef WITH_E2FSATTRS , 'E' #endif }; const DB_ATTR_TYPE details_attributes[] = { DB_FTYPE, DB_LINKNAME, DB_SIZE, DB_SIZEG, DB_BCOUNT, DB_PERM, DB_UID, DB_GID, DB_ATIME, DB_MTIME, DB_CTIME, DB_INODE, DB_LNKCOUNT, DB_MD5, DB_SHA1, DB_RMD160, DB_TIGER, DB_SHA256, DB_SHA512 #ifdef WITH_MHASH , DB_CRC32, DB_HAVAL, DB_GOST, DB_CRC32B, DB_WHIRLPOOL #endif #ifdef WITH_ACL , DB_ACL #endif #ifdef WITH_XATTR , DB_XATTRS #endif #ifdef WITH_SELINUX , DB_SELINUX #endif #ifdef WITH_E2FSATTRS , DB_E2FSATTRS #endif }; const char* details_string[] = { _("File type") , _("Lname"), _("Size"), _("Size"), _("Bcount"), _("Perm"), _("Uid"), _("Gid"), _("Atime"), _("Mtime"), _("Ctime"), _("Inode"), _("Linkcount"), _("MD5"), _("SHA1"), _("RMD160"), _("TIGER"), _("SHA256"), _("SHA512") #ifdef WITH_MHASH , _("CRC32"), _("HAVAL"), _("GOST"), _("CRC32B"), _("WHIRLPOOL") #endif #ifdef WITH_ACL , _("ACL") #endif #ifdef WITH_XATTR , _("XAttrs") #endif #ifdef WITH_SELINUX , _("SELinux") #endif #ifdef WITH_E2FSATTRS , _("E2FSAttrs") #endif }; const char* attrs_string[] = { "filename", "l", "p", "u", "g", "s", "a", "c", "m", "i", "b", "n", "md5", "sha1", "rmd160", "tiger", "crc32", "haval", "gost", "crc32b", "attr", "acl", "bsize", "rdev", "dev", "checkmask", "S", "I", "ANF", "ARF", "sha256", "sha512", "selinux", "xattrs", "whirlpool", "ftype", "e2fsattrs" }; #ifdef WITH_E2FSATTRS /* flag->character mappings taken from lib/e2p/pf.c (git commit c46b57b) * date: 2015-05-10 * sources: git://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git * * on update see also do_e2fsattrs in commandconf.c */ unsigned long flag_bits[] = { EXT2_SECRM_FL, EXT2_UNRM_FL, EXT2_SYNC_FL, EXT2_DIRSYNC_FL, EXT2_IMMUTABLE_FL, EXT2_APPEND_FL, EXT2_NODUMP_FL, EXT2_NOATIME_FL, EXT2_COMPR_FL, EXT2_COMPRBLK_FL, EXT2_DIRTY_FL, EXT2_NOCOMPR_FL, #ifdef EXT2_ECOMPR_FL EXT2_ECOMPR_FL, #else EXT4_ENCRYPT_FL, #endif EXT3_JOURNAL_DATA_FL, EXT2_INDEX_FL, EXT2_NOTAIL_FL, EXT2_TOPDIR_FL #ifdef EXT4_EXTENTS_FL , EXT4_EXTENTS_FL #endif #ifdef EXT4_HUGE_FILE_FL , EXT4_HUGE_FILE_FL #endif #ifdef FS_NOCOW_FL , FS_NOCOW_FL #endif #ifdef EXT4_INLINE_DATA_FL , EXT4_INLINE_DATA_FL #endif }; char flag_char[] = { 's', 'u', 'S', 'D', 'i', 'a', 'd', 'A', 'c', 'B', 'Z', 'X', 'E', 'j', 'I', 't', 'T' #ifdef EXT4_EXTENTS_FL , 'e' #endif #ifdef EXT4_HUGE_FILE_FL , 'h' #endif #ifdef FS_NOCOW_FL , 'C' #endif #ifdef EXT4_INLINE_DATA_FL , 'N' #endif }; /*************/ #endif static DB_ATTR_TYPE get_special_report_group(char* group) { DB_ATTR_TYPE attr = get_groupval(group); return attr==DB_ATTR_UNDEF?0:attr; } static char* report_attrs(DB_ATTR_TYPE attrs) { char* str; int j = 1; int num_attrs = sizeof(attrs_string)/sizeof(char*); for (int i = 0; i < num_attrs; ++i) { if ((1LLU<()!@#$%^&*|\\/?~" static int xattrs2array(xattrs_type* xattrs, char* **values) { int n = 0; if (xattrs==NULL) { n=1; } else { n=1+xattrs->num; } *values = malloc(n * sizeof(char*)); (*values)[0]=malloc((6+floor(log10(n)))*sizeof(char)); snprintf((*values)[0], 6+floor(log10(n)), "num=%d", n-1); if (n>1) { size_t num = 0; int width, length; width = log10(xattrs->num); /* make them the same width */ while (num++ < xattrs->num) { char *val = NULL; size_t len = 0; val = (char *)xattrs->ents[num - 1].val; len = xstrnspn(val, xattrs->ents[num - 1].vsz, PRINTABLE_XATTR_VALS); if ((len == xattrs->ents[num - 1].vsz) || ((len == (xattrs->ents[num - 1].vsz - 1)) && !val[len])) { length = 8 + width + strlen(xattrs->ents[num - 1].key) + strlen(val); (*values)[num]=malloc(length *sizeof(char)); char * fmt = "[%.*zd] %s = %s"; if (conf->syslog_format) fmt = "[%.*zd]%s=%s"; // its smaller so it has to be enough space allocated. snprintf((*values)[num], length , fmt, width, num, xattrs->ents[num - 1].key, val); } else { val = encode_base64(xattrs->ents[num - 1].val, xattrs->ents[num - 1].vsz); length = 10 + width + strlen(xattrs->ents[num - 1].key) + strlen(val); (*values)[num]=malloc( length *sizeof(char)); char * fmt = "[%.*zd] %s <=> %s"; if (conf->syslog_format) fmt = "[%.*zd]%s<=>%s"; // its smaller so it has to be enough space allocated. snprintf((*values)[num], length , fmt, width, num, xattrs->ents[num - 1].key, val); free(val); } } } return n; } #endif #ifdef WITH_ACL static int acl2array(acl_type* acl, char* **values) { int n = 0; #ifdef WITH_POSIX_ACL #define easy_posix_acl(x,y) \ if (acl->x) { \ i = k = 0; \ while (acl->x[i]) { \ if (acl->x[i]=='\n') { \ (*values)[j]=malloc(4+(i-k)*sizeof(char)); \ snprintf((*values)[j], 4+(i-k), "%c: %s", y, &acl->x[k]); \ j++; \ k=i+1; \ } \ i++; \ } \ } if (acl->acl_a || acl->acl_d) { int j, k, i; if (conf->syslog_format) { *values = malloc(2 * sizeof(char*)); char *A= "", *D = ""; if (acl->acl_a) { A = acl->acl_a; } if (acl->acl_d) { D = acl->acl_d; } (*values)[0] = (char*) malloc(strlen(A) + 3); // "A:" and \0 snprintf((*values)[0], strlen(A) + 3, "A:%s", A); (*values)[1] = (char*) malloc(strlen(D) + 3); // "D:" and \0 snprintf((*values)[1], strlen(D) + 3, "D:%s", D); i = 0; while ( (*values)[0][i] ) { if ( (*values)[0][i]=='\n') { (*values)[0][i] = ' '; } i++; } i = 0; while ( (*values)[1][i] ) { if ( (*values)[1][i]=='\n') { (*values)[1][i] = ' '; } i++; } return 2; } if (acl->acl_a) { i = 0; while (acl->acl_a[i]) { if (acl->acl_a[i++]=='\n') { n++; } } } if (acl->acl_d) { i = 0; while (acl->acl_d[i]) { if (acl->acl_d[i++]=='\n') { n++; } } } *values = malloc(n * sizeof(char*)); j = 0; easy_posix_acl(acl_a, 'A') easy_posix_acl(acl_d, 'D') } #endif #ifdef WITH_SUN_ACL /* FIXME: readd sun acl support */ #endif return n; } #endif #ifdef WITH_E2FSATTRS static char* e2fsattrs2string(unsigned long flags, int flags_only) { int length = sizeof(flag_bits)/sizeof(long); char* string = malloc ((length+1) * sizeof (char)); int j = 0; for (int i = 0 ; i < length ; i++) { if (!flags_only && flag_bits[i]&(conf->report_ignore_e2fsattrs)) { string[j++]=':'; } else if (flag_bits[i] & flags) { string[j++]=flag_char[i]; } else if (!flags_only) { string[j++]='-'; } } string[j] = '\0'; return string; } #endif static char* get_file_type_string(mode_t mode) { switch (mode & S_IFMT) { case S_IFREG: return conf->syslog_format ? "file" : _("File"); case S_IFDIR: return conf->syslog_format ? "dir" : _("Directory"); #ifdef S_IFIFO case S_IFIFO: return conf->syslog_format ? "fifo" : _("FIFO"); #endif case S_IFLNK: return conf->syslog_format ? "link" : _("Link"); case S_IFBLK: return conf->syslog_format ? "blockd" : _("Block device"); case S_IFCHR: return conf->syslog_format ? "chard" : _("Character device"); #ifdef S_IFSOCK case S_IFSOCK: return conf->syslog_format ? "socket" : _("Socket"); #endif #ifdef S_IFDOOR case S_IFDOOR: return conf->syslog_format ? "door" : _("Door"); #endif #ifdef S_IFPORT case S_IFPORT: return conf->syslog_format ? "port" : _("Port"); #endif case 0: return NULL; default: return conf->syslog_format ? "unknown" : _("Unknown file type"); } } static char* byte_to_base16(byte* src, size_t ssize) { char* str = malloc((2*ssize+1) * sizeof (char)); size_t i; for(i=0; i < ssize; ++i) { snprintf(&str[2*i], 3, "%02x", src[i]); } return str; } static int get_attribute_values(DB_ATTR_TYPE attr, db_line* line, char* **values) { #define easy_string(s) \ l = strlen(s)+1; \ *values[0] = malloc(l * sizeof (char)); \ snprintf(*values[0], l, "%s",s); #define easy_md(a,b,c) \ } else if (a&attr) { \ if (conf->report_base16) { \ *values[0] = byte_to_base16(line->b, c); \ } else { \ *values[0] = encode_base64(line->b, c); \ } #define easy_number(a,b,c) \ } else if (a&attr) { \ l = 2+floor(line->b?log10(line->b):0); \ *values[0] = malloc(l * sizeof (char)); \ snprintf(*values[0], l, c,line->b); #define easy_time(a,b) \ } else if (a&attr) { \ *values[0] = malloc(time_string_len * sizeof (char)); \ strftime(*values[0], time_string_len, time_format, localtime(&(line->b))); int l; if (line==NULL || !(line->attr&attr)) { *values = NULL; return 0; #ifdef WITH_ACL } else if (DB_ACL&attr) { return acl2array(line->acl, &*values); #endif #ifdef WITH_XATTR } else if (DB_XATTRS&attr) { return xattrs2array(line->xattrs, &*values); #endif } else { *values = malloc(1 * sizeof (char*)); if (DB_FTYPE&attr) { easy_string(get_file_type_string(line->perm)) } else if (DB_LINKNAME&attr) { easy_string(line->linkname) easy_number((DB_SIZE|DB_SIZEG),size,"%li") } else if (DB_PERM&attr) { *values[0] = perm_to_char(line->perm); easy_time(DB_ATIME,atime) easy_time(DB_MTIME,mtime) easy_time(DB_CTIME,ctime) easy_number(DB_BCOUNT,bcount,"%li") easy_number(DB_UID,uid,"%i") easy_number(DB_GID,gid,"%i") easy_number(DB_INODE,inode,"%lu") easy_number(DB_LNKCOUNT,nlink,"%lu") easy_md(DB_MD5,md5,HASH_MD5_LEN) easy_md(DB_SHA1,sha1,HASH_SHA1_LEN) easy_md(DB_RMD160,rmd160,HASH_RMD160_LEN) easy_md(DB_TIGER,tiger,HASH_TIGER_LEN) easy_md(DB_SHA256,sha256,HASH_SHA256_LEN) easy_md(DB_SHA512,sha512,HASH_SHA512_LEN) #ifdef WITH_MHASH easy_md(DB_CRC32,crc32,HASH_CRC32_LEN) easy_md(DB_HAVAL,haval,HASH_HAVAL256_LEN) easy_md(DB_GOST,gost,HASH_GOST_LEN) easy_md(DB_CRC32B,crc32b,HASH_CRC32B_LEN) easy_md(DB_WHIRLPOOL,whirlpool,HASH_WHIRLPOOL_LEN) #endif #ifdef WITH_SELINUX } else if (DB_SELINUX&attr) { easy_string(line->cntx) #endif #ifdef WITH_E2FSATTRS } else if (DB_E2FSATTRS&attr) { *values[0]=e2fsattrs2string(line->e2fsattrs, 0); #endif } else { easy_string("unknown attribute") } return 1; } } static void print_line(seltree* node) { if(conf->summarize_changes==1) { int i; int length = sizeof(summary_attributes)/sizeof(DB_ATTR_TYPE); char* summary = malloc ((length+1) * sizeof (char)); if (node->checked&(NODE_ADDED|NODE_REMOVED)) { summary[0]=get_file_type_char((node->checked&NODE_REMOVED?node->old_data:node->new_data)->perm); for(i=1;ichecked&NODE_ADDED?'+':'-'; } } else if (node->checked&NODE_CHANGED) { char c, u, a, r, g, s; for(i=0;inew_data)->perm); continue; case 2: if (summary_attributes[i]&(node->changed_attrs&(~ignored_changed_attrs)) && (node->old_data)->size > (node->new_data)->size) { c = '<'; } u = '='; break; } if (summary_attributes[i]&node->changed_attrs&(forced_attrs|(~ignored_changed_attrs))) { summary[i]=c; } else if (summary_attributes[i]&((node->old_data)->attr&~((node->new_data)->attr)&(forced_attrs|~(ignored_removed_attrs)))) { summary[i]=r; } else if (summary_attributes[i]&~((node->old_data)->attr)&(node->new_data)->attr&(forced_attrs|~(ignored_added_attrs))) { summary[i]=a; } else if (summary_attributes[i]& ( (((node->old_data)->attr&~((node->new_data)->attr)&ignored_removed_attrs))| (~((node->old_data)->attr)&(node->new_data)->attr&ignored_added_attrs)| (((node->old_data)->attr&(node->new_data)->attr)&ignored_changed_attrs) ) ) { summary[i]=g; } else if (summary_attributes[i]&((node->old_data)->attr&(node->new_data)->attr)) { summary[i]=u; } else { summary[i]=s; } } } summary[length]='\0'; error(2,"\n%s: %s", summary, (node->checked&NODE_REMOVED?node->old_data:node->new_data)->filename); free(summary); summary=NULL; } else { if (node->checked&NODE_ADDED) { error(2,"added: %s\n",(node->new_data)->filename); } else if (node->checked&NODE_REMOVED) { error(2,"removed: %s\n",(node->old_data)->filename); } else if (node->checked&NODE_CHANGED) { error(2,"changed: %s\n",(node->new_data)->filename); } } } static void print_dbline_attributes(db_line* oline, db_line* nline, DB_ATTR_TYPE changed_attrs, DB_ATTR_TYPE force_attrs) { char **ovalue, **nvalue; int onumber, nnumber, olen, nlen, i, j, k, c; int length = sizeof(details_attributes)/sizeof(DB_ATTR_TYPE); int p = (width_details-(width_details%2?13:14))/2; DB_ATTR_TYPE attrs; error(2,"\n"); char *file_type = get_file_type_string((nline==NULL?oline:nline)->perm); if (file_type) { error(2,"%s: ", file_type); } error(2,"%s\n", (nline==NULL?oline:nline)->filename); attrs=force_attrs|(~(ignored_changed_attrs)&changed_attrs); for (j=0; j < length; ++j) { if (details_attributes[j]&attrs) { onumber=get_attribute_values(details_attributes[j], oline, &ovalue); nnumber=get_attribute_values(details_attributes[j], nline, &nvalue); i = 0; while (i= 0 || nlen-p*k >= 0) { c = k*(p-1); if (!onumber) { error(2," %s%-9s%c %-*c %.*s\n", width_details%2?"":" ", i+k?"":details_string[j], i+k?' ':':', p, ' ', p-1, nlen-c>0?&nvalue[i][c]:""); } else if (!nnumber) { error(2," %s%-9s%c %.*s\n", width_details%2?"":" ", i+k?"":details_string[j], i+k?' ':':', p-1, olen-c>0?&ovalue[i][c]:""); } else { error(2," %s%-9s%c %-*.*s| %.*s\n", width_details%2?"":" ", i+k?"":details_string[j], i+k?' ':':', p, p-1, olen-c>0?&ovalue[i][c]:"", p-1, nlen-c>0?&nvalue[i][c]:""); } k++; } ++i; } for(i=0; i < onumber; ++i) { free(ovalue[i]); ovalue[i]=NULL; } free(ovalue); ovalue=NULL; for(i=0; i < nnumber; ++i) { free(nvalue[i]); nvalue[i]=NULL; } free(nvalue); nvalue=NULL; } } } static void print_dbline_attributes_syslog(db_line* oline, db_line* nline, DB_ATTR_TYPE changed_attrs, DB_ATTR_TYPE force_attrs) { char **ovalue, **nvalue; int onumber, nnumber, i, j; int length = sizeof(details_attributes)/sizeof(DB_ATTR_TYPE); DB_ATTR_TYPE attrs; char *file_type = get_file_type_string((nline==NULL?oline:nline)->perm); if (file_type) { error(0,"%s=", file_type); } error(0,"%s", (nline==NULL?oline:nline)->filename); attrs=force_attrs|(~(ignored_changed_attrs)&changed_attrs); for (j=0; j < length; ++j) { if (details_attributes[j]&attrs) { onumber=get_attribute_values(details_attributes[j], oline, &ovalue); nnumber=get_attribute_values(details_attributes[j], nline, &nvalue); if (details_attributes[j] == DB_ACL || details_attributes[j] == DB_XATTRS) { error(0, ";%s_old=|", details_string[j]); for (i = 0 ; i < onumber ; i++) { error(0, "%s|", ovalue[i]); } error(0, ";%s_new=|", details_string[j]); for (i = 0 ; i < nnumber ; i++) { error(0, "%s|", nvalue[i]); } } else { error(0, ";%s_old=%s;%s_new=%s", details_string[j], *ovalue, details_string[j], *nvalue); } for(i=0; i < onumber; ++i) { free(ovalue[i]); ovalue[i]=NULL; } free(ovalue); ovalue=NULL; for(i=0; i < nnumber; ++i) { free(nvalue[i]); nvalue[i]=NULL; } free(nvalue); nvalue=NULL; } } error(0, "\n"); } static void print_attributes_added_node(db_line* line) { print_dbline_attributes(NULL, line, 0, line->attr); } static void print_attributes_removed_node(db_line* line) { print_dbline_attributes(line, NULL, 0, line->attr); } static void print_attributes_added_node_syslog(db_line* line) { char *file_type = get_file_type_string(line->perm); if (file_type) { error(0,"%s=", file_type); } error(0,"%s; added\n", line->filename); } static void print_attributes_removed_node_syslog(db_line* line) { char *file_type = get_file_type_string(line->perm); if (file_type) { error(0,"%s=", file_type); } error(0,"%s; removed\n", line->filename); } static void terse_report(seltree* node) { list* r=NULL; if ((node->checked&(DB_OLD|DB_NEW)) != 0) { ntotal += ((node->checked&DB_NEW) != 0); if (!(node->checked&DB_OLD)){ /* File is in new db but not old. (ADDED) */ /* unless it was moved in */ if (!((node->checked&NODE_ALLOW_NEW)||(node->checked&NODE_MOVED_IN))) { nadd++; node->checked|=NODE_ADDED; } } else if (!(node->checked&DB_NEW)){ /* File is in old db but not new. (REMOVED) */ /* unless it was moved out */ if (!((node->checked&NODE_ALLOW_RM)||(node->checked&NODE_MOVED_OUT))) { nrem++; node->checked|=NODE_REMOVED; } } else if ((node->old_data!=NULL)&&(node->new_data!=NULL)){ /* File is in both db's and the data is still there. (CHANGED) */ if (!(node->checked&(NODE_MOVED_IN|NODE_MOVED_OUT))){ nchg++; node->checked|=NODE_CHANGED; }else if (!((node->checked&NODE_ALLOW_NEW)||(node->checked&NODE_MOVED_IN))) { nadd++; node->checked|=NODE_ADDED; }else if (!((node->checked&NODE_ALLOW_RM)||(node->checked&NODE_MOVED_OUT))) { nrem++; node->checked|=NODE_REMOVED; } } } for (r=node->childs;r;r=r->next) { terse_report((seltree*)r->data); } } static void print_report_list(seltree* node, const int node_status) { list* r=NULL; if (node->checked&node_status) { print_line(node); } for(r=node->childs;r;r=r->next){ print_report_list((seltree*)r->data, node_status); } } static void print_report_details(seltree* node) { list* r=NULL; if (conf->verbose_level>=5) { if (node->checked&NODE_CHANGED) { print_dbline_attributes(node->old_data, node->new_data, node->changed_attrs, (conf->verbose_level>=6?( ((node->old_data)->attr&~((node->new_data)->attr)&~(ignored_removed_attrs))|(~((node->old_data)->attr)&(node->new_data)->attr&~(ignored_added_attrs)) ):0)|forced_attrs); } else if ((conf->verbose_level>=7)) { if (node->checked&NODE_ADDED) { print_attributes_added_node(node->new_data); } if (node->checked&NODE_REMOVED) { print_attributes_removed_node(node->old_data); } } } for(r=node->childs;r;r=r->next){ print_report_details((seltree*)r->data); } } static void print_syslog_format(seltree* node) { list* r=NULL; if (node->checked&NODE_CHANGED) { print_dbline_attributes_syslog(node->old_data, node->new_data, node->changed_attrs, forced_attrs); } if (node->checked&NODE_ADDED) { print_attributes_added_node_syslog(node->new_data); } if (node->checked&NODE_REMOVED) { print_attributes_removed_node_syslog(node->old_data); } for(r=node->childs;r;r=r->next){ print_syslog_format((seltree*)r->data); } } static void print_report_header() { char *time; int first = 1; time = malloc(time_string_len * sizeof (char)); strftime(time, time_string_len, time_format, localtime(&(conf->start_time))); error(2,_("Start timestamp: %s (AIDE " AIDEVERSION ")\n"), time); free(time); time=NULL; error(0,_("AIDE")); if(conf->action&(DO_COMPARE|DO_DIFF)) { error(0,_(" found %sdifferences between %s%s!!\n"), (nadd||nrem||nchg)?"":"NO ", conf->action&DO_COMPARE?_("database and filesystem"):_("the two databases"), (nadd||nrem||nchg)?"":_(". Looks okay")); if(conf->action&(DO_INIT)) { error(0,_("New AIDE database written to %s\n"),conf->db_out_url->value); } } else { error(0,_(" initialized database at %s\n"),conf->db_out_url->value); } if(conf->config_version) error(2,_("Config version used: %s\n"),conf->config_version); if (conf->limit != NULL) { error (2,_("Limit: %s"), conf->limit); first = 0; } if (conf->action&(DO_INIT|DO_COMPARE) && conf->root_prefix_length > 0) { if (first) { first=0; } else { error (2," | "); } error (2,_("Root prefix: %s"),conf->root_prefix); } if (conf->verbose_level != 5) { if (first) { first=0; } else { error (2," | "); } error (2,_("Verbose level: %d"), conf->verbose_level); } if (!first) { error (2,"\n"); } if (ignored_added_attrs) { error (2,_("Ignored added attributes: %s\n"),report_attrs(ignored_added_attrs)); } if (ignored_removed_attrs) { error (2,_("Ignored removed attributes: %s\n"),report_attrs(ignored_removed_attrs)); } if (ignored_changed_attrs) { error (2,_("Ignored changed attributes: %s\n"),report_attrs(ignored_changed_attrs)); } if (forced_attrs) { error (2,_("Forced attributes: %s\n"),report_attrs(forced_attrs)); } #ifdef WITH_E2FSATTRS if (conf->report_ignore_e2fsattrs) { error (2,_("Ignored e2fs attributes: %s\n"), e2fsattrs2string(conf->report_ignore_e2fsattrs, 1) ); } #endif if(conf->action&(DO_COMPARE|DO_DIFF) && (nadd||nrem||nchg)) { error(0,_("\nSummary:\n Total number of entries:\t%li\n Added entries:\t\t%li\n" " Removed entries:\t\t%li\n Changed entries:\t\t%li"), ntotal, nadd, nrem, nchg); } else { error(0,_("\nNumber of entries:\t%li"), ntotal); } } static void print_report_databases() { if (conf->verbose_level>=2 && (conf->line_db_in || conf->line_db_out)) { error(2,(char*)report_top_format,_("The attributes of the (uncompressed) database(s)")); if (conf->line_db_in) { print_attributes_removed_node(conf->line_db_in); } if (conf->line_db_out) { print_attributes_removed_node(conf->line_db_out); } } } static void print_report_footer() { char *time = malloc(time_string_len * sizeof (char)); int run_time = (int) difftime(conf->end_time, conf->start_time); strftime(time, time_string_len, time_format, localtime(&(conf->end_time))); error(2,_("\n\nEnd timestamp: %s (run time: %dm %ds)\n"), time, run_time/60, run_time%60); free(time); time=NULL; } #ifdef WITH_AUDIT /* Something changed, send audit anomaly message */ void send_audit_report() { if(nadd!=0||nrem!=0||nchg!=0){ int fd=audit_open(); if (fd>=0){ char msg[64]; snprintf(msg, sizeof(msg), "added=%ld removed=%ld changed=%ld", nadd, nrem, nchg); if (audit_log_user_message(fd, AUDIT_ANOM_RBAC_INTEGRITY_FAIL, msg, NULL, NULL, NULL, 0)<=0) #ifdef HAVE_SYSLOG syslog(LOG_ERR, "Failed sending audit message:%s", msg); #else ; #endif close(fd); } } } #endif /* WITH_AUDIT */ int gen_report(seltree* node) { forced_attrs = get_special_report_group("report_force_attrs"); ignored_added_attrs = get_special_report_group("report_ignore_added_attrs"); ignored_removed_attrs = get_special_report_group("report_ignore_removed_attrs"); ignored_changed_attrs = get_special_report_group("report_ignore_changed_attrs"); terse_report(node); #ifdef WITH_AUDIT send_audit_report(); #endif if ((nadd|nrem|nchg) > 0 || conf->report_quiet == 0) { if (!conf->syslog_format) { print_report_header(); } if(conf->action&(DO_COMPARE|DO_DIFF) || (conf->action&DO_INIT && conf->report_detailed_init) ) { if (!conf->syslog_format && conf->grouped) { if (nadd) { error(2,(char*)report_top_format,_("Added entries")); print_report_list(node, NODE_ADDED); } if (nrem) { error(2,(char*)report_top_format,_("Removed entries")); print_report_list(node, NODE_REMOVED); } if (nchg) { error(2,(char*)report_top_format,_("Changed entries")); print_report_list(node, NODE_CHANGED); } } else if (!conf->syslog_format && ( nadd || nrem || nchg ) ) { if (nadd && nrem && nchg) { error(2,(char*)report_top_format,_("Added, removed and changed entries")); } else if (nadd && nrem) { error(2,(char*)report_top_format,_("Added and removed entries")); } else if (nadd && nchg) { error(2,(char*)report_top_format,_("Added and changed entries")); } else if (nrem && nchg) { error(2,(char*)report_top_format,_("Removed and changed entries")); } else if (nadd) { error(2,(char*)report_top_format,_("Added entries")); } else if (nrem) { error(2,(char*)report_top_format,_("Removed entries")); } else if (nchg) { error(2,(char*)report_top_format,_("Changed entries")); } print_report_list(node, NODE_ADDED|NODE_REMOVED|NODE_CHANGED); } if (nadd || nrem || nchg) { if (!conf->syslog_format) { error(nchg?5:7,(char*)report_top_format,_("Detailed information about changes")); print_report_details(node); } else { /* Syslog Format */ error(0, "AIDE found differences between database and filesystem!!\n"); error(0, "summary;total_number_of_files=%ld;added_files=%ld;" "removed_files=%ld;changed_files=%ld\n",ntotal,nadd,nrem,nchg); print_syslog_format(node); } } } if (!conf->syslog_format) { print_report_databases(); conf->end_time=time(&(conf->end_time)); print_report_footer(); } } return conf->action&(DO_COMPARE|DO_DIFF) ? (nadd!=0)*1+(nrem!=0)*2+(nchg!=0)*4 : 0; } const char* aide_key_9=CONFHMACKEY_09; const char* db_key_9=DBHMACKEY_09; // vi: ts=8 sw=8