diff --git a/ChangeLog b/ChangeLog index 7f08d55..57b5da9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,52 @@ +2013-05-20 Hannes von Haugwitz + * Print checksums of databases in verbose level 2 or higher (closes + feature request 1502032) + * Added new 'database_attrs' option + * configure.in: fixed compilation with selinux + * src/conf_lex.l, src/db_lex.l: fixed definition of YYDEBUG + +2013-05-18 Hannes von Haugwitz + * configure.in: removed check for 'libcrypt' + * Renamed 'detailed_init_report' option to 'report_detailed_init' + +2013-05-17 Hannes von Haugwitz + * configure.in: + - fixed "suspicious cache-id" warnings + - removed 'AC_CONFIG_MACRO_DIR' macro + * src/Makefile.am: + - replaced INCLUDES with AM_CPPFLAGS + +2013-05-16 Hannes von Haugwitz + * Handle tilde (~) in database paths and report urls + * src/compare_db.c: adjusted report layout + +2013-05-14 Hannes von Haugwitz + * src/db.c: fixed segfault when dbconf->db_out is NULL + * Replaced fopen.c with the version from curl-7.30.0 + +2013-05-08 Hannes von Haugwitz + * src/compare_db.c: + - fixed output of checksums + - use size_t as the type of for loop variable + +2013-05-06 Hannes von Haugwitz + * src/compare_db.c: + - fixed return value of database initialization + - minor code cleanup + * src/db_file.c, src/do_md.c: + - fixed use of unportable %m format + * doc/aide.1.in: + - fixed format in NOTES section + - documented return value of '--compare' and '--update' command + +2013-05-04 Hannes von Haugwitz + * src/compare_db.c: + - changed minimum verbose level for printing the details + about added and removed entries to 7 + * README: + - updated "Source Code Verification" section + * Released version 0.16a2 + 2012-10-10 Hannes von Haugwitz * Added new default group X * src/gen_list.c: fixed stripping of removed attributes diff --git a/NEWS b/NEWS index 379fd6f..4aeed98 100644 --- a/NEWS +++ b/NEWS @@ -2,14 +2,16 @@ Version 0.16 (NOT_YET_RELEASED) * Enabled summarize_changes by default * Compare database entries just once * Added new root_prefix option - * Added new detailed_init_report option + * Added new database_attrs option + * Added new report_detailed_init option * Added new report_base16 option * Wrap attribute values instead of cut them off * Side-by-side output of acl and xattrs values * Use '|' to separate the old value from the new one + * Print checksums of databases in verbose level 2 or higher * Print added or removed attributes of changed entries if forced via report_attributes - * Print details about added and removed entries in verbose level 6 + * Print details about added and removed entries in verbose level 7 or higher * Print added and removed attribute values of changed entries in verbose level 6 or higher @@ -22,6 +24,7 @@ Version 0.16 (NOT_YET_RELEASED) * Added info about number of entries if aide found no changes or the database has been initialized * Added new default group X + * Handle tilde (~) in database paths and report urls * Bug fixes Version 0.15.1 diff --git a/README b/README index 933ae6d..b90e445 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ AIDE - Advanced Intrusion Detection Environment ------------------------------------------------- - Version 0.16a1 + Version 0.16a2 This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without @@ -86,17 +86,16 @@ $ git verify-tag v - The key used to create this signature is: + The current public key needed for signature verification is: - pub 4096R/F4474E5A 2011-01-30 [expires: 2012-01-31] - uid Aide Developers + pub 4096R/68E7B931 2011-06-28 [expires: 2017-06-26] + uid Hannes von Haugwitz - If you do not have this key, you can get it from the SourceForge - web site or from one of the well known PGP key servers. You have - to make sure that the key you install is not a faked one. You can - do this with reasonable assurance by comparing the output of: + If you do not have this key, you can get it from one of the well known PGP + key servers. You have to make sure that the key you install is not a faked + one. You can do this with reasonable assurance by comparing the output of: - $ gpg --fingerprint 0xF4474E5A + $ gpg --fingerprint 0x68E7B931 with the fingerprint published elsewhere. diff --git a/configure.in b/configure.in index 0f786de..25f2b21 100644 --- a/configure.in +++ b/configure.in @@ -2,7 +2,6 @@ m4_include([version.m4]) dnl Initialize autoconf/automake AC_INIT(aide, AIDE_VERSION) -dnl AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE @@ -10,7 +9,7 @@ AC_DEFINE_UNQUOTED(AIDEVERSION, "AIDE_VERSION") AH_TEMPLATE([AIDEVERSION], [package version]) dnl The name of the configure h-file. -AC_CONFIG_HEADERS([config.h]) +AM_CONFIG_HEADER(config.h) dnl Checks for programs. AC_PROG_CC @@ -465,15 +464,26 @@ AC_ARG_WITH([selinux], ) AS_IF([test "x$with_selinux_support" != xno], - [AC_DEFINE(WITH_SELINUX,1,[use SELinux]) - if test -n "$PKG_CONFIG" && $PKG_CONFIG --exists libselinux; then - SELINUXLIB=$(${PKG_CONFIG} --libs libselinux --static) - else - SELINUXLIB="-lselinux" - fi + AC_DEFINE(WITH_SELINUX,1,[use SELinux]) + [AC_MSG_RESULT(yes) + if test -n "$PKG_CONFIG" && $PKG_CONFIG --exists libselinux; then + if test "$aide_static_choice" == "yes"; then + SELINUXLIB=$(${PKG_CONFIG} --libs libselinux --static) + else + SELINUXLIB=$(${PKG_CONFIG} --libs libselinux) + fi + else + SELINUXLIB="-lselinux" + if test "$aide_static_choice" == "yes"; then + saveLIBS=$LIBS + LIBS="-static $SELINUXLIB" + AC_SEARCH_LIBS([lgetfilecon_raw], [], [], [SELINUXLIB="$SELINUXLIB -lpthread"]) + LIBS=$saveLIBS + fi + fi compoptionstring="${compoptionstring}WITH_SELINUX\\n" aideextragroups="${aideextragroups}+selinux" - AC_MSG_RESULT(yes)], + ], [AC_MSG_RESULT(no)] ) @@ -591,22 +601,24 @@ AC_CHECK_FUNC(lstat64, saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $AIDE_DEFS" -AC_CACHE_CHECK([for LFS ino_t],AIDE_INO_TYPE,[ +AC_CACHE_CHECK([for LFS ino_t],ac_cv_ino_type,[ AC_TRY_RUN([ #include #include #include #include main() { struct stat64 st; ino64_t s; if (sizeof(ino_t) == sizeof(ino64_t)) exit(1); exit((lstat64("/dev/null", &st)==0)?0:1); }], -AIDE_INO_TYPE=ino64_t,AIDE_INO_TYPE=ino_t,AIDE_INO_TYPE=cross)]) +ac_cv_ino_type=ino64_t,ac_cv_ino_type=ino_t,ac_cv_ino_type=cross)]) +AIDE_INO_TYPE=$ac_cv_ino_type -AC_CACHE_CHECK([for LFS dirent],AIDE_DIRENT_TYPE,[ +AC_CACHE_CHECK([for LFS dirent],ac_cv_dirent_type,[ AC_TRY_COMPILE([ #include #include #include ], [struct dirent64 de;], -AIDE_DIRENT_TYPE=dirent64,AIDE_DIRENT_TYPE=dirent)]) +ac_cv_dirent_type=dirent64,ac_cv_dirent_type=dirent)]) +AIDE_DIRENT_TYPE=$ac_cv_dirent_type else AIDE_LSTAT_FUNC="lstat" AIDE_STAT_FUNC="stat" @@ -926,9 +938,6 @@ AC_ARG_WITH(initial_errors_to, AC_DEFINE_UNQUOTED(INITIALERRORSTO,"stderr",[send errors to stderr]) ) - -AC_CHECK_LIB(c, crypt, [true], AC_CHECK_LIB(crypt, crypt)) - AC_MSG_CHECKING(for PostgresSQL support) AC_ARG_WITH([psql], [AC_HELP_STRING([--with-psql], diff --git a/doc/aide.1.in b/doc/aide.1.in index 99e8bf1..23aa9b0 100644 --- a/doc/aide.1.in +++ b/doc/aide.1.in @@ -54,7 +54,9 @@ Prints out the standard help message. .PP .SH DIAGNOSTICS Normally, the exit status is 0 if no errors occurred. Except when the -.B --check +.BR --check, +.BR --compare " or" +.B --update command was requested, in which case the exit status is defined as: .IP "1 * (new files detected?) +" .IP "2 * (removed files detected?) +" @@ -77,7 +79,7 @@ The checksums in the database and in the output are by default base64 encoded (see also report_base16 option). To decode them you can use the following shell command: -echo | base64 -d | hexdump -v -e '32/1 "%02x" "\\n"' +echo | base64 \-d | hexdump \-v \-e '32/1 "%02x" "\\n"' .PP .SH FILES diff --git a/doc/aide.conf.5.in b/doc/aide.conf.5.in index ab578f2..a68d18b 100644 --- a/doc/aide.conf.5.in +++ b/doc/aide.conf.5.in @@ -38,6 +38,14 @@ first is used. The default value is "@prefix@/etc/aide.db.new". .IP "database_new" The url from which the other database for \-\-compare is read. There is no default for this one. +.IP "database_attrs" +The attributes of the (uncompressed) database files which are to be added to +the final report in verbose level 2 or higher. Only checksum attributes are +supported. To disable set +.I database_attrs +to +.RB ' E '. +By default all compiled in checksums are added to the report. .IP "verbose" The level of messages that is output. This value can be 0-255 inclusive. This parameter can only be given once. Value from the first @@ -52,7 +60,7 @@ stdout. Whether to base16 encode the checksums in the report or not. Valid values are yes, true, no and false. The default is to report checksums not in base16 but in base64 encoding. -.IP "detailed_init_report" +.IP "report_detailed_init" Whether to report added files (verbose level >= 2) and their details (verbose level >=6) in initialization mode or not. Valid values are yes, true, no and false. The default is to not report added files or their details in init mode. diff --git a/doc/manual.html b/doc/manual.html index c03f70b..1bf1238 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,5 +1,5 @@ -AIDE Manual version 0.16a1 +AIDE Manual version 0.16a2 diff --git a/include/db.h b/include/db.h index 077c38f..8c684f1 100644 --- a/include/db.h +++ b/include/db.h @@ -1,7 +1,7 @@ /* aide, Advanced Intrusion Detection Environment * - * Copyright (C) 1999-2002,2004,2005 Rami Lehti, Pablo Virolainen, - * Richard van den Berg + * Copyright (C) 1999-2002,2004,2005,2013 Rami Lehti, Pablo Virolainen, + * Richard van den Berg, Hannes von Haugwitz * $Header$ * * This program is free software; you can redistribute it and/or @@ -33,7 +33,7 @@ int db_writespec(db_config*); int db_writeline(db_line*,db_config*); -int db_close(db_config*); +void db_close(); void free_db_line(db_line* dl); diff --git a/include/db_config.h b/include/db_config.h index e0a46ce..79a2ae6 100644 --- a/include/db_config.h +++ b/include/db_config.h @@ -1,6 +1,6 @@ /* aide, Advanced Intrusion Detection Environment * - * Copyright (C) 1999-2002,2004-2006,2010-2012 Rami Lehti, Pablo Virolainen, + * Copyright (C) 1999-2002,2004-2006,2010-2013 Rami Lehti, Pablo Virolainen, * Richard van den Berg, Hannes von Haugwitz * $Header$ * @@ -252,6 +252,52 @@ extern const int db_aliasvalue[db_alias_size]; #include "seltree.h" +typedef struct db_line { + byte* md5; + byte* sha1; + byte* rmd160; + byte* tiger; + + byte* sha256; + byte* sha512; + + byte* crc32; /* MHASH only */ + byte* haval; + byte* gost; + byte* crc32b; + byte* whirlpool; + + acl_type* acl; + /* Something here.. */ + + mode_t perm; + mode_t perm_o; /* Permission for tree traverse */ + uid_t uid; + gid_t gid; + time_t atime; + time_t ctime; + time_t mtime; + AIDE_INO_TYPE inode; + nlink_t nlink; + + AIDE_OFF_TYPE size; + AIDE_OFF_TYPE size_o; /* ... */ + AIDE_BLKCNT_TYPE bcount; + char* filename; + char* fullpath; + char* linkname; + + char *cntx; + + xattrs_type* xattrs; + + unsigned long e2fsattrs; + + /* Attributes .... */ + DB_ATTR_TYPE attr; + +} db_line; + typedef struct db_config { url_t* db_in_url; @@ -265,6 +311,14 @@ typedef struct db_config { int config_check; + struct md_container *mdc_in; + struct md_container *mdc_out; + + struct db_line *line_db_in; + struct db_line *line_db_out; + + DB_ATTR_TYPE db_attrs; + #ifdef WITH_ZLIB gzFile db_gzin; gzFile db_gznew; @@ -309,7 +363,7 @@ typedef struct db_config { list* negrxlst; int verbose_level; - int detailed_init_report; + int report_detailed_init; int report_base16; int use_initial_errorsto; @@ -360,52 +414,6 @@ typedef struct db_config { } db_config; -typedef struct db_line { - byte* md5; - byte* sha1; - byte* rmd160; - byte* tiger; - - byte* sha256; - byte* sha512; - - byte* crc32; /* MHASH only */ - byte* haval; - byte* gost; - byte* crc32b; - byte* whirlpool; - - acl_type* acl; - /* Something here.. */ - - mode_t perm; - mode_t perm_o; /* Permission for tree traverse */ - uid_t uid; - gid_t gid; - time_t atime; - time_t ctime; - time_t mtime; - AIDE_INO_TYPE inode; - nlink_t nlink; - - AIDE_OFF_TYPE size; - AIDE_OFF_TYPE size_o; /* ... */ - AIDE_BLKCNT_TYPE bcount; - char* filename; - char* fullpath; - char* linkname; - - char *cntx; - - xattrs_type* xattrs; - - unsigned long e2fsattrs; - - /* Attributes .... */ - DB_ATTR_TYPE attr; - -} db_line; - #ifdef WITH_PSQL #include "libpq-fe.h" diff --git a/include/fopen.h b/include/fopen.h index 26ad1a6..5682d09 100644 --- a/include/fopen.h +++ b/include/fopen.h @@ -1,39 +1,46 @@ -#include "aide.h" +/* see src/fopen.c for copyright information */ -#ifdef WITH_CURL +#ifndef _FOPEN_H_INCLUDED +#define _FOPEN_H_INCLUDED #include #include -#include +#ifndef WIN32 +# include +#endif #include #include #include -enum fcurl_type_e { CFTYPE_NONE=0, CFTYPE_FILE=1, CFTYPE_CURL=2 }; +enum fcurl_type_e { + CFTYPE_NONE=0, + CFTYPE_FILE=1, + CFTYPE_CURL=2 +}; struct fcurl_data { - enum fcurl_type_e type; /* type of handle */ - union { - CURL *curl; - FILE *file; - } handle; /* handle */ - - char *buffer; /* buffer to store cached data*/ - int buffer_len; /* currently allocated buffers length */ - int buffer_pos; /* end of data in buffer*/ - int still_running; /* Is background url fetch still in progress */ + enum fcurl_type_e type; /* type of handle */ + union { + CURL *curl; + FILE *file; + } handle; /* handle */ + + char *buffer; /* buffer to store cached data*/ + size_t buffer_len; /* currently allocated buffers length */ + size_t buffer_pos; /* end of data in buffer*/ + int still_running; /* Is background url fetch still in progress */ }; typedef struct fcurl_data URL_FILE; /* exported functions */ -URL_FILE *url_fopen(char *url,const char *operation); +URL_FILE *url_fopen(const char *url,const char *operation); int url_fclose(URL_FILE *file); int url_feof(URL_FILE *file); size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file); -char * url_fgets(char *ptr, int size, URL_FILE *file); +char * url_fgets(char *ptr, size_t size, URL_FILE *file); void url_rewind(URL_FILE *file); -#endif +#endif /* _FOPEN_H_INCLUDED */ diff --git a/include/util.h b/include/util.h index 8184e4a..7998853 100644 --- a/include/util.h +++ b/include/util.h @@ -1,7 +1,7 @@ /* aide, Advanced Intrusion Detection Environment * - * Copyright (C) 1999-2002,2006 Rami Lehti, Pablo Virolainen, Richard - * van den Berg + * Copyright (C) 1999-2002,2006,2013 Rami Lehti, Pablo Virolainen, Richard + * van den Berg, Hannes von Haugwitz * $Header$ * * This program is free software; you can redistribute it and/or @@ -54,6 +54,8 @@ void sig_handler(int signal); void init_sighandler(void); +char *expand_tilde(char * path); + #ifndef HAVE_STRNSTR char* strnstr(char* haystack,char* needle,int n); #endif diff --git a/src/Makefile.am b/src/Makefile.am index b595079..e7beb24 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,8 +30,10 @@ AM_CFLAGS = @AIDE_DEFS@ -W -Wall -g CLEANFILES = conf_yacc.h conf_yacc.c conf_lex.c db_lex.c *~ -INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/src \ - -I$(top_builddir)/src +AM_CPPFLAGS = -I$(top_srcdir) \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src aide_SOURCES = aide.c \ base64.c \ diff --git a/src/aide.c b/src/aide.c index 46181ea..c32be69 100644 --- a/src/aide.c +++ b/src/aide.c @@ -1,6 +1,6 @@ /* aide, Advanced Intrusion Detection Environment * - * Copyright (C) 1999-2006,2010-2012 Rami Lehti, Pablo Virolainen, Mike + * Copyright (C) 1999-2006,2010-2013 Rami Lehti, Pablo Virolainen, Mike * Markley, Richard van den Berg, Hannes von Haugwitz * $Header$ * @@ -269,7 +269,7 @@ static void setdefaults_before_config() conf->tree=NULL; conf->config_check=0; conf->verbose_level=-1; - conf->detailed_init_report=0; + conf->report_detailed_init=0; conf->report_base16=0; conf->use_initial_errorsto=1; conf->report_url=NULL; @@ -316,6 +316,23 @@ static void setdefaults_before_config() conf->db_new=NULL; conf->db_out_url=NULL; conf->db_out=NULL; + + conf->mdc_in=NULL; + conf->mdc_out=NULL; + + conf->line_db_in=NULL; + conf->line_db_out=NULL; + + conf->db_attrs = 0; +#if defined(WITH_MHASH) || defined(WITH_GCRYPT) + conf->db_attrs |= DB_MD5|DB_TIGER|DB_HAVAL|DB_CRC32|DB_SHA1|DB_RMD160|DB_SHA256|DB_SHA512; +#ifdef WITH_MHASH + conf->db_attrs |= DB_GOST; +#ifdef HAVE_MHASH_WHIRLPOOL + conf->db_attrs |= DB_WHIRLPOOL; +#endif +#endif +#endif #ifdef WITH_ZLIB conf->db_gzin=0; @@ -584,7 +601,7 @@ int main(int argc,char**argv) } populate_tree(conf->tree); - db_close(conf); + db_close(); exit(gen_report(conf->tree)); diff --git a/src/be.c b/src/be.c index 1d86578..c299666 100644 --- a/src/be.c +++ b/src/be.c @@ -1,6 +1,6 @@ /* aide, Advanced Intrusion Detection Environment * - * Copyright (C) 1999-2003,2005,2006,2010,2011 Rami Lehti, Pablo + * Copyright (C) 1999-2003,2005,2006,2010,2011,2013 Rami Lehti, Pablo * Virolainen, Richard van den Berg, Hannes von Haugwitz * $Header$ * @@ -29,7 +29,10 @@ #include "db_config.h" #include "db_file.h" #include "report.h" +#include "util.h" +#ifdef WITH_CURL #include "fopen.h" +#endif #include "be.h" #ifdef WITH_PSQL @@ -130,6 +133,7 @@ FILE* be_init(int inout,url_t* u,int iszipped) switch (u->type) { case url_file : { + u->value = expand_tilde(u->value); error(200,_("Opening file \"%s\" for %s\n"),u->value,inout?"r":"w+"); #if HAVE_FCNTL && HAVE_FTRUNCATE fd=open(u->value,inout?O_RDONLY:O_CREAT|O_RDWR,0666); diff --git a/src/commandconf.c b/src/commandconf.c index 74f6c38..b40f4a6 100644 --- a/src/commandconf.c +++ b/src/commandconf.c @@ -1,6 +1,6 @@ /* aide, Advanced Intrusion Detection Environment * - * Copyright (C) 1999-2006,2010,2011 Rami Lehti, Pablo Virolainen, + * Copyright (C) 1999-2006,2010,2011,2013 Rami Lehti, Pablo Virolainen, * Richard van den Berg, Hannes von Haugwitz * $Header$ * @@ -34,12 +34,15 @@ #include "db_config.h" #include "gen_list.h" #include "symboltable.h" +#include "md.h" #include "util.h" #include "base64.h" /*for locale support*/ #include "locale-aide.h" /*for locale support*/ +#ifdef WITH_CURL #include "fopen.h" +#endif #define BUFSIZE 4096 #define ZBUFSIZE 16384 @@ -96,27 +99,8 @@ int commandconf(const char mode,const char* line) case 'D': { /* Let's do it */ int rv=-1; - char* new_config=NULL; - char* homedir=NULL; - - /* support for ~ in the config file string - ~ must be the first character and it will be - replaced with HOME-environment variable - */ - if(config[0]=='~'){ - if((homedir=getenv("HOME"))){ - new_config=(char*)malloc(sizeof(char)* - (strlen(config)+strlen(homedir)+1)); - memcpy(new_config,homedir,strlen(homedir)); - memcpy(new_config+strlen(homedir), - config+sizeof(char),strlen(config+sizeof(char))); - l=(strlen(config)+strlen(homedir)); - new_config[l]='\0'; - free(config); - config=new_config; - /* Don't free(homedir); because it is not safe on some platforms */ - } - } + + config = expand_tilde(config); if (config!=NULL && strcmp(config,"-")==0) { error(255,_("Config from stdin\n")); rv=0; @@ -256,6 +240,7 @@ int db_input_wrapper(char* buf, int max_size, int db) #ifdef WITH_ZLIB gzFile* db_gzp=NULL; #endif + struct md_container *mdc; switch(db) { case DB_OLD: { #ifdef WITH_CURL @@ -299,6 +284,9 @@ int db_input_wrapper(char* buf, int max_size, int db) case url_https: case url_ftp: { retval=url_fread(buf,1,max_size,(URL_FILE *)*db_filep); + if ((mdc = (db == DB_OLD ? conf->mdc_in : conf->mdc_out))) { + update_md(mdc, buf, retval); + } break; } default: @@ -371,6 +359,10 @@ int db_input_wrapper(char* buf, int max_size, int db) #endif /* WITH_MHASH */ #endif /* WITH_ZLIB */ + if ((mdc = (db == DB_OLD ? conf->mdc_in : conf->mdc_out))) { + update_md(mdc, buf, retval); + } + #ifdef WITH_MHASH if(*domd){ if(!*md){ diff --git a/src/compare_db.c b/src/compare_db.c index 8c15dc0..db67a15 100644 --- a/src/compare_db.c +++ b/src/compare_db.c @@ -1,6 +1,6 @@ /* aide, Advanced Intrusion Detection Environment * - * Copyright (C) 1999-2007,2010,2011 Rami Lehti, Pablo Virolainen, + * Copyright (C) 1999-2007,2010-2013 Rami Lehti, Pablo Virolainen, * Richard van den Berg, Mike Markley, Hannes von Haugwitz * $Id$ * @@ -59,7 +59,7 @@ const int time_string_len = 26; long ntotal, nadd, nrem, nchg = 0; -const char* report_top_format = "\n---------------------------------------------------\n%s:\n---------------------------------------------------\n\n"; +const char* report_top_format = "\n\n---------------------------------------------------\n%s:\n---------------------------------------------------\n"; DB_ATTR_TYPE ignored_attrs, forced_attrs; @@ -302,14 +302,15 @@ static char* get_file_type_string(mode_t mode) { #ifdef S_IFDOOR case S_IFDOOR: return _("Door"); #endif + case 0: return NULL; default: return _("Unknown file type"); } } static char* byte_to_base16(byte* src, size_t ssize) { char* str = malloc((2*ssize+1) * sizeof (char)); - int i; - for(i=0; iattr&attr)) { - *values = malloc(1 * sizeof (char*)); - easy_string("") - return 1; + *values = NULL; + return 0; #ifdef WITH_ACL } else if (DB_ACL&attr) { return acl2array(line->acl, &*values); @@ -442,7 +442,7 @@ static void print_line(seltree* node) { } } summary[length]='\0'; - error(2,"%s: %s\n", summary, (node->checked&NODE_REMOVED?node->old_data:node->new_data)->filename); + 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) { @@ -462,7 +462,12 @@ static void print_dbline_attributes(db_line* oline, db_line* nline, DB_ATTR_TYPE 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%s: %s\n",get_file_type_string((nline==NULL?oline:nline)->perm),(nline==NULL?oline:nline)->filename); + 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=(~(ignored_attrs))&(report_attrs|changed_attrs)&((oline==NULL?0:oline->attr)|(nline==NULL?0:nline->attr)); for (j=0; j < length; ++j) { if (details_attributes[j]&attrs) { @@ -475,12 +480,12 @@ static void print_dbline_attributes(db_line* oline, db_line* nline, DB_ATTR_TYPE k = 0; while (olen-p*k >= 0 || nlen-p*k >= 0) { c = k*(p-1); - if (oline==NULL || !(oline->attr&details_attributes[j]) ) { - error(2," %s%-9s%c %-*c %.*s\n", width_details%2?"":" ", i+k?"":details_string[j], i+k?' ':':', p, ' ', p-1, nlen-p*k>0?&nvalue[i][c]:""); - } else if (nline==NULL || !(nline->attr&details_attributes[j])) { - error(2," %s%-9s%c %.*s\n", width_details%2?"":" ", i+k?"":details_string[j], i+k?' ':':', p-1, olen-p*k>0?&ovalue[i][c]:""); + 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-p*k>0?&ovalue[i][c]:"", p-1, nlen-p*k>0?&nvalue[i][c]:""); + 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++; } @@ -558,7 +563,7 @@ static void print_report_details(seltree* node) { 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)):0)|forced_attrs); - } else if ((conf->verbose_level>=6)) { + } 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); } } @@ -613,9 +618,21 @@ static void print_report_header() { 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\n\n"), ntotal, nadd, nrem, nchg); + " Removed entries:\t\t%li\n Changed entries:\t\t%li"), ntotal, nadd, nrem, nchg); } else { - error(0,_("\nNumber of entries:\t%li\n"), ntotal); + 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); + } } } @@ -625,7 +642,7 @@ static void print_report_footer() int run_time = (int) difftime(conf->end_time, conf->start_time); strftime(time, time_string_len, time_format, localtime(&(conf->end_time))); - error(2,_("\nEnd timestamp: %s (run time: %dm %ds)\n"), time, run_time/60, run_time%60); + error(2,_("\n\nEnd timestamp: %s (run time: %dm %ds)\n"), time, run_time/60, run_time%60); free(time); time=NULL; } @@ -663,7 +680,7 @@ int gen_report(seltree* node) { send_audit_report(); #endif print_report_header(); - if(conf->action&(DO_COMPARE|DO_DIFF) || (conf->action&DO_INIT && conf->detailed_init_report) ) { + if(conf->action&(DO_COMPARE|DO_DIFF) || (conf->action&DO_INIT && conf->report_detailed_init) ) { if (conf->grouped) { if (nadd) { error(2,(char*)report_top_format,_("Added entries")); @@ -688,14 +705,15 @@ int gen_report(seltree* node) { print_report_list(node, NODE_ADDED|NODE_REMOVED|NODE_CHANGED); } if (nadd || nrem || nchg) { - error(nchg?5:6,(char*)report_top_format,_("Detailed information about changes")); + error(nchg?5:7,(char*)report_top_format,_("Detailed information about changes")); print_report_details(node); } } + print_report_databases(); conf->end_time=time(&(conf->end_time)); print_report_footer(); - return (nadd!=0)*1+(nrem!=0)*2+(nchg!=0)*4; + return conf->action&(DO_COMPARE|DO_DIFF) ? (nadd!=0)*1+(nrem!=0)*2+(nchg!=0)*4 : 0; } const char* aide_key_9=CONFHMACKEY_09; diff --git a/src/conf_lex.l b/src/conf_lex.l index 71378a5..b1e09df 100644 --- a/src/conf_lex.l +++ b/src/conf_lex.l @@ -12,10 +12,10 @@ EX [" "\t]* %{ -#define YYDEBUG +#define YYDEBUG 1 /* - * Copyright (C) 1999-2002,2004-2006,2010-2012 Rami Lehti, Pablo + * Copyright (C) 1999-2002,2004-2006,2010-2013 Rami Lehti, Pablo * Virolainen, Richard van den Berg, Hannes von Haugwitz * $Header$ * This program is free software; you can redistribute it and/or @@ -307,6 +307,12 @@ int var_in_conflval=0; return (TDATABASE_NEW); } +^[\t\ ]*"database_attrs"{E} { + error(230,"%li:database_attrs =\n",conf_lineno); + BEGIN EXPR; + return (TDATABASE_ATTRS); +} + ^[\t\ ]*"warn_dead_symlinks"{E} { error(230,"%li:warn_dead_symlinks =\n",conf_lineno); BEGIN CONFVALHUNT; @@ -343,10 +349,10 @@ int var_in_conflval=0; return (TREPORT_URL); } -^[\t\ ]*"detailed_init_report"{E} { - error(230,"%li:detailed_init_report =\n",conf_lineno); +^[\t\ ]*"report_detailed_init"{E} { + error(230,"%li:report_detailed_init =\n",conf_lineno); BEGIN CONFVALHUNT; - return (TDETAILEDINITREPORT); + return (TREPORTDETAILEDINIT); } ^[\t\ ]*"report_base16"{E} { diff --git a/src/conf_yacc.y b/src/conf_yacc.y index 136c666..f7d2874 100644 --- a/src/conf_yacc.y +++ b/src/conf_yacc.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (C) 1999-2006,2010-2012 Rami Lehti, Pablo Virolainen, + * Copyright (C) 1999-2006,2010-2013 Rami Lehti, Pablo Virolainen, * Richard van den Berg, Hannes von Haugwitz * $Header$ * This program is free software; you can redistribute it and/or @@ -75,12 +75,13 @@ extern long conf_lineno; %token TSUMMARIZECHANGES %token TNEWLINE %token TVERBOSE -%token TDETAILEDINITREPORT +%token TREPORTDETAILEDINIT %token TREPORTBASE16 %token TCONFIG_FILE %token TDATABASE %token TDATABASE_OUT %token TDATABASE_NEW +%token TDATABASE_ATTRS %token TREPORT_URL %token TGZIPDBOUT %token TROOT_PREFIX @@ -152,7 +153,7 @@ lines : lines line | ; line : rule | equrule | negrule | definestmt | undefstmt | ifdefstmt | ifndefstmt | ifhoststmt | ifnhoststmt - | groupdef | db_in | db_out | db_new | verbose | detailed_init_report | config_version + | groupdef | db_in | db_out | db_new | db_attrs | verbose | report_detailed_init | config_version | report | gzipdbout | root_prefix | report_base16 | recursion_stopper | warn_dead_symlinks | grouped | summarize_changes | acl_no_symlink_follow | beginconfigstmt | endconfigstmt | TEOF { @@ -268,6 +269,15 @@ verbose : TVERBOSE TSTRING { do_verbdef($2); }; report : TREPORT_URL TSTRING { do_repurldef($2); } ; +db_attrs : TDATABASE_ATTRS expr { + DB_ATTR_TYPE attr; + if((attr = $2&(~DB_HASHES))){ + error(0, "%li: invalid attribute(s) in database_attrs: %llx\n", conf_lineno-1, attr); + YYABORT; + } + conf->db_attrs=$2; +} ; + beginconfigstmt : TBEGIN_CONFIG TSTRING { #ifdef WITH_MHASH conf->do_configmd=1; @@ -303,12 +313,12 @@ warn_dead_symlinks : TWARNDEADSYMLINKS TFALSE { conf->warn_dead_symlinks=0; } ; -detailed_init_report : TDETAILEDINITREPORT TTRUE { - conf->detailed_init_report=1; +report_detailed_init : TREPORTDETAILEDINIT TTRUE { + conf->report_detailed_init=1; } ; -detailed_init_report : TDETAILEDINITREPORT TFALSE { - conf->detailed_init_report=0; +report_detailed_init : TREPORTDETAILEDINIT TFALSE { + conf->report_detailed_init=0; } ; report_base16 : TREPORTBASE16 TTRUE { diff --git a/src/db.c b/src/db.c index c6cce85..41be2dd 100644 --- a/src/db.c +++ b/src/db.c @@ -1,6 +1,6 @@ /* aide, Advanced Intrusion Detection Environment * - * Copyright (C) 1999-2006,2010,2011 Rami Lehti, Pablo Virolainen, + * Copyright (C) 1999-2006,2010,2011,2013 Rami Lehti, Pablo Virolainen, * Richard van den Berg, Hannes von Haugwitz * $Header$ * @@ -26,6 +26,7 @@ #include "db.h" #include "db_file.h" #include "db_disk.h" +#include "md.h" #ifdef WITH_PSQL #include "db_sql.h" @@ -131,6 +132,47 @@ const char* db_namealias[db_alias_size] = { const int db_aliasvalue[db_alias_size] = { db_lnkcount } ; /* "count", */ +static struct md_container *init_db_attrs(URL_TYPE type) { + struct md_container *mdc = NULL; + if (conf->db_attrs) { + switch (type) { + case url_stdout: + case url_stderr: + case url_fd: + case url_file: + #ifdef WITH_CURL + case url_http: + case url_https: + case url_ftp: + #endif /* WITH CURL */ + mdc = malloc(sizeof(struct md_container)); /* freed in close_db_attrs */ + mdc->todo_attr = conf->db_attrs; + init_md(mdc); + break; + #ifdef WITH_PSQL + case url_sql: + break; + #endif /* WITH_PSQL */ + default : + error(200,_("init_db_attrs(): Unknown url type.\n")); + } + } + return mdc; +} + +static db_line *close_db_attrs (struct md_container *mdc, char *url_value) { + db_line *line = NULL; + if (mdc != NULL) { + close_md(mdc); + line = malloc(sizeof(struct db_line)); + line->filename = url_value; + line->perm = 0; + line->attr = conf->db_attrs; + md2line(mdc, line); + free(mdc); + } + return line; +} int db_init(int db) { @@ -149,6 +191,7 @@ int db_init(int db) case DB_OLD: { + conf->mdc_in = init_db_attrs((conf->db_in_url)->type); rv=be_init(1,conf->db_in_url,0); if(rv==NULL) { error(200,_("db_in is null\n")); @@ -160,6 +203,7 @@ int db_init(int db) } case DB_WRITE: { #ifdef WITH_ZLIB + conf->mdc_out = init_db_attrs((conf->db_out_url)->type); if(conf->gzip_dbout){ rv=be_init(0,conf->db_out_url,conf->gzip_dbout); conf->db_gzout=rv; @@ -180,6 +224,7 @@ int db_init(int db) return RETOK; } case DB_NEW: { + conf->mdc_out = init_db_attrs((conf->db_new_url)->type); rv=be_init(1,conf->db_new_url,0); if(rv==NULL) { error(200,_("db_new is null\n")); @@ -760,25 +805,19 @@ int db_writeline(db_line* line,db_config* dbconf){ return RETFAIL; } -int db_close(db_config* dbconf) -{ - if (dbconf==NULL) return RETOK; - - switch (dbconf->db_out_url->type) { +void db_close() { + switch (conf->db_out_url->type) { case url_stdout: case url_stderr: case url_fd: case url_file: { if ( #ifdef WITH_ZLIB - (dbconf->gzip_dbout && dbconf->db_gzout) || + (conf->gzip_dbout && conf->db_gzout) || #endif - (dbconf->db_out!=NULL)) { - if (db_close_file(dbconf)==RETOK) { - return RETOK; - } + (conf->db_out!=NULL)) { + db_close_file(conf); } - return RETFAIL; break; } #ifdef WITH_CURL @@ -786,29 +825,27 @@ int db_close(db_config* dbconf) case url_https: case url_ftp: { - url_fclose(dbconf->db_out); + if (conf->db_out!=NULL) { + url_fclose(conf->db_out); + } break; } #endif /* WITH CURL */ #ifdef WITH_PSQL case url_sql: { - if (dbconf->db_out!=NULL) { - if (db_close_sql(dbconf->db_out)==RETOK) { - return RETOK; - } else { - return RETFAIL; - } + if (conf->db_out!=NULL) { + db_close_sql(conf->db_out); } - return RETOK; break; } #endif default : { error(0,_("db_close():Unknown output in db out.\n")); - return RETFAIL; } } - return RETFAIL; + conf->line_db_in = close_db_attrs(conf->mdc_in, (conf->db_in_url)->value); + conf->line_db_out = close_db_attrs(conf->mdc_out, (conf->action&DO_DIFF + ? conf->db_new_url : conf->db_out_url)->value); } void free_db_line(db_line* dl) diff --git a/src/db_file.c b/src/db_file.c index 984d041..f9fff4d 100644 --- a/src/db_file.c +++ b/src/db_file.c @@ -1,6 +1,6 @@ /* aide, Advanced Intrusion Detection Environment * - * Copyright (C) 1999-2007,2010,2011 Rami Lehti, Pablo Virolainen, Mike + * Copyright (C) 1999-2007,2010-2013 Rami Lehti, Pablo Virolainen, Mike * Markley, Richard van den Berg, Hannes von Haugwitz * $Header$ * @@ -85,7 +85,7 @@ void handle_gzipped_input(int out,gzFile* gzp){ } if (write(out, buf,nread) != tmp) { - error(0,_("write() failed: %m\n")); + error(0,_("write() failed: %s\n"), strerror(errno)); exit(1); } @@ -142,6 +142,10 @@ int dofprintf( const char* s,...) retval=vsnprintf(temp,retval+1,s,ap); va_end(ap); + if (conf->mdc_out) { + update_md(conf->mdc_out,temp ,retval); + } + #ifdef WITH_MHASH if(conf->do_dbnewmd) mhash(conf->dbnewmd,(void*)temp,retval); diff --git a/src/db_lex.l b/src/db_lex.l index 50fe069..ef1f107 100644 --- a/src/db_lex.l +++ b/src/db_lex.l @@ -22,8 +22,8 @@ extern YYSTYPE yylval; /* aide, Advanced Intrusion Detection Environment * - * Copyright (C) 1999-2002,2005,2010 Rami Lehti,Pablo Virolainen, - * Richard van den Berg + * Copyright (C) 1999-2002,2005,2010,2013 Rami Lehti,Pablo Virolainen, + * Richard van den Berg, Hannes von Haugwitz * $Header$ * * This program is free software; you can redistribute it and/or @@ -45,7 +45,7 @@ extern YYSTYPE yylval; #define YY_DECL int db_scan(void) -#define YYDEBUG +#define YYDEBUG 1 #include "aide.h" #include "conf_yacc.h" diff --git a/src/do_md.c b/src/do_md.c index 358199c..bc06e62 100644 --- a/src/do_md.c +++ b/src/do_md.c @@ -1,7 +1,7 @@ /* aide, Advanced Intrusion Detection Environment * vi: ts=8 sw=8 * - * Copyright (C) 1999-2002,2004-2006,2009-2011 Rami Lehti, Pablo + * Copyright (C) 1999-2002,2004-2006,2009-2011,2013 Rami Lehti, Pablo * Virolainen, Mike Markley, Richard van den Berg, Hannes von Haugwitz * $Header$ * @@ -463,13 +463,13 @@ void acl2line(db_line* line) { return; } if (acl_a == NULL) - error(0, "Tried to read access ACL on %s but failed with: %m\n", - line->fullpath); + error(0, "Tried to read access ACL on %s but failed with: %s\n", + line->fullpath, strerror(errno)); if ((acl_d == NULL) && (errno != EACCES)) /* ignore DEFAULT on files */ { acl_free(acl_a); - error(0, "Tried to read default ACL on %s but failed with: %m\n", - line->fullpath); + error(0, "Tried to read default ACL on %s but failed with: %s\n", + line->fullpath, strerror(errno)); } /* assume memory allocs work, like rest of AIDE code... */ @@ -589,7 +589,7 @@ void xattrs2line(db_line *line) { if ((xret == -1) && ((errno == ENOSYS) || (errno == ENOTSUP))) { line->attr&=(~DB_XATTRS); } else if (xret == -1) { - error(0, "listxattrs failed for %s:%m\n", line->fullpath); + error(0, "listxattrs failed for %s:%s\n", line->fullpath, strerror(errno)); } else if (xret) { const char *attr = xatrs; static ssize_t asz = 1024; @@ -616,7 +616,7 @@ void xattrs2line(db_line *line) { if (aret != -1) xattr_add(xattrs, attr, val, aret); else if (errno != ENOATTR) - error(0, "getxattr failed for %s:%m\n", line->fullpath); + error(0, "getxattr failed for %s:%s\n", line->fullpath, strerror(errno)); next_attr: attr += len + 1; @@ -638,7 +638,7 @@ void selinux2line(db_line *line) { if (lgetfilecon_raw(line->fullpath, &cntx) == -1) { line->attr&=(~DB_SELINUX); if ((errno != ENOATTR) && (errno != EOPNOTSUPP)) - error(0, "lgetfilecon_raw failed for %s:%m\n", line->fullpath); + error(0, "lgetfilecon_raw failed for %s:%s\n", line->fullpath, strerror(errno)); return; } diff --git a/src/fopen.c b/src/fopen.c index 1f9c5da..0f57048 100644 --- a/src/fopen.c +++ b/src/fopen.c @@ -13,7 +13,7 @@ * See the main() function at the bottom that shows an app that retrives from a * specified url using fgets() and fread() and saves as two output files. * - * Coyright (c)2003 Simtec Electronics + * Copyright (c) 2003 Simtec Electronics * * Re-implemented by Vincent Sanders with extensive * reference to original curl example code @@ -41,568 +41,357 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This example requires libcurl 7.9.7 or later. + * + * Modified for aide by Hannes von Haugwitz + * based on modifications of previous version by Pablo Virolainen + * (pablo@ipi.fi): + * 2013-05-14: - moved declarations to 'include/fopen.h' + * - removed (unneeded) main method */ -/** - * Modified for aide by Pablo Virolainen (pablo@ipi.fi) - */ - -#include "aide.h" - -#ifdef WITH_CURL - -#include -#include -#include -#include -#include -#include - #include "fopen.h" /* we use a global one for convenience */ CURLM *multi_handle; /* curl calls this routine to get more data */ -static size_t -write_callback(char *buffer, - size_t size, - size_t nitems, - void *userp) +static size_t write_callback(char *buffer, + size_t size, + size_t nitems, + void *userp) { - char *newbuff; - int rembuff; - - URL_FILE *url = (URL_FILE *)userp; - size *= nitems; - - rembuff=url->buffer_len - url->buffer_pos;//remaining space in buffer - - if(size > rembuff) - { - //not enuf space in buffer - newbuff=realloc(url->buffer,url->buffer_len + (size - rembuff)); - if(newbuff==NULL) - { - size=rembuff; - } - else - { - /* realloc suceeded increase buffer size*/ - url->buffer_len+=size - rembuff; - url->buffer=newbuff; - } - } - - memcpy(&url->buffer[url->buffer_pos], buffer, size); - url->buffer_pos += size; + char *newbuff; + size_t rembuff; - return size; -} + URL_FILE *url = (URL_FILE *)userp; + size *= nitems; -/* use to attempt to fill the read buffer up to requested number of bytes */ -static int -fill_buffer(URL_FILE *file,int want,int waittime) -{ - fd_set fdread; - fd_set fdwrite; - fd_set fdexcep; - int maxfd; - struct timeval timeout; - int rc; - (void) waittime; - - /* only attempt to fill buffer if transactions still running and buffer - * doesnt exceed required size already - */ - if((!file->still_running) || (file->buffer_pos > want)) - return 0; - - /* attempt to fill buffer */ - do - { - FD_ZERO(&fdread); - FD_ZERO(&fdwrite); - FD_ZERO(&fdexcep); - - /* set a suitable timeout to fail on */ - timeout.tv_sec = 60; /* 1 minute */ - timeout.tv_usec = 0; - - /* get file descriptors from the transfers */ - curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); - - rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); - - switch(rc) { - case -1: - /* select error */ - break; - - case 0: - break; - - default: - /* timeout or readable/writable sockets */ - /* note we *could* be more efficient and not wait for - * CURLM_CALL_MULTI_PERFORM to clear here and check it on re-entry - * but that gets messy */ - while(curl_multi_perform(multi_handle, &file->still_running) == - CURLM_CALL_MULTI_PERFORM); - - break; - } - } while(file->still_running && (file->buffer_pos < want)); - return 1; -} + rembuff=url->buffer_len - url->buffer_pos; /* remaining space in buffer */ -/* use to remove want bytes from the front of a files buffer */ -static int -use_buffer(URL_FILE *file,int want) -{ - /* sort out buffer */ - if((file->buffer_pos - want) <=0) - { - /* ditch buffer - write will recreate */ - if(file->buffer) - free(file->buffer); - - file->buffer=NULL; - file->buffer_pos=0; - file->buffer_len=0; + if(size > rembuff) { + /* not enough space in buffer */ + newbuff=realloc(url->buffer,url->buffer_len + (size - rembuff)); + if(newbuff==NULL) { + fprintf(stderr,"callback buffer grow failed\n"); + size=rembuff; } - else - { - /* move rest down make it available for later */ - memmove(file->buffer, - &file->buffer[want], - (file->buffer_pos - want)); - - file->buffer_pos -= want; + else { + /* realloc suceeded increase buffer size*/ + url->buffer_len+=size - rembuff; + url->buffer=newbuff; } - return 0; -} - - - -URL_FILE * -url_fopen(char *url,const char *operation) -{ - /* this code could check for URLs or types in the 'url' and - basicly use the real fopen() for standard files */ - - URL_FILE *file; - (void)operation; - - file = (URL_FILE *)malloc(sizeof(URL_FILE)); - if(!file) - return NULL; + } - memset(file, 0, sizeof(URL_FILE)); + memcpy(&url->buffer[url->buffer_pos], buffer, size); + url->buffer_pos += size; - - - if((file->handle.file=fopen(url,operation))) - { - file->type = CFTYPE_FILE; /* marked as URL */ - } - else - { - /* I know that this is broken. FIXME!!! */ - if (operation[0]=='r') { - /* Read.. */ - file->type = CFTYPE_CURL; /* marked as URL */ - file->handle.curl = curl_easy_init(); - - curl_easy_setopt(file->handle.curl, CURLOPT_URL, url); - curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file); - curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0!=0); - curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback); - - - if(!multi_handle) - multi_handle = curl_multi_init(); - - curl_multi_add_handle(multi_handle, file->handle.curl); - - /* lets start the fetch */ - while(curl_multi_perform(multi_handle, &file->still_running) == - CURLM_CALL_MULTI_PERFORM ); - - if((file->buffer_pos == 0) && (!file->still_running)) - { - /* if still_running is 0 now, we should return NULL */ - - /* make sure the easy handle is not in the multi handle anymore */ - curl_multi_remove_handle(multi_handle, file->handle.curl); - - /* cleanup */ - curl_easy_cleanup(file->handle.curl); - - free(file); - - file = NULL; - } - } else { - /* write ? */ - file->type = CFTYPE_CURL; /* marked as URL */ - file->handle.curl = curl_easy_init(); - - curl_easy_setopt(file->handle.curl, CURLOPT_URL, url); - curl_easy_setopt(file->handle.curl, CURLOPT_UPLOAD, 0==0); - curl_easy_setopt(file->handle.curl, CURLOPT_PUT, 0==0); - curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0!=0); - - if(!multi_handle) - multi_handle = curl_multi_init(); - - curl_multi_add_handle(multi_handle, file->handle.curl); - - /* lets start the fetch */ - while(curl_multi_perform(multi_handle, &file->still_running) == - CURLM_CALL_MULTI_PERFORM ); - - if((file->buffer_pos == 0) && (!file->still_running)) - { - /* if still_running is 0 now, we should return NULL */ - - /* make sure the easy handle is not in the multi handle anymore */ - curl_multi_remove_handle(multi_handle, file->handle.curl); - - /* cleanup */ - curl_easy_cleanup(file->handle.curl); - - free(file); - - file = NULL; - } - } - } - return file; + return size; } -int -url_fclose(URL_FILE *file) +/* use to attempt to fill the read buffer up to requested number of bytes */ +static int fill_buffer(URL_FILE *file, size_t want) { - int ret=0;/* default is good return */ - - switch(file->type) - { - case CFTYPE_FILE: - ret=fclose(file->handle.file); /* passthrough */ - break; - - case CFTYPE_CURL: - /* make sure the easy handle is not in the multi handle anymore */ - curl_multi_remove_handle(multi_handle, file->handle.curl); - - /* cleanup */ - curl_easy_cleanup(file->handle.curl); - break; - - default: /* unknown or supported type - oh dear */ - ret=EOF; - errno=EBADF; - break; + fd_set fdread; + fd_set fdwrite; + fd_set fdexcep; + struct timeval timeout; + int rc; + + /* only attempt to fill buffer if transactions still running and buffer + * doesnt exceed required size already + */ + if((!file->still_running) || (file->buffer_pos > want)) + return 0; + /* attempt to fill buffer */ + do { + int maxfd = -1; + long curl_timeo = -1; + + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcep); + + /* set a suitable timeout to fail on */ + timeout.tv_sec = 60; /* 1 minute */ + timeout.tv_usec = 0; + + curl_multi_timeout(multi_handle, &curl_timeo); + if(curl_timeo >= 0) { + timeout.tv_sec = curl_timeo / 1000; + if(timeout.tv_sec > 1) + timeout.tv_sec = 1; + else + timeout.tv_usec = (curl_timeo % 1000) * 1000; } - if(file->buffer) - free(file->buffer);/* free any allocated buffer space */ + /* get file descriptors from the transfers */ + curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); - free(file); - - return ret; -} + /* In a real-world program you OF COURSE check the return code of the + function calls. On success, the value of maxfd is guaranteed to be + greater or equal than -1. We call select(maxfd + 1, ...), specially + in case of (maxfd == -1), we call select(0, ...), which is basically + equal to sleep. */ -int -url_feof(URL_FILE *file) -{ - int ret=0; + rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); - switch(file->type) - { - case CFTYPE_FILE: - ret=feof(file->handle.file); - break; + switch(rc) { + case -1: + /* select error */ + break; - case CFTYPE_CURL: - if((file->buffer_pos == 0) && (!file->still_running)) - ret = 1; - break; - default: /* unknown or supported type - oh dear */ - ret=-1; - errno=EBADF; - break; + case 0: + default: + /* timeout or readable/writable sockets */ + curl_multi_perform(multi_handle, &file->still_running); + break; } - return ret; + } while(file->still_running && (file->buffer_pos < want)); + return 1; } -size_t url_fwrite(const void *ptr, size_t size, size_t nmemb, URL_FILE *file) +/* use to remove want bytes from the front of a files buffer */ +static int use_buffer(URL_FILE *file,int want) { - size_t want; - switch(file->type) - { - case CFTYPE_FILE: - return fwrite(ptr,size,nmemb,file->handle.file); - break; - - case CFTYPE_CURL: - want = nmemb*size; - if (file->buffer_pos!=NULL) { - return 0; - } - - file->buffer=ptr; - file->buffer_pos=0; - file->buffer_len=want; - fill_buffer(file,want,1); - - break; - default: - //error=EBADF; - return 0; - break; - } - /* not reached */ - return -1; + /* sort out buffer */ + if((file->buffer_pos - want) <=0) { + /* ditch buffer - write will recreate */ + if(file->buffer) + free(file->buffer); + + file->buffer=NULL; + file->buffer_pos=0; + file->buffer_len=0; + } + else { + /* move rest down make it available for later */ + memmove(file->buffer, + &file->buffer[want], + (file->buffer_pos - want)); + + file->buffer_pos -= want; + } + return 0; } - -size_t -url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file) +URL_FILE *url_fopen(const char *url,const char *operation) { - size_t want; + /* this code could check for URLs or types in the 'url' and + basicly use the real fopen() for standard files */ - switch(file->type) - { - case CFTYPE_FILE: - want=fread(ptr,size,nmemb,file->handle.file); - break; + URL_FILE *file; + (void)operation; - case CFTYPE_CURL: - want = nmemb * size; + file = malloc(sizeof(URL_FILE)); + if(!file) + return NULL; - fill_buffer(file,want,1); + memset(file, 0, sizeof(URL_FILE)); - /* check if theres data in the buffer - if not fill_buffer() - * either errored or EOF */ - if(!file->buffer_pos) { - return 0; - } - /* ensure only available data is considered */ - if(file->buffer_pos < want) - want = file->buffer_pos; + if((file->handle.file=fopen(url,operation))) + file->type = CFTYPE_FILE; /* marked as URL */ - /* xfer data to caller */ - memcpy(ptr, file->buffer, want); + else { + file->type = CFTYPE_CURL; /* marked as URL */ + file->handle.curl = curl_easy_init(); - use_buffer(file,want); + curl_easy_setopt(file->handle.curl, CURLOPT_URL, url); + curl_easy_setopt(file->handle.curl, CURLOPT_WRITEDATA, file); + curl_easy_setopt(file->handle.curl, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(file->handle.curl, CURLOPT_WRITEFUNCTION, write_callback); - want = want / size; /* number of items - nb correct op - checked - * with glibc code*/ - break; + if(!multi_handle) + multi_handle = curl_multi_init(); - default: /* unknown or supported type - oh dear */ - want=0; - errno=EBADF; - break; + curl_multi_add_handle(multi_handle, file->handle.curl); - } - return want; -} + /* lets start the fetch */ + curl_multi_perform(multi_handle, &file->still_running); -char * -url_fgets(char *ptr, int size, URL_FILE *file) -{ - int want = size - 1;/* always need to leave room for zero termination */ - int loop; + if((file->buffer_pos == 0) && (!file->still_running)) { + /* if still_running is 0 now, we should return NULL */ - switch(file->type) - { - case CFTYPE_FILE: - ptr = fgets(ptr,size,file->handle.file); - break; + /* make sure the easy handle is not in the multi handle anymore */ + curl_multi_remove_handle(multi_handle, file->handle.curl); - case CFTYPE_CURL: - fill_buffer(file,want,1); - - /* check if theres data in the buffer - if not fill either errored or - * EOF */ - if(!file->buffer_pos) - return NULL; - - /* ensure only available data is considered */ - if(file->buffer_pos < want) - want = file->buffer_pos; - - /*buffer contains data */ - /* look for newline or eof */ - for(loop=0;loop < want;loop++) - { - if(file->buffer[loop] == '\n') - { - want=loop+1;/* include newline */ - break; - } - } - - /* xfer data to caller */ - memcpy(ptr, file->buffer, want); - ptr[want]=0;/* allways null terminate */ - - use_buffer(file,want); - break; + /* cleanup */ + curl_easy_cleanup(file->handle.curl); - default: /* unknown or supported type - oh dear */ - ptr=NULL; - errno=EBADF; - break; - } + free(file); - return ptr;/*success */ + file = NULL; + } + } + return file; } -void -url_rewind(URL_FILE *file) +int url_fclose(URL_FILE *file) { - switch(file->type) - { - case CFTYPE_FILE: - rewind(file->handle.file); /* passthrough */ - break; + int ret=0;/* default is good return */ - case CFTYPE_CURL: - /* halt transaction */ - curl_multi_remove_handle(multi_handle, file->handle.curl); + switch(file->type) { + case CFTYPE_FILE: + ret=fclose(file->handle.file); /* passthrough */ + break; - /* restart */ - curl_multi_add_handle(multi_handle, file->handle.curl); + case CFTYPE_CURL: + /* make sure the easy handle is not in the multi handle anymore */ + curl_multi_remove_handle(multi_handle, file->handle.curl); - /* ditch buffer - write will recreate - resets stream pos*/ - if(file->buffer) - free(file->buffer); + /* cleanup */ + curl_easy_cleanup(file->handle.curl); + break; - file->buffer=NULL; - file->buffer_pos=0; - file->buffer_len=0; + default: /* unknown or supported type - oh dear */ + ret=EOF; + errno=EBADF; + break; + } - break; + if(file->buffer) + free(file->buffer);/* free any allocated buffer space */ - default: /* unknown or supported type - oh dear */ - break; + free(file); - } + return ret; +} +int url_feof(URL_FILE *file) +{ + int ret=0; + + switch(file->type) { + case CFTYPE_FILE: + ret=feof(file->handle.file); + break; + + case CFTYPE_CURL: + if((file->buffer_pos == 0) && (!file->still_running)) + ret = 1; + break; + + default: /* unknown or supported type - oh dear */ + ret=-1; + errno=EBADF; + break; + } + return ret; } +size_t url_fread(void *ptr, size_t size, size_t nmemb, URL_FILE *file) +{ + size_t want; -/* Small main program to retrieve from a url using fgets and fread saving the - * output to two test files (note the fgets method will corrupt binary files if - * they contain 0 chars */ -/* int */ -/* main(int argc, char *argv[]) */ -/* { */ -/* URL_FILE *handle; */ -/* FILE *outf; */ + switch(file->type) { + case CFTYPE_FILE: + want=fread(ptr,size,nmemb,file->handle.file); + break; -/* int nread; */ -/* char buffer[256]; */ -/* char *url; */ + case CFTYPE_CURL: + want = nmemb * size; -/* if(argc < 2) */ -/* { */ -/* url="http://192.168.7.3/testfile";/\* default to testurl *\/ */ -/* } */ -/* else */ -/* { */ -/* url=argv[1];/\* use passed url *\/ */ -/* } */ + fill_buffer(file,want); -/* /\* copy from url line by line with fgets *\/ */ -/* outf=fopen("fgets.test","w+"); */ -/* if(!outf) */ -/* { */ -/* perror("couldnt open fgets output file\n"); */ -/* return 1; */ -/* } */ + /* check if theres data in the buffer - if not fill_buffer() + * either errored or EOF */ + if(!file->buffer_pos) + return 0; -/* handle = url_fopen(url, "r"); */ -/* if(!handle) */ -/* { */ -/* printf("couldn't url_fopen()\n"); */ -/* fclose(outf); */ -/* return 2; */ -/* } */ + /* ensure only available data is considered */ + if(file->buffer_pos < want) + want = file->buffer_pos; -/* while(!url_feof(handle)) */ -/* { */ -/* url_fgets(buffer,sizeof(buffer),handle); */ -/* fwrite(buffer,1,strlen(buffer),outf); */ -/* } */ + /* xfer data to caller */ + memcpy(ptr, file->buffer, want); -/* url_fclose(handle); */ + use_buffer(file,want); -/* fclose(outf); */ + want = want / size; /* number of items */ + break; + default: /* unknown or supported type - oh dear */ + want=0; + errno=EBADF; + break; -/* /\* Copy from url with fread *\/ */ -/* outf=fopen("fread.test","w+"); */ -/* if(!outf) */ -/* { */ -/* perror("couldnt open fread output file\n"); */ -/* return 1; */ -/* } */ + } + return want; +} + +char *url_fgets(char *ptr, size_t size, URL_FILE *file) +{ + size_t want = size - 1;/* always need to leave room for zero termination */ + size_t loop; + + switch(file->type) { + case CFTYPE_FILE: + ptr = fgets(ptr,size,file->handle.file); + break; + + case CFTYPE_CURL: + fill_buffer(file,want); + + /* check if theres data in the buffer - if not fill either errored or + * EOF */ + if(!file->buffer_pos) + return NULL; + + /* ensure only available data is considered */ + if(file->buffer_pos < want) + want = file->buffer_pos; + + /*buffer contains data */ + /* look for newline or eof */ + for(loop=0;loop < want;loop++) { + if(file->buffer[loop] == '\n') { + want=loop+1;/* include newline */ + break; + } + } -/* handle = url_fopen("testfile", "r"); */ -/* if(!handle) { */ -/* printf("couldn't url_fopen()\n"); */ -/* fclose(outf); */ -/* return 2; */ -/* } */ + /* xfer data to caller */ + memcpy(ptr, file->buffer, want); + ptr[want]=0;/* allways null terminate */ -/* do { */ -/* nread = url_fread(buffer, 1,sizeof(buffer), handle); */ -/* fwrite(buffer,1,nread,outf); */ -/* } while(nread); */ + use_buffer(file,want); -/* url_fclose(handle); */ + break; -/* fclose(outf); */ + default: /* unknown or supported type - oh dear */ + ptr=NULL; + errno=EBADF; + break; + } + return ptr;/*success */ +} -/* /\* Test rewind *\/ */ -/* outf=fopen("rewind.test","w+"); */ -/* if(!outf) */ -/* { */ -/* perror("couldnt open fread output file\n"); */ -/* return 1; */ -/* } */ +void url_rewind(URL_FILE *file) +{ + switch(file->type) { + case CFTYPE_FILE: + rewind(file->handle.file); /* passthrough */ + break; -/* handle = url_fopen("testfile", "r"); */ -/* if(!handle) { */ -/* printf("couldn't url_fopen()\n"); */ -/* fclose(outf); */ -/* return 2; */ -/* } */ + case CFTYPE_CURL: + /* halt transaction */ + curl_multi_remove_handle(multi_handle, file->handle.curl); -/* nread = url_fread(buffer, 1,sizeof(buffer), handle); */ -/* fwrite(buffer,1,nread,outf); */ -/* url_rewind(handle); */ + /* restart */ + curl_multi_add_handle(multi_handle, file->handle.curl); -/* buffer[0]='\n'; */ -/* fwrite(buffer,1,1,outf); */ + /* ditch buffer - write will recreate - resets stream pos*/ + if(file->buffer) + free(file->buffer); -/* nread = url_fread(buffer, 1,sizeof(buffer), handle); */ -/* fwrite(buffer,1,nread,outf); */ + file->buffer=NULL; + file->buffer_pos=0; + file->buffer_len=0; + break; -/* url_fclose(handle); */ - -/* fclose(outf); */ - - -/* return 0;/\* all done *\/ */ -/* } */ - -#endif + default: /* unknown or supported type - oh dear */ + break; + } +} diff --git a/src/util.c b/src/util.c index bcacc91..2659c8c 100644 --- a/src/util.c +++ b/src/util.c @@ -1,6 +1,6 @@ /* aide, Advanced Intrusion Detection Environment * - * Copyright (C) 1999-2002,2004-2006,2010,2011 Rami Lehti, Pablo + * Copyright (C) 1999-2002,2004-2006,2010,2011,2013 Rami Lehti, Pablo * Virolainen, Mike Markley, Richard van den Berg, Hannes von Haugwitz * $Header$ * @@ -361,6 +361,32 @@ void sig_handler(int signum) return; } +char *expand_tilde(char *path) { + char *homedir, *full; + size_t path_len, homedir_len, full_len; + + if (path != NULL) { + if (path[0] == '~') { + if((homedir=getenv("HOME")) != NULL) { + path_len = strlen(path+sizeof(char)); + homedir_len = strlen(homedir); + full_len = homedir_len+path_len; + full = malloc(sizeof(char) * (full_len+1)); + strncpy(full, homedir, homedir_len); + strncpy(full+homedir_len, path+sizeof(char), path_len); + full[full_len] = '\0'; + free(path); + /* Don't free(homedir); because it is not safe on some platforms */ + path = full; + } else { + error(3, _("Variable name 'HOME' not found in environment. '~' cannot be expanded\n")); + } + } else if (path[0] == '\\' && path[1] == '~') { + path += sizeof(char); + } + } + return path; +} /* Like strstr but only do search for maximum of n chars. haystack does not have to be NULL terminated