1054 lines
34 KiB
Diff
1054 lines
34 KiB
Diff
diff --git a/ChangeLog b/ChangeLog
|
|
index 263c438f4a2a38edc45f91c0d5a216112a8fa38c..5d286a8e07d0b3235f97272223175a1dd85848b2 100644
|
|
--- a/ChangeLog
|
|
+++ b/ChangeLog
|
|
@@ -1,27 +1,30 @@
|
|
+2025-08-07 Hannes von Haugwitz <hannes@vonhaugwitz.com>
|
|
+ * Escape control characters in report and log output (CVE-2025-54389)
|
|
+
|
|
2016-07-25 Hannes von Haugwitz <hannes@vonhaugwitz.com>
|
|
- * Release version 0.16
|
|
+ * Release version 0.16
|
|
|
|
2016-07-11 Hannes von Haugwitz <hannes@vonhaugwitz.com>
|
|
* Fix example aide.conf (xattr -> xattrs)
|
|
* aide.conf.5: update "SELECTION LINES" section
|
|
* Released version 0.16rc1
|
|
|
|
2016-07-10 Hannes von Haugwitz <hannes@vonhaugwitz.com>
|
|
* Fix compilation with latest libaudit
|
|
* Use AC_PROG_CC_C99 instead of AC_PROG_CC
|
|
* Add AM_PROG_CC_C_O
|
|
* aide.conf.in: logfile -> file
|
|
* Update README
|
|
* Update manual pages (aide.1 and aide.conf.5)
|
|
|
|
2016-07-07 Hannes von Haugwitz <hannes@vonhaugwitz.com>
|
|
* Adapt manual to version 0.16
|
|
|
|
2016-06-08 Hannes von Haugwitz <hannes@vonhaugwitz.com>
|
|
* Add missing break statements
|
|
|
|
2016-04-15 Hannes von Haugwitz <hannes@vonhaugwitz.com>
|
|
* Released version 0.16b1
|
|
|
|
2016-04-13 Hannes von Haugwitz <hannes@vonhaugwitz.com>
|
|
* Fix spelling errors
|
|
diff --git a/doc/aide.1.in b/doc/aide.1.in
|
|
index 932810eebd2eda353c2f30ce89a042e5f9d69a51..e932b8d0273e9144b09b3e1f8cf61cba2be12155 100644
|
|
--- a/doc/aide.1.in
|
|
+++ b/doc/aide.1.in
|
|
@@ -71,51 +71,61 @@ output. See aide.conf (5) section URLS for available values.
|
|
Prints out the standard help message.
|
|
.PP
|
|
.SH DIAGNOSTICS
|
|
Normally, the exit status is 0 if no errors occurred. Except when the
|
|
.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?) +"
|
|
.IP "4 * (changed files detected?)"
|
|
.PP
|
|
Additionally, the following exit codes are defined for generic error
|
|
conditions:
|
|
.IP "14 Error writing error"
|
|
.IP "15 Invalid argument error"
|
|
.IP "16 Unimplemented function error"
|
|
.IP "17 Invalid configureline error"
|
|
.IP "18 IO error"
|
|
.IP "19 Version mismatch error"
|
|
.PP
|
|
.SH NOTES
|
|
Please note that due to mmap issues, aide cannot be terminated with
|
|
SIGTERM. Use SIGKILL to terminate.
|
|
|
|
+.IP "Checksum encoding"
|
|
+
|
|
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 <encoded_checksum> | base64 \-d | hexdump \-v \-e '32/1 "%02x" "\\n"'
|
|
|
|
+.IP "Control characters"
|
|
+
|
|
+Control characters (00-31 and 127) are always escaped in log and plain report
|
|
+output. They are escaped by a literal backslash (\\) followed by exactly 3
|
|
+digits representing the character in octal notation (e.g. a newline is output
|
|
+as "\\012"). A literal backslash is not escaped unless it is followed by 3 digits
|
|
+(0-9), in this case the literal backslash is escaped as "\\134".
|
|
+
|
|
.PP
|
|
.SH FILES
|
|
.IP \fB@sysconfdir@/aide.conf\fR
|
|
Default aide configuration file.
|
|
.IP \fB@localstatedir@/lib/aide/aide.db\fR
|
|
Default aide database.
|
|
.IP \fB@localstatedir@/lib/aide/aide.db.new\fR
|
|
Default aide output database.
|
|
.SH SEE ALSO
|
|
.BR aide.conf (5)
|
|
.BR manual.html
|
|
.SH BUGS
|
|
There are probably bugs in this release. Please report them
|
|
at http://sourceforge.net/projects/aide . Bug fixes are more than welcome.
|
|
Unified diffs are preferred.
|
|
.SH DISCLAIMER
|
|
All trademarks are the property of their respective owners.
|
|
No animals were harmed while making this webpage or this piece of
|
|
software. Although some pizza delivery guy's feelings were hurt.
|
|
.BR
|
|
diff --git a/include/util.h b/include/util.h
|
|
index 79988536c974ca83b14696380f6006031e0fa5e4..68e6ee2a905856bc7b73f1a67633585e0c1d814d 100644
|
|
--- a/include/util.h
|
|
+++ b/include/util.h
|
|
@@ -22,48 +22,51 @@
|
|
#ifndef _UTIL_H_INCLUDED
|
|
#define _UTIL_H_INCLUDED
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include "db_config.h"
|
|
|
|
#define HEXD2ASC(x) (((x) < 10) ? ((x) + '0') : ((x) - 10 + 'A'))
|
|
|
|
#define ASC2HEXD(x) (((x) >= '0' && (x) <= '9') ? \
|
|
((x) - '0') : (toupper(x) - 'A' + 10))
|
|
|
|
#define ISXDIGIT(x) isxdigit ((unsigned char)(x))
|
|
|
|
#define CLEANDUP(x) (contains_unsafe (x) ? encode_string (x) : strdup (x))
|
|
|
|
#ifndef HAVE_STRICMP
|
|
# define stricmp(a,b) strcasecmp( (a), (b) )
|
|
#endif
|
|
|
|
int cmpurl(url_t*, url_t*);
|
|
|
|
url_t* parse_url(char*);
|
|
|
|
int contains_unsafe(const char*);
|
|
|
|
+char *strnesc(const char *, size_t);
|
|
+char *stresc(const char *);
|
|
+
|
|
void decode_string(char*);
|
|
|
|
char* encode_string(const char*);
|
|
|
|
char* perm_to_char(mode_t perm);
|
|
|
|
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
|
|
|
|
#ifndef HAVE_STRNLEN
|
|
size_t strnlen(const char *s, size_t maxlen);
|
|
#endif
|
|
|
|
int syslog_facility_lookup(char *);
|
|
|
|
#endif
|
|
diff --git a/src/aide.c b/src/aide.c
|
|
index 8dd38b7c5a7130cc1136d0ee30f5addc9c2226e5..2b7eee14b6e1d4351ca5ddc9387344bd88a8951c 100644
|
|
--- a/src/aide.c
|
|
+++ b/src/aide.c
|
|
@@ -164,54 +164,60 @@ static int read_param(int argc,char**argv)
|
|
error(0,_("-B must have a parameter\n"));
|
|
exit(INVALID_ARGUMENT_ERROR);
|
|
}
|
|
break;
|
|
}
|
|
case 'A': {
|
|
if (optarg!=NULL) {
|
|
int errorno=commandconf('A',optarg);
|
|
if (errorno!=0){
|
|
error(0,_("Configuration error in after statement:%s\n"),optarg);
|
|
exit(INVALID_CONFIGURELINE_ERROR);
|
|
}
|
|
} else {
|
|
error(0,_("-A must have a parameter\n"));
|
|
exit(INVALID_ARGUMENT_ERROR);
|
|
}
|
|
break;
|
|
}
|
|
case 'l': {
|
|
if (optarg!=NULL) {
|
|
const char* pcre_error;
|
|
int pcre_erroffset;
|
|
conf->limit=malloc(strlen(optarg)+1);
|
|
strcpy(conf->limit,optarg);
|
|
if((conf->limit_crx=pcre_compile(conf->limit, PCRE_ANCHORED, &pcre_error, &pcre_erroffset, NULL)) == NULL) {
|
|
- error(0,_("Error in limit regexp '%s' at %i: %s\n"), conf->limit, pcre_erroffset, pcre_error);
|
|
+ char *limit_safe = stresc(conf->limit);
|
|
+ error(0,_("Error in limit regexp '%s' at %i: %s\n"), limit_safe, pcre_erroffset, pcre_error);
|
|
+ free(limit_safe);
|
|
exit(INVALID_ARGUMENT_ERROR);
|
|
}
|
|
- error(200,_("Limit set to '%s'\n"), conf->limit);
|
|
+ {
|
|
+ char *limit_safe = stresc(conf->limit);
|
|
+ error(200,_("Limit set to '%s'\n"), limit_safe);
|
|
+ free(limit_safe);
|
|
+ }
|
|
} else {
|
|
error(0,_("-l must have an argument\n"));
|
|
exit(INVALID_ARGUMENT_ERROR);
|
|
}
|
|
break;
|
|
}
|
|
case 'r': {
|
|
if(optarg!=NULL) {
|
|
do_repurldef(optarg);
|
|
}else {
|
|
error(0,_("-r must have an argument\n"));
|
|
}
|
|
break;
|
|
}
|
|
case 'i': {
|
|
if(conf->action==0){
|
|
conf->action=DO_INIT;
|
|
}else {
|
|
error(0,
|
|
_("Cannot have multiple commands on a single commandline.\n"));
|
|
exit(INVALID_ARGUMENT_ERROR);
|
|
};
|
|
break;
|
|
}
|
|
case 'C': {
|
|
@@ -566,53 +572,57 @@ int main(int argc,char**argv)
|
|
if(cmpurl(conf->db_in_url,conf->db_out_url)==RETOK){
|
|
error(4,_("WARNING:Input and output database urls are the same.\n"));
|
|
if((conf->action&DO_INIT)&&(conf->action&DO_COMPARE)){
|
|
error(0,_("Input and output database urls cannot be the same "
|
|
"when doing database update\n"));
|
|
exit(INVALID_ARGUMENT_ERROR);
|
|
}
|
|
if(conf->action&DO_DIFF){
|
|
error(0,_("Both input databases cannot be the same "
|
|
"when doing database compare\n"));
|
|
exit(INVALID_ARGUMENT_ERROR);
|
|
}
|
|
};
|
|
if((conf->action&DO_DIFF)&&(!(conf->db_new_url)||!(conf->db_in_url))){
|
|
error(0,_("Must have both input databases defined for "
|
|
"database compare.\n"));
|
|
exit(INVALID_ARGUMENT_ERROR);
|
|
}
|
|
if (conf->action&(DO_INIT|DO_COMPARE) && conf->root_prefix_length > 0) {
|
|
DIR *dir;
|
|
if((dir = opendir(conf->root_prefix)) != NULL) {
|
|
closedir(dir);
|
|
} else {
|
|
char* er=strerror(errno);
|
|
if (er!=NULL) {
|
|
- error(0,"opendir() for root prefix %s failed: %s\n", conf->root_prefix,er);
|
|
+ char *rp_safe = stresc(conf->root_prefix);
|
|
+ error(0,"opendir() for root prefix %s failed: %s\n", rp_safe,er);
|
|
+ free(rp_safe);
|
|
} else {
|
|
- error(0,"opendir() for root prefix %s failed: %i\n", conf->root_prefix,errno);
|
|
+ char *rp_safe = stresc(conf->root_prefix);
|
|
+ error(0,"opendir() for root prefix %s failed: %i\n", rp_safe,errno);
|
|
+ free(rp_safe);
|
|
}
|
|
exit(INVALID_ARGUMENT_ERROR);
|
|
}
|
|
}
|
|
#ifdef WITH_MHASH
|
|
byte* dig=NULL;
|
|
char* digstr=NULL;
|
|
|
|
if(conf->config_check&&FORCECONFIGMD){
|
|
error(0,"Can't give config checksum when compiled with --enable-forced_configmd\n");
|
|
exit(INVALID_ARGUMENT_ERROR);
|
|
}
|
|
|
|
if((conf->do_configmd||conf->config_check)&& conf->confmd!=0){
|
|
/* The patch automatically adds a newline so will also have to add it. */
|
|
if(newlinelastinconfig==0){
|
|
mhash(conf->confmd,"\n",1);
|
|
};
|
|
mhash(conf->confmd, NULL,0);
|
|
dig=(byte*)malloc(sizeof(byte)*mhash_get_block_size(conf->confhmactype));
|
|
mhash_deinit(conf->confmd,(void*)dig);
|
|
digstr=encode_base64(dig,mhash_get_block_size(conf->confhmactype));
|
|
|
|
if(!conf->config_check||FORCECONFIGMD){
|
|
if(strncmp(digstr,conf->old_confmdstr,strlen(digstr))!=0){
|
|
diff --git a/src/compare_db.c b/src/compare_db.c
|
|
index c17828d3e8b732096e00253f21623339f2168ccf..41e216527a9b05b90f1b601a61279fd408e2df71 100644
|
|
--- a/src/compare_db.c
|
|
+++ b/src/compare_db.c
|
|
@@ -504,175 +504,225 @@ static void print_line(seltree* node) {
|
|
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);
|
|
+ {
|
|
+ char *filename_safe = stresc((node->checked&NODE_REMOVED?node->old_data:node->new_data)->filename);
|
|
+ error(2,"\n%s: %s", summary, filename_safe);
|
|
+ free(filename_safe);
|
|
+ }
|
|
free(summary); summary=NULL;
|
|
} else {
|
|
if (node->checked&NODE_ADDED) {
|
|
- error(2,"added: %s\n",(node->new_data)->filename);
|
|
+ {
|
|
+ char *filename_safe = stresc((node->new_data)->filename);
|
|
+ error(2,"added: %s\n",filename_safe);
|
|
+ free(filename_safe);
|
|
+ }
|
|
} else if (node->checked&NODE_REMOVED) {
|
|
- error(2,"removed: %s\n",(node->old_data)->filename);
|
|
+ {
|
|
+ char *filename_safe = stresc((node->old_data)->filename);
|
|
+ error(2,"removed: %s\n",filename_safe);
|
|
+ free(filename_safe);
|
|
+ }
|
|
} else if (node->checked&NODE_CHANGED) {
|
|
- error(2,"changed: %s\n",(node->new_data)->filename);
|
|
+ {
|
|
+ char *filename_safe = stresc((node->new_data)->filename);
|
|
+ error(2,"changed: %s\n",filename_safe);
|
|
+ free(filename_safe);
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
+ {
|
|
+ char *filename_safe = stresc((nline==NULL?oline:nline)->filename);
|
|
+ error(2,"%s\n", filename_safe);
|
|
+ free(filename_safe);
|
|
+ }
|
|
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<onumber || i<nnumber) {
|
|
- olen = i<onumber?strlen(ovalue[i]):0;
|
|
- nlen = i<nnumber?strlen(nvalue[i]):0;
|
|
+ char *ov = i<onumber?stresc(ovalue[i]):NULL;
|
|
+ char *nv = i<nnumber?stresc(nvalue[i]):NULL;
|
|
+ olen = ov?strlen(ov):0;
|
|
+ nlen = nv?strlen(nv):0;
|
|
k = 0;
|
|
while (olen-p*k >= 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]:"");
|
|
+ error(2," %s%-9s%c %-*c %.*s\n", width_details%2?"":" ", i+k?"":details_string[j], i+k?' ':':', p, ' ', p-1, nlen-c>0?&nv[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]:"");
|
|
+ error(2," %s%-9s%c %.*s\n", width_details%2?"":" ", i+k?"":details_string[j], i+k?' ':':', p-1, olen-c>0?&ov[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]:"");
|
|
+ error(2," %s%-9s%c %-*.*s| %.*s\n", width_details%2?"":" ", i+k?"":details_string[j], i+k?' ':':', p, p-1, olen-c>0?&ov[c]:"", p-1, nlen-c>0?&nv[c]:"");
|
|
}
|
|
k++;
|
|
}
|
|
++i;
|
|
+ free(ov);
|
|
+ free(nv);
|
|
}
|
|
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);
|
|
+ {
|
|
+ char *filename_safe = stresc((nline==NULL?oline:nline)->filename);
|
|
+ error(0,"%s", filename_safe);
|
|
+ free(filename_safe);
|
|
+ }
|
|
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]);
|
|
+ {
|
|
+ char *val_safe = stresc(ovalue[i]);
|
|
+ error(0, "%s|", val_safe);
|
|
+ free(val_safe);
|
|
+ }
|
|
}
|
|
|
|
error(0, ";%s_new=|", details_string[j]);
|
|
|
|
for (i = 0 ; i < nnumber ; i++) {
|
|
- error(0, "%s|", nvalue[i]);
|
|
+ {
|
|
+ char *val_safe = stresc(nvalue[i]);
|
|
+ error(0, "%s|", val_safe);
|
|
+ free(val_safe);
|
|
+ }
|
|
}
|
|
|
|
} else {
|
|
|
|
- error(0, ";%s_old=%s;%s_new=%s", details_string[j], *ovalue, details_string[j], *nvalue);
|
|
+ {
|
|
+ char *ov_safe = stresc(*ovalue);
|
|
+ char *nv_safe = stresc(*nvalue);
|
|
+ error(0, ";%s_old=%s;%s_new=%s", details_string[j], ov_safe, details_string[j], nv_safe);
|
|
+ free(ov_safe);
|
|
+ free(nv_safe);
|
|
+ }
|
|
|
|
}
|
|
|
|
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);
|
|
+ {
|
|
+ char *filename_safe = stresc(line->filename);
|
|
+ error(0,"%s; added\n", filename_safe);
|
|
+ free(filename_safe);
|
|
+ }
|
|
|
|
}
|
|
|
|
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);
|
|
+ {
|
|
+ char *filename_safe = stresc(line->filename);
|
|
+ error(0,"%s; removed\n", filename_safe);
|
|
+ free(filename_safe);
|
|
+ }
|
|
|
|
}
|
|
|
|
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++;
|
|
@@ -739,51 +789,53 @@ static void print_syslog_format(seltree* node) {
|
|
}
|
|
|
|
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);
|
|
+ char *limit_safe = stresc(conf->limit);
|
|
+ error (2,_("Limit: %s"), limit_safe);
|
|
+ free(limit_safe);
|
|
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));
|
|
}
|
|
diff --git a/src/db_sql.c b/src/db_sql.c
|
|
index 154579070ccacb6e9b6b8393b989eb50c843e71d..09a32504c317607150174d2bec0fcddf47992995 100644
|
|
--- a/src/db_sql.c
|
|
+++ b/src/db_sql.c
|
|
@@ -16,50 +16,51 @@
|
|
*
|
|
* 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"
|
|
/*for locale support*/
|
|
#include "locale-aide.h"
|
|
/*for locale support*/
|
|
|
|
#ifdef WITH_PSQL
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <gcrypt.h>
|
|
#include "base64.h"
|
|
#include "db.h"
|
|
|
|
#include "db_sql.h"
|
|
#include "db_config.h"
|
|
#include "libpq-fe.h"
|
|
#include "report.h"
|
|
+#include "util.h"
|
|
|
|
#ifdef WITH_MHASH
|
|
#include <mhash.h>
|
|
#endif
|
|
|
|
char* db_get_sql(db_line*,db_config*);
|
|
|
|
int _db_check_result(PGconn *conn, PGresult *res, char *query)
|
|
{
|
|
int status = 0;
|
|
int ret = RETOK;
|
|
|
|
|
|
if (!res || ( (PQresultStatus(res) != PGRES_COMMAND_OK) &&
|
|
(PQresultStatus(res) != PGRES_TUPLES_OK) )){
|
|
ret = RETFAIL;
|
|
if (res!=NULL) {
|
|
error(0,"Sql error %s while doing %s\n", PQerrorMessage(conn), query);
|
|
} else {
|
|
error(0,"Sql error while doing %s.\n",query);
|
|
}
|
|
} else {
|
|
error(255,"Sql went ok.\n");
|
|
status = 1;
|
|
}
|
|
@@ -281,51 +282,55 @@ db_line* db_readline_sql(int db, db_config* conf) {
|
|
db_readline_sql_byte((void*)&(rline->haval),db,db_haval, conf);
|
|
db_readline_sql_byte((void*)&(rline->gost),db,db_gost, conf);
|
|
#endif
|
|
db_readline_sql_char((void*)&(rline->fullpath),db,db_filename, conf);
|
|
rline->filename=rline->fullpath;
|
|
db_readline_sql_char((void*)&(rline->linkname),db,db_linkname, conf);
|
|
|
|
db_readline_sql_int((void*)&(rline->perm),db,db_perm, conf);
|
|
db_readline_sql_int((void*)&(rline->uid),db,db_uid, conf);
|
|
db_readline_sql_int((void*)&(rline->gid),db,db_gid, conf);
|
|
db_readline_sql_int((void*)&(rline->inode),db,db_inode, conf);
|
|
db_readline_sql_int((void*)&(rline->nlink),db,db_lnkcount, conf);
|
|
|
|
db_readline_sql_int((void*)&(rline->size),db,*db_osize, conf);
|
|
db_readline_sql_int((void*)&(rline->bcount),db,db_bcount, conf);
|
|
db_readline_sql_int((void*)&(rline->attr),db,db_attr, conf);
|
|
|
|
db_readline_sql_time((void*)&(rline->atime),db,db_atime, conf);
|
|
db_readline_sql_time((void*)&(rline->ctime),db,db_ctime, conf);
|
|
db_readline_sql_time((void*)&(rline->mtime),db,db_mtime, conf);
|
|
#ifdef WITH_ACL
|
|
rline->acl=NULL;
|
|
#endif
|
|
((psql_data*)(*db_filep))->curread++;
|
|
|
|
- error(255,"filename %s\n",rline->filename);
|
|
+ {
|
|
+ char *filename_safe = stresc(rline->filename);
|
|
+ error(255,"filename %s\n",filename_safe);
|
|
+ free(filename_safe);
|
|
+ }
|
|
|
|
return rline;
|
|
}
|
|
|
|
|
|
void sql_writeint(int data,char *s,int i){
|
|
char t[10];
|
|
t[0]=0;
|
|
if (i!=0) {
|
|
s = strcat(s,",");
|
|
}
|
|
sprintf(t,"%i",data);
|
|
|
|
strcat(s,t);
|
|
|
|
}
|
|
|
|
void sql_writeoct(int data,char *s,int i){
|
|
char t[10];
|
|
t[0]=0;
|
|
if (i!=0) {
|
|
s = strcat(s,",");
|
|
}
|
|
sprintf(t,"%lo",data);
|
|
|
|
diff --git a/src/do_md.c b/src/do_md.c
|
|
index 77d2e15f5f9cdba5168a92feaf2f97128e705f36..4a648b6f5ff14edd553a3f8d94b1171708ccadaf 100644
|
|
--- a/src/do_md.c
|
|
+++ b/src/do_md.c
|
|
@@ -16,50 +16,51 @@
|
|
* 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"
|
|
|
|
#ifndef _POSIX_C_SOURCE
|
|
#define _POSIX_C_SOURCE 200112L
|
|
#endif
|
|
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include "md.h"
|
|
+#include "util.h"
|
|
|
|
#include "db_config.h"
|
|
#include "do_md.h"
|
|
#include "report.h"
|
|
#include "list.h"
|
|
/*for locale support*/
|
|
#include "locale-aide.h"
|
|
/*for locale support*/
|
|
|
|
|
|
/* This define should be somewhere else */
|
|
#define READ_BLOCK_SIZE 16777216
|
|
|
|
#ifdef WITH_MHASH
|
|
#include <mhash.h>
|
|
#endif /* WITH_MHASH */
|
|
|
|
/* Redhat 5.0 needs this */
|
|
#ifdef HAVE_MMAP
|
|
#ifndef MAP_FAILED
|
|
#define MAP_FAILED (-1)
|
|
#endif /* MAP_FAILED */
|
|
#define MMAP_BLOCK_SIZE 16777216
|
|
#endif /* HAVE_MMAP */
|
|
|
|
@@ -206,55 +207,59 @@ void calc_md(struct AIDE_STAT_TYPE* old_fs,db_line* line) {
|
|
from we are about to calculate the hash is the correct one,
|
|
and we don't read from a pipe :)
|
|
*/
|
|
struct AIDE_STAT_TYPE fs;
|
|
int stat_diff,filedes;
|
|
#ifdef WITH_PRELINK
|
|
pid_t pid;
|
|
#endif
|
|
|
|
error(255,"calc_md called\n");
|
|
#ifdef _PARAMETER_CHECK_
|
|
if (line==NULL) {
|
|
abort();
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_O_NOATIME
|
|
filedes=open(line->fullpath,O_RDONLY|O_NOATIME);
|
|
if(filedes<0)
|
|
#endif
|
|
filedes=open(line->fullpath,O_RDONLY);
|
|
|
|
if (filedes==-1) {
|
|
char* er=strerror(errno);
|
|
if (er!=NULL) {
|
|
+ char *fp_safe = stresc(line->fullpath);
|
|
error(3,"do_md(): open() for %s failed: %s\n",
|
|
- line->fullpath,er);
|
|
+ fp_safe,er);
|
|
+ free(fp_safe);
|
|
} else {
|
|
+ char *fp_safe = stresc(line->fullpath);
|
|
error(3,"do_md(): open() for %s failed: %i\n",
|
|
- line->fullpath,errno);
|
|
+ fp_safe,errno);
|
|
+ free(fp_safe);
|
|
}
|
|
/*
|
|
Nop. Cannot cal hashes. Mark it.
|
|
*/
|
|
no_hash(line);
|
|
return;
|
|
}
|
|
|
|
AIDE_FSTAT_FUNC(filedes,&fs);
|
|
if(!(line->attr&DB_RDEV))
|
|
fs.st_rdev=0;
|
|
|
|
#ifdef HAVE_POSIX_FADVISE
|
|
if (posix_fadvise(filedes,0,fs.st_size,POSIX_FADV_NOREUSE)!=0) {
|
|
error(255,"posix_fadvise error %s\n",strerror(errno));
|
|
} else {
|
|
error(255,"posix_fadvise(%i,0,%li,POSIX_FADV_NOREUSE) ok\n",filedes,fs.st_size);
|
|
}
|
|
#endif
|
|
if ((stat_diff=stat_cmp(&fs,old_fs))==RETOK) {
|
|
/*
|
|
Now we have a 'valid' filehandle to read from a file.
|
|
*/
|
|
|
|
#ifdef WITH_PRELINK
|
|
@@ -288,51 +293,55 @@ void calc_md(struct AIDE_STAT_TYPE* old_fs,db_line* line) {
|
|
off_t curpos=0;
|
|
|
|
r_size=fs.st_size;
|
|
/* in mmap branch r_size is used as size remaining */
|
|
while(r_size>0){
|
|
if(r_size<MMAP_BLOCK_SIZE){
|
|
#ifdef __hpux
|
|
buf = mmap(0,r_size,PROT_READ,MAP_PRIVATE,filedes,curpos);
|
|
#else
|
|
buf = mmap(0,r_size,PROT_READ,MAP_SHARED,filedes,curpos);
|
|
#endif
|
|
curpos+=r_size;
|
|
size=r_size;
|
|
r_size=0;
|
|
}else {
|
|
#ifdef __hpux
|
|
buf = mmap(0,MMAP_BLOCK_SIZE,PROT_READ,MAP_PRIVATE,filedes,curpos);
|
|
#else
|
|
buf = mmap(0,MMAP_BLOCK_SIZE,PROT_READ,MAP_SHARED,filedes,curpos);
|
|
#endif
|
|
curpos+=MMAP_BLOCK_SIZE;
|
|
size=MMAP_BLOCK_SIZE;
|
|
r_size-=MMAP_BLOCK_SIZE;
|
|
}
|
|
if ( buf == MAP_FAILED ) {
|
|
- error(0,"error mmap'ing %s: %s\n", line->fullpath,strerror(errno));
|
|
+ {
|
|
+ char *fp_safe = stresc(line->fullpath);
|
|
+ error(0,"error mmap'ing %s: %s\n", fp_safe,strerror(errno));
|
|
+ free(fp_safe);
|
|
+ }
|
|
close(filedes);
|
|
close_md(&mdc);
|
|
return;
|
|
}
|
|
conf->catch_mmap=1;
|
|
if (update_md(&mdc,buf,size)!=RETOK) {
|
|
error(0,"Message digest failed during update\n");
|
|
close(filedes);
|
|
close_md(&mdc);
|
|
munmap(buf,size);
|
|
return;
|
|
}
|
|
munmap(buf,size);
|
|
conf->catch_mmap=0;
|
|
}
|
|
/* we have used MMAP, let's return */
|
|
close_md(&mdc);
|
|
md2line(&mdc,line);
|
|
close(filedes);
|
|
return;
|
|
#ifdef WITH_PRELINK
|
|
}
|
|
#endif
|
|
#endif /* not HAVE_MMAP */
|
|
// buf=malloc(READ_BLOCK_SIZE);
|
|
@@ -491,53 +500,61 @@ void acl2line(db_line* line) {
|
|
ret->acl_d = NULL;
|
|
else
|
|
{
|
|
tmp = acl_to_text(acl_d, NULL);
|
|
if (!tmp || !*tmp)
|
|
ret->acl_d = NULL;
|
|
else
|
|
ret->acl_d = strdup(tmp);
|
|
acl_free(tmp);
|
|
}
|
|
|
|
acl_free(acl_a);
|
|
acl_free(acl_d);
|
|
}
|
|
line->acl = ret;
|
|
#endif
|
|
#ifdef WITH_SUN_ACL
|
|
if(DB_ACL&line->attr) { /* There might be a bug here. */
|
|
int res;
|
|
line->acl=malloc(sizeof(acl_type));
|
|
line->acl->entries=acl(line->fullpath,GETACLCNT,0,NULL);
|
|
if (line->acl->entries==-1) {
|
|
char* er=strerror(errno);
|
|
line->acl->entries=0;
|
|
if (er==NULL) {
|
|
- error(0,"ACL query failed for %s. strerror failed for %i\n",line->fullpath,errno);
|
|
+ {
|
|
+ char *fp_safe = stresc(line->fullpath);
|
|
+ error(0,"ACL query failed for %s. strerror failed for %i\n",fp_safe,errno);
|
|
+ free(fp_safe);
|
|
+ }
|
|
} else {
|
|
- error(0,"ACL query failed for %s:%s\n",line->fullpath,er);
|
|
+ {
|
|
+ char *fp_safe = stresc(line->fullpath);
|
|
+ error(0,"ACL query failed for %s:%s\n",fp_safe,er);
|
|
+ free(fp_safe);
|
|
+ }
|
|
}
|
|
} else {
|
|
line->acl->acl=malloc(sizeof(aclent_t)*line->acl->entries);
|
|
res=acl(line->fullpath,GETACL,line->acl->entries,line->acl->acl);
|
|
if (res==-1) {
|
|
error(0,"ACL error %s\n",strerror(errno));
|
|
} else {
|
|
if (res!=line->acl->entries) {
|
|
error(0,"Tried to read %i acl but got %i\n",line->acl->entries,res);
|
|
}
|
|
}
|
|
}
|
|
}else{
|
|
line->acl=NULL;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifdef WITH_XATTR
|
|
static xattrs_type *xattr_new(void) {
|
|
xattrs_type *ret = NULL;
|
|
|
|
ret = malloc(sizeof(xattrs_type));
|
|
ret->num = 0;
|
|
@@ -571,100 +588,112 @@ static void xattr_add(xattrs_type *xattrs, const char *key, const char
|
|
|
|
xattrs->num += 1;
|
|
}
|
|
|
|
void xattrs2line(db_line *line) {
|
|
/* get all generic user xattrs. */
|
|
xattrs_type *xattrs = NULL;
|
|
static ssize_t xsz = 1024;
|
|
static char *xatrs = NULL;
|
|
ssize_t xret = -1;
|
|
|
|
if (!(DB_XATTRS&line->attr))
|
|
return;
|
|
|
|
/* assume memory allocs work, like rest of AIDE code... */
|
|
if (!xatrs) xatrs = malloc(xsz);
|
|
|
|
while (((xret = llistxattr(line->fullpath, xatrs, xsz)) == -1) && (errno == ERANGE)) {
|
|
xsz <<= 1;
|
|
xatrs = realloc(xatrs, xsz);
|
|
}
|
|
|
|
if ((xret == -1) && ((errno == ENOSYS) || (errno == ENOTSUP))) {
|
|
line->attr&=(~DB_XATTRS);
|
|
} else if (xret == -1) {
|
|
- error(0, "listxattrs failed for %s:%s\n", line->fullpath, strerror(errno));
|
|
+ {
|
|
+ char *fp_safe = stresc(line->fullpath);
|
|
+ error(0, "listxattrs failed for %s:%s\n", fp_safe, strerror(errno));
|
|
+ free(fp_safe);
|
|
+ }
|
|
} else if (xret) {
|
|
const char *attr = xatrs;
|
|
static ssize_t asz = 1024;
|
|
static char *val = NULL;
|
|
|
|
if (!val) val = malloc(asz);
|
|
|
|
xattrs = xattr_new();
|
|
|
|
while (xret > 0) {
|
|
size_t len = strlen(attr);
|
|
ssize_t aret = 0;
|
|
|
|
if (strncmp(attr, "user.", strlen("user.")) &&
|
|
strncmp(attr, "root.", strlen("root.")))
|
|
goto next_attr; /* only store normal xattrs, and SELinux */
|
|
|
|
while (((aret = getxattr(line->fullpath, attr, val, asz)) ==
|
|
-1) && (errno == ERANGE)) {
|
|
asz <<= 1;
|
|
val = realloc (val, asz);
|
|
}
|
|
|
|
if (aret != -1)
|
|
xattr_add(xattrs, attr, val, aret);
|
|
else if (errno != ENOATTR)
|
|
- error(0, "getxattr failed for %s:%s\n", line->fullpath, strerror(errno));
|
|
+ {
|
|
+ char *fp_safe = stresc(line->fullpath);
|
|
+ error(0, "getxattr failed for %s:%s\n", fp_safe, strerror(errno));
|
|
+ free(fp_safe);
|
|
+ }
|
|
|
|
next_attr:
|
|
attr += len + 1;
|
|
xret -= len + 1;
|
|
}
|
|
}
|
|
|
|
line->xattrs = xattrs;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WITH_SELINUX
|
|
void selinux2line(db_line *line) {
|
|
char *cntx = NULL;
|
|
|
|
if (!(DB_SELINUX&line->attr))
|
|
return;
|
|
|
|
if (lgetfilecon_raw(line->fullpath, &cntx) == -1) {
|
|
line->attr&=(~DB_SELINUX);
|
|
if ((errno != ENOATTR) && (errno != EOPNOTSUPP))
|
|
- error(0, "lgetfilecon_raw failed for %s:%s\n", line->fullpath, strerror(errno));
|
|
+ {
|
|
+ char *fp_safe = stresc(line->fullpath);
|
|
+ error(0, "lgetfilecon_raw failed for %s:%s\n", fp_safe, strerror(errno));
|
|
+ free(fp_safe);
|
|
+ }
|
|
return;
|
|
}
|
|
|
|
line->cntx = strdup(cntx);
|
|
|
|
freecon(cntx);
|
|
}
|
|
#endif
|
|
|
|
#ifdef WITH_E2FSATTRS
|
|
void e2fsattrs2line(db_line* line) {
|
|
unsigned long flags;
|
|
if (DB_E2FSATTRS&line->attr) {
|
|
if (fgetflags(line->fullpath, &flags) == 0) {
|
|
line->e2fsattrs=flags;
|
|
} else {
|
|
line->attr&=(~DB_E2FSATTRS);
|
|
line->e2fsattrs=0;
|
|
}
|
|
} else {
|
|
line->e2fsattrs=0;
|
|
}
|
|
}
|
|
#endif
|