/* aide, Advanced Intrusion Detection Environment * * Copyright (C) 1999-2006,2010,2011,2013 Rami Lehti, Pablo Virolainen, * Richard van den Berg, Hannes von Haugwitz * $Header$ * * 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 "db.h" #include "db_file.h" #include "db_disk.h" #include "md.h" #ifdef WITH_PSQL #include "db_sql.h" #endif #include "db_config.h" #include "report.h" #include "be.h" #ifdef WITH_MHASH #include #endif #include "base64.h" #include "util.h" /*for locale support*/ #include "locale-aide.h" /*for locale support*/ db_line* db_char2line(char** ss,int db); long readint(char* s,char* err); AIDE_OFF_TYPE readlong(char* s,char* err); long readoct(char* s,char* err); time_t base64totime_t(char*); const char* db_names[db_unknown+1] = { "name", "lname", "perm", "uid", "gid", "size", "atime", "ctime", "mtime", "inode", "bcount", "lcount", "md5", "sha1", "rmd160", "tiger", "crc32", "haval", "gost", "crc32b", "attr", "acl", "bsize", "rdev", "dev", "checkmask", "allownewfiles", "allowrmfiles", "sha256", "sha512", "whirlpool", "selinux", "xattrs", "e2fsattrs", "unknown"} ; const int db_value[db_unknown+1] = { db_filename, /* "name", */ db_linkname, /* "lname", */ db_perm, /* "perm", */ db_uid, /* "uid", */ db_gid, /* "gid", */ db_size, /* "size", */ db_atime, /* "atime", */ db_ctime, /* "ctime", */ db_mtime, /* "mtime", */ db_inode, /* "inode", */ db_bcount, /* "bcount", */ db_lnkcount, /* "lcount", */ db_md5, /* "md5", */ db_sha1, /* "sha1", */ db_rmd160, /* "rmd160", */ db_tiger, /* "tiger", */ db_crc32, /* "crc32", */ db_haval, /* "haval", */ db_gost, /* "gost", */ db_crc32b, /* "crc32b", */ db_attr, /* attributes */ db_acl, /* "acl" */ db_bsize, /* "bsize" */ db_rdev, /* "rdev" */ db_dev, /* "dev" */ db_checkmask, /* "checkmask" */ db_allownewfile, /* "allownewfile" */ db_allowrmfile, /* "allowrmfile" */ db_sha256, /* "sha256", */ db_sha512, /* "sha512", */ db_whirlpool, /* "whirlpool", */ db_selinux, /* "selinux", */ db_xattrs, /* "xattrs", */ db_e2fsattrs, /* "e2fsattrs", */ db_unknown }; /* "unknown" */ const char* db_namealias[db_alias_size] = { "count" } ; 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) { void* rv=NULL; error(200,"db_init %i\n",db); switch(db) { case DB_DISK: { /* Should we actually do something here? */ return db_disk_init(); } 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")); return RETFAIL; } conf->db_in=rv; error(200,_("db_in is nonnull\n")); return RETOK; } 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; } else{ #endif rv=be_init(0,conf->db_out_url,0); conf->db_out=rv; #ifdef WITH_ZLIB } #endif if(rv==NULL){ error(200,_("db_out is null\n")); return RETFAIL; } error(200,_("db_out is nonnull %s\n"),conf->db_out_url->value); 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")); return RETFAIL; } conf->db_new=rv; error(200,_("db_new is nonnull\n")); return RETOK; } } return RETFAIL; } db_line* db_readline(int db){ db_line* s=NULL; int i=0; url_t* db_url=NULL; FILE** db_filep=NULL; int* db_osize=0; DB_FIELD** db_order=NULL; switch (db) { case DB_DISK: { /* Nothing else to be done? */ s=db_readline_disk(); return s; } case DB_OLD: { db_url=conf->db_in_url; db_filep=&(conf->db_in); db_osize=&(conf->db_in_size); db_order=&(conf->db_in_order); break; } case DB_NEW: { db_url=conf->db_new_url; db_filep=&(conf->db_new); db_osize=&(conf->db_new_size); db_order=&(conf->db_new_order); break; } } switch (db_url->type) { #ifdef WITH_CURL case url_http: case url_https: case url_ftp: #endif /* WITH CURL */ case url_stdin: case url_fd: case url_file: { /* Should set errno */ /* Please FIXME */ if ((*db_filep)!=NULL) { char** ss=db_readline_file(db); if (ss!=NULL){ s=db_char2line(ss,db); for(i=0;i<*db_osize;i++){ if((*db_order)[i]!=db_unknown && ss[(*db_order)[i]]!=NULL){ free(ss[(*db_order)[i]]); ss[(*db_order)[i]]=NULL; } } free(ss); } } break; } #ifdef WITH_PSQL case url_sql: { error(255,"db_sql readline..."); s=db_readline_sql(db, conf); break; } #endif default : { error(0,_("db_readline():Url-type backend not implemented\n")); return NULL; } } return s; } byte* base64tobyte(char* src,int len,size_t *ret_len) { if(strcmp(src,"0")!=0){ return decode_base64(src,len,ret_len); } return NULL; } static char *db_readchar(char *s) { if (s == NULL) return (NULL); if (s[0] == '0') { if (s[1] == '\0') return (NULL); if (s[1] == '-') return (strdup("")); if (s[1] == '0') { memmove(s, s+1, strlen(s+1)+1); // Hope this removes core // dumping in some environments. Has something to do with // memory (de)allocation. } } decode_string(s); return strdup(s); } #define WARN_ONCE(x) case db_ ## x : { \ static int warn_once_ ## x = 0; \ if (! warn_once_ ## x ) \ error(0,_("Hash %s uses MHASH, which is not enabled.\n"), \ #x ); \ warn_once_ ## x = 1; \ } break db_line* db_char2line(char** ss,int db){ int i; db_line* line=(db_line*)malloc(sizeof(db_line)*1); int* db_osize=0; DB_FIELD** db_order=NULL; switch (db) { case DB_OLD: { db_osize=&(conf->db_in_size); db_order=&(conf->db_in_order); break; } case DB_NEW: { db_osize=&(conf->db_new_size); db_order=&(conf->db_new_order); break; } } line->md5=NULL; line->sha1=NULL; line->rmd160=NULL; line->tiger=NULL; line->crc32=NULL; /* MHASH stuff.. */ line->crc32b=NULL; line->haval=NULL; line->gost=NULL; line->whirlpool=NULL; line->sha256=NULL; line->sha512=NULL; line->perm=0; line->uid=0; line->gid=0; line->atime=0; line->ctime=0; line->mtime=0; line->inode=0; line->nlink=0; line->bcount=0; line->size=0; line->filename=NULL; line->fullpath=NULL; line->linkname=NULL; line->acl=NULL; line->xattrs=NULL; line->e2fsattrs=0; line->cntx=NULL; line->attr=conf->attr; /* attributes from @@dbspec */ for(i=0;i<*db_osize;i++){ switch ((*db_order)[i]) { case db_filename : { if(ss[(*db_order)[i]]!=NULL){ decode_string(ss[(*db_order)[i]]); line->fullpath=strdup(ss[(*db_order)[i]]); line->filename=line->fullpath; } else { error(0,"db_char2line():Error while reading database\n"); exit(EXIT_FAILURE); } break; } case db_linkname : { line->linkname = db_readchar(ss[(*db_order)[i]]); break; } case db_mtime : { line->mtime=base64totime_t(ss[(*db_order)[i]]); break; } case db_bcount : { line->bcount=readint(ss[(*db_order)[i]],"bcount"); break; } case db_atime : { line->atime=base64totime_t(ss[(*db_order)[i]]); break; } case db_ctime : { line->ctime=base64totime_t(ss[(*db_order)[i]]); break; } case db_inode : { line->inode=readint(ss[(*db_order)[i]],"inode"); break; } case db_uid : { line->uid=readint(ss[(*db_order)[i]],"uid"); break; } case db_gid : { line->gid=readint(ss[(*db_order)[i]],"gid"); break; } case db_size : { line->size=readlong(ss[(*db_order)[i]],"size"); break; } case db_md5 : { line->md5=base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]), NULL); break; } case db_sha1 : { line->sha1=base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]), NULL); break; } case db_rmd160 : { line->rmd160=base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]), NULL); break; } case db_tiger : { line->tiger=base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]), NULL); break; } case db_crc32 : { line->crc32=base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]), NULL); break; } case db_haval : { line->haval=base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]), NULL); break; } #ifdef WITH_MHASH case db_gost : { line->gost=base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]), NULL); break; } case db_crc32b : { line->crc32b=base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]), NULL); break; } case db_whirlpool : { line->whirlpool=base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]), NULL); break; } #else WARN_ONCE(gost); WARN_ONCE(crc32b); WARN_ONCE(whirlpool); #endif case db_sha256 : { line->sha256=base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]), NULL); break; } case db_sha512 : { line->sha512=base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]), NULL); break; } #ifdef WITH_SUN_ACL case db_acl : { char* endp,*pos; int entries,lc; line->acl=NULL; entries=strtol(ss[(*db_order)[i]],&endp,10); if (endp==ss[(*db_order)[i]]) { /* Something went wrong */ break; } pos=endp+1; /* Warning! if acl in database is corrupted then this will break down. */ line->acl=malloc(sizeof(acl_type)); line->acl->entries=entries; line->acl->acl=malloc(sizeof(aclent_t)*entries); for (lc=0;lcacl->acl[lc].a_type=strtol(pos,&endp,10); pos=endp+1; line->acl->acl[lc].a_id=strtol(pos,&endp,10); pos=endp+1; line->acl->acl[lc].a_perm=strtol(pos,&endp,10); pos=endp+1; } break; } #endif #ifdef WITH_POSIX_ACL case db_acl : { char *tval = NULL; tval = strtok(ss[(*db_order)[i]], ","); line->acl = NULL; if (tval[0] == '0') line->acl = NULL; else if (!strcmp(tval, "POSIX")) { line->acl = malloc(sizeof(acl_type)); line->acl->acl_a = NULL; line->acl->acl_d = NULL; tval = strtok(NULL, ","); line->acl->acl_a = (char *)base64tobyte(tval, strlen(tval), NULL); tval = strtok(NULL, ","); line->acl->acl_d = (char *)base64tobyte(tval, strlen(tval), NULL); } /* else, it's broken... */ break; } #endif case db_xattrs : { size_t num = 0; char *tval = NULL; tval = strtok(ss[(*db_order)[i]], ","); num = readlong(tval, "xattrs"); if (num) { line->xattrs = malloc(sizeof(xattrs_type)); line->xattrs->ents = calloc(sizeof(xattr_node), num); line->xattrs->sz = num; line->xattrs->num = num; num = 0; while (num < line->xattrs->num) { byte *val = NULL; size_t vsz = 0; tval = strtok(NULL, ","); line->xattrs->ents[num].key = db_readchar(strdup(tval)); tval = strtok(NULL, ","); val = base64tobyte(tval, strlen(tval), &vsz); line->xattrs->ents[num].val = val; line->xattrs->ents[num].vsz = vsz; ++num; } } break; } case db_selinux : { byte *val = NULL; val = base64tobyte(ss[(*db_order)[i]], strlen(ss[(*db_order)[i]]),NULL); line->cntx = (char *)val; break; } case db_perm : { line->perm=readoct(ss[(*db_order)[i]],"permissions"); break; } case db_lnkcount : { line->nlink=readint(ss[(*db_order)[i]],"nlink"); break; } case db_attr : { line->attr=readlong(ss[(*db_order)[i]],"attr"); break; } case db_e2fsattrs : { line->e2fsattrs=readlong(ss[(*db_order)[i]],"e2fsattrs"); break; } case db_unknown : { /* Unknown fields are ignored. */ break; } default : { error(0,_("Not implemented in db_char2line %i \n"),(*db_order)[i]); return NULL; } } } return line; } time_t base64totime_t(char* s){ byte* b=decode_base64(s,strlen(s),NULL); char* endp; if (b==NULL||strcmp(s,"0")==0) { /* Should we print error here? */ free(b); return 0; } else { time_t t = strtol((char *)b,&endp,10); if (endp[0]!='\0') { error(0,"Error converting base64\n"); free(b); return 0; } free(b); return t; } } long readint(char* s,char* err){ long i; char* e; i=strtol(s,&e,10); if (e[0]!='\0') { error(0,_("Could not read %s from database"),err); } return i; } AIDE_OFF_TYPE readlong(char* s,char* err){ AIDE_OFF_TYPE i; char* e; i=AIDE_STRTOLL_FUNC(s,&e,10); if (e[0]!='\0') { error(0,_("Could not read %s from database"),err); } return i; } long readoct(char* s,char* err){ long i; char* e; i=strtol(s,&e,8); if (e[0]!='\0') { error(0,_("Could not read %s from database. String %s \n"),err,s); } return i; } int db_writespec(db_config* dbconf) { switch (dbconf->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) || #endif (dbconf->db_out!=NULL)){ if(db_writespec_file(dbconf)==RETOK){ return RETOK; } } break; } #ifdef WITH_CURL case url_http: case url_https: case url_ftp: { break; } #endif /* WITH CURL */ #ifdef WITH_PSQL case url_sql: { if(dbconf->db_out!=NULL){ if(db_writespec_sql(dbconf)==RETOK){ return RETOK; } } break; } #endif default:{ error(0,_("Unknown output in db out.\n")); return RETFAIL; } } return RETFAIL; } int db_writeline(db_line* line,db_config* dbconf){ if (line==NULL||dbconf==NULL) return RETOK; switch (dbconf->db_out_url->type) { #ifdef WITH_CURL case url_http: case url_https: case url_ftp: #endif /* WITH CURL */ case url_stdout: case url_stderr: case url_fd: case url_file: { if ( #ifdef WITH_ZLIB (dbconf->gzip_dbout && dbconf->db_gzout) || #endif (dbconf->db_out!=NULL)) { if (db_writeline_file(line,dbconf,dbconf->db_out_url)==RETOK) { return RETOK; } } return RETFAIL; break; } #ifdef WITH_PSQL case url_sql: { if (dbconf->db_out!=NULL) { if (db_writeline_sql(line,dbconf)==RETOK) { return RETOK; } } return RETFAIL; break; } #endif default : { error(0,_("Unknown output in db out.\n")); return RETFAIL; } } return RETFAIL; } 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 (conf->gzip_dbout && conf->db_gzout) || #endif (conf->db_out!=NULL)) { db_close_file(conf); } break; } #ifdef WITH_CURL case url_http: case url_https: case url_ftp: { if (conf->db_out!=NULL) { url_fclose(conf->db_out); } break; } #endif /* WITH CURL */ #ifdef WITH_PSQL case url_sql: { if (conf->db_out!=NULL) { db_close_sql(conf->db_out); } break; } #endif default : { error(0,_("db_close():Unknown output in db out.\n")); } } 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) { if (dl==NULL) { return; } #define checked_free(x) do { free(x); x=NULL; } while (0) checked_free(dl->md5); checked_free(dl->sha1); checked_free(dl->rmd160); checked_free(dl->tiger); dl->filename=NULL; checked_free(dl->fullpath); checked_free(dl->linkname); #ifdef WITH_MHASH checked_free(dl->crc32); checked_free(dl->crc32b); checked_free(dl->gost); checked_free(dl->haval); #endif checked_free(dl->sha256); checked_free(dl->sha512); checked_free(dl->whirlpool); if (dl->acl) { #ifdef WITH_ACL free(dl->acl->acl_a); free(dl->acl->acl_d); #endif } checked_free(dl->acl); if (dl->xattrs) free(dl->xattrs->ents); checked_free(dl->xattrs); checked_free(dl->cntx); } const char* aide_key_5=CONFHMACKEY_05; const char* db_key_5=DBHMACKEY_05;