1
/* aide, Advanced Intrusion Detection Environment
3
* Copyright (C) 1999,2000 Rami Lehti,Pablo Virolainen
4
* $Header: /cvs-root-aide/aide/src/gen_list.c,v 1.82 2002/02/11 09:27:23 rammer Exp $
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License as
8
* published by the Free Software Foundation; either version 2 of the
9
* License, or (at your option) any later version.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
#include <sys/types.h>
35
#include "gnu_regex.h"
39
#include "db_config.h"
41
/*for locale support*/
42
#include "locale-aide.h"
43
/*for locale support*/
54
char* strrxtok(char* rx)
59
/* This assumes that the first character is a slash */
62
/* i=0 because we want to return at least the first slash */
63
for(i=1;i<strlen(rx);i++){
75
/* FIXME: The '\\' character should be handled more gracefully. */
76
/* That is, if it is the only special character then */
77
/* The next character should be taken literally so */
78
/* that the search would be more efficient */
87
p=(char*)malloc(sizeof(char)*lastslash+1);
88
strncpy(p,rx,lastslash);
95
char* strlastslash(char*str)
101
for(i=1;i<strlen(str);i++){
107
p=(char*)malloc(sizeof(char)*lastslash+1);
108
strncpy(p,str,lastslash);
114
seltree* get_seltree_node(seltree* tree,char* path)
123
if(strncmp(path,tree->path,strlen(path)+1)==0){
127
for(r=tree->childs;r;r=r->next){
128
node=get_seltree_node((seltree*)r->data,path);
137
void copy_rule_ref(seltree* node, rx_rule* r)
140
node->conf_lineno = r->conf_lineno;
141
node->rx=(char*)malloc(strlen(r->rx)+1);
142
strcpy(node->rx,r->rx);
144
node->conf_lineno = -1;
149
seltree* new_seltree_node(
156
seltree* parent=NULL;
158
node=(seltree*)malloc(sizeof(seltree));
161
node->sel_rx_lst=NULL;
162
node->neg_rx_lst=NULL;
163
node->equ_rx_lst=NULL;
166
copy_rule_ref(node,r);
170
parent=get_seltree_node(tree,strrxtok(path));
172
parent=get_seltree_node(tree,strlastslash(path));
176
parent=new_seltree_node(tree,strrxtok(path),isrx,r);
178
parent=new_seltree_node(tree,strlastslash(path),isrx,r);
182
parent->childs=list_append(parent->childs,(void*)node);
190
void gen_seltree(list* rxlist,seltree* tree,char type)
192
regex_t* rxtmp = NULL;
193
seltree* curnode = NULL;
198
for(r=rxlist;r;r=r->next){
200
rx_rule* curr_rule = (rx_rule*)r->data;
203
rxtok=strrxtok(curr_rule->rx);
204
curnode=get_seltree_node(tree,rxtok);
206
curnode=new_seltree_node(tree,rxtok,1,curr_rule);
209
/* We have to add '^' to the first charaster of string...
213
data=(char*)malloc(strlen(curr_rule->rx)+1+1);
216
error(0,_("Not enough memory for regexpr compile... exiting..\n"));
220
/* FIX ME! (returnvalue) */
222
strcpy(data+1,curr_rule->rx);
226
rxtmp=(regex_t*)malloc(sizeof(regex_t));
227
if( regcomp(rxtmp,data,REG_EXTENDED|REG_NOSUB)){
228
error(0,_("Error in selective regexp:%s"),curr_rule->rx);
231
/* replace regexp text with regexp compiled */
232
rxc=(rx_rule*)malloc(sizeof(rx_rule));
234
/* and copy the rest */
236
rxc->attr=curr_rule->attr;
237
rxc->conf_lineno=curr_rule->conf_lineno;
241
curnode->sel_rx_lst=list_append(curnode->sel_rx_lst,(void*)rxc);
245
curnode->neg_rx_lst=list_append(curnode->neg_rx_lst,(void*)rxc);
249
curnode->equ_rx_lst=list_append(curnode->equ_rx_lst,(void*)rxc);
254
/* Data should not be free'ed because it's in rxc struct
255
* and freeing is done if error occour.
262
list* add_file_to_list(list* listp,char*filename,int attr,int* addok)
266
struct AIDE_STAT_TYPE fs;
269
error(220, _("Adding %s to filelist\n"),filename);
271
fil=(db_line*)malloc(sizeof(db_line));
272
fil->attr=attr|DB_FILENAME|DB_LINKNAME;
273
fil->filename=(char*)malloc(sizeof(char)*strlen(filename)+1);
274
strncpy(fil->filename,filename,strlen(filename));
275
fil->filename[strlen(filename)]='\0';
276
/* We want to use lstat here instead of stat since we want *
277
* symlinks stats not the file that it points to. */
278
sres=AIDE_LSTAT_FUNC(fil->filename,&fs);
280
char* er=strerror(errno);
282
error(0,"lstat() failed for %s. strerror failed for %i\n",fil->filename,errno);
284
error(0,"lstat() failed for %s:%s\n",fil->filename,strerror(errno));
294
if (cur_time==(time_t)-1) {
295
char* er=strerror(errno);
297
error(0,_("Can not get current time. strerror failed for %i\n"),errno);
299
error(0,_("Can not get current time with reason %s\n"),er);
303
if(fs.st_atime>cur_time){
304
error(CLOCK_SKEW,_("%s atime in future\n"),fil->filename);
306
if(fs.st_mtime>cur_time){
307
error(CLOCK_SKEW,_("%s mtime in future\n"),fil->filename);
309
if(fs.st_ctime>cur_time){
310
error(CLOCK_SKEW,_("%s ctime in future\n"),fil->filename);
315
Here we should check if we need to add it..
320
if (ustat(fs.st_dev, &buf) != 0 || buf.f_fname[0]==0) {
329
fil->perm_o=fs.st_mode;
330
fil->size_o=fs.st_size;
332
if((S_ISLNK(fs.st_mode))){
338
if(conf->no_acl_on_symlinks!=-1) {
339
fil->attr&=(~DB_ACL);
343
if(conf->warn_dead_symlinks!=-1) {
344
struct AIDE_STAT_TYPE fs;
346
sres=AIDE_STAT_FUNC(fil->filename,&fs);
348
error(5,"Dead symlink detected at %s\n",fil->filename);
352
if(conf->symlinks_found==0){
356
dbtmp=conf->db_out_order[1];
357
conf->db_out_order[1]=db_linkname;
358
for(it=2;it<conf->db_out_size;it++){
359
dbtmp2=conf->db_out_order[it];
360
conf->db_out_order[it]=dbtmp;
363
conf->db_out_order[conf->db_out_size++]=dbtmp;
364
conf->symlinks_found=1;
367
lnktmp=(char*)malloc(_POSIX_PATH_MAX+1);
369
error(0,_("malloc failed in add_file_to_list()\n"));
373
len=readlink(fil->filename,lnktmp,_POSIX_PATH_MAX+1);
374
lnkbuf=(char*)malloc(len+1);
376
error(0,_("malloc failed in add_file_to_list()\n"));
380
strncpy(lnkbuf,lnktmp,len);
382
fil->linkname=lnkbuf;
384
fil->attr|=DB_LINKNAME;
387
/* Just remove linkname avaivilibity bit from this entry */
388
fil->attr&=(~DB_LINKNAME);
392
if(DB_INODE&fil->attr){
393
fil->inode=fs.st_ino;
398
if(DB_UID&fil->attr) {
404
if(DB_GID&fil->attr){
410
if(DB_PERM&fil->attr){
411
fil->perm=fs.st_mode;
416
if(DB_SIZE&fil->attr||DB_SIZEG&fil->attr){
417
fil->size=fs.st_size;
422
if(DB_LNKCOUNT&fil->attr){
423
fil->nlink=fs.st_nlink;
428
if(DB_MTIME&fil->attr){
429
fil->mtime=fs.st_mtime;
434
if(DB_CTIME&fil->attr){
435
fil->ctime=fs.st_ctime;
440
if(DB_ATIME&fil->attr){
441
fil->atime=fs.st_atime;
446
if(DB_BCOUNT&fil->attr){
447
fil->bcount=fs.st_blocks;
453
if(DB_ACL&fil->attr) { /* There might be a bug here. */
455
fil->acl=malloc(sizeof(acl_type));
456
fil->acl->entries=acl(fil->filename,GETACLCNT,0,NULL);
457
if (fil->acl->entries==-1) {
458
char* er=strerror(errno);
461
error(0,"ACL query failed for %s. strerror failed for %i\n",fil->filename,errno);
463
error(0,"ACL query failed for %s:%s\n",fil->filename,er);
466
fil->acl->acl=malloc(sizeof(aclent_t)*fil->acl->entries);
467
res=acl(fil->filename,GETACL,fil->acl->entries,fil->acl->acl);
469
error(0,"ACL error %s\n",strerror(errno));
471
if (res!=fil->acl->entries) {
472
error(0,"Tried to read %i acl but got %i\n",fil->acl->entries,res);
482
if(S_ISDIR(fs.st_mode)||S_ISCHR(fs.st_mode)
483
||S_ISBLK(fs.st_mode)||S_ISFIFO(fs.st_mode)
484
||S_ISLNK(fs.st_mode)||S_ISSOCK(fs.st_mode)){
486
fil->attr&=(~DB_MD5)&(~DB_SHA1)&(~DB_RMD160)&(~DB_TIGER);
494
fil->attr&=(~DB_CRC32)&(~DB_HAVAL)&(~DB_CRC32B);
502
/* 1 if needs to be set
504
fil->md5=DB_MD5&fil->attr?(byte*)"":NULL;
505
fil->sha1=DB_SHA1&fil->attr?(byte*)"":NULL;
506
fil->tiger=DB_TIGER&fil->attr?(byte*)"":NULL;
507
fil->rmd160=DB_RMD160&fil->attr?(byte*)"":NULL;
509
fil->crc32=DB_CRC32&fil->attr?(byte*)"":NULL;
510
fil->crc32b=DB_CRC32B&fil->attr?(byte*)"":NULL;
511
fil->gost=DB_GOST&fil->attr?(byte*)"":NULL;
512
fil->haval=DB_HAVAL&fil->attr?(byte*)"":NULL;
515
listp=list_append(listp,(void*)fil);
521
int check_list_for_match(list* rxrlist,char* text,int* attr)
525
for(r=rxrlist;r;r=r->next){
526
if((retval=regexec((regex_t*)((rx_rule*)r->data)->crx,text,0,0,0))==0){
527
*attr=((rx_rule*)r->data)->attr;
528
error(231,"Matches rule from line #%ld: %s\n",((rx_rule*)r->data)->conf_lineno,((rx_rule*)r->data)->rx);
536
* Function check_node_for_match()
537
* calls itself recursively to go to the top and then back down.
538
* uses check_list_for_match()
540
* 0, if a negative rule was matched
541
* 1, if a selective rule was matched
542
* 2, if a equals rule was matched
543
* retval if no rule was matched.
544
* retval&3 if no rule was matched and first in the recursion
548
int check_node_for_match(seltree*node,char*text,int retval,int* attr)
556
/* We need this to check whether this was the first one *
557
* to be called and not a recursive call */
558
if(!((retval&16)==16)){
565
/* if no deeper match found */
566
if(!((retval&8)==8)&&!((retval&4)==4)){
567
if(!check_list_for_match(node->equ_rx_lst,text,attr)){
571
/* We'll use retval to pass information on whether to recurse
575
if(!((retval&8)==8)&&!((retval&4)==4)){
576
if(!check_list_for_match(node->sel_rx_lst,text,attr))
580
/* Now let's check the ancestors */
581
retval=check_node_for_match(node->parent,text,retval,attr);
584
/* Negative regexps are the strongest so they are checked last */
585
/* If this file is to be added */
587
if(!check_list_for_match(node->neg_rx_lst,text,attr)){
591
/* Now we discard the info whether a match was made or not *
592
* and just return 0,1 or 2 */
599
list* traverse_tree(seltree* tree,list* file_lst,int attr)
604
struct AIDE_DIRENT_TYPE* entp=NULL;
605
struct AIDE_DIRENT_TYPE** resp=NULL;
611
# ifndef HAVE_READDIR_R
616
/* Root is special and it must be checked on it's own. */
617
if( tree->path[0]=='/' && tree->path[1]=='\0' ){
618
addfile=check_node_for_match(tree,"/",0,&matchattr);
620
error(240,"%s match=%d\n",fullname, addfile);
621
file_lst=add_file_to_list(file_lst,"/",matchattr,&addok);
625
if(!(dirh=opendir(tree->path))){
626
error(5,"traverse_tree():%s: %s\n", strerror(errno),tree->path);
630
# ifdef HAVE_READDIR_R
631
resp=(struct AIDE_DIRENT_TYPE**)
632
malloc(sizeof(struct AIDE_DIRENT_TYPE)+_POSIX_PATH_MAX);
633
entp=(struct AIDE_DIRENT_TYPE*)
634
malloc(sizeof(struct AIDE_DIRENT_TYPE)+_POSIX_PATH_MAX);
636
for(rdres=AIDE_READDIR_R_FUNC(dirh,entp,resp);
637
(rdres==0&&(*resp)!=NULL);
638
rdres=AIDE_READDIR_R_FUNC(dirh,entp,resp)){
641
for(entp=AIDE_READDIR_FUNC(dirh);
642
(entp!=NULL&&td!=telldir(dirh));
643
entp=AIDE_READDIR_FUNC(dirh)){
646
# error AIDE needs readdir or readdir_r
650
if(strncmp(entp->d_name,".",1)==0){
651
if(strncmp(entp->d_name,".",strlen(entp->d_name))==0)
653
if(strncmp(entp->d_name,"..",strlen(entp->d_name))==0)
656
/* Construct fully qualified pathname for the file in question */
658
malloc(sizeof(char)*(strlen(entp->d_name)+strlen(tree->path)+2));
659
strncpy(fullname,tree->path,strlen(tree->path));
660
if(strncmp(tree->path,"/",strlen(tree->path))!=0){
661
strncpy(fullname+strlen(tree->path),"/",1);
666
strncpy(fullname+strlen(tree->path)+e,entp->d_name,strlen(entp->d_name));
667
fullname[(strlen(tree->path)+e+strlen(entp->d_name))]='\0';
668
error(230,_("Checking %s for match\n"),fullname);
669
if(attr){ /* This dir and all its subs are added by default */
672
addfile=check_node_for_match(tree,fullname,addfile,&matchattr);
675
error(240,"%s match=%d\n",fullname, addfile);
677
file_lst=add_file_to_list(file_lst,fullname,matchattr,&addok);
678
if( !(addfile&2) && addok!=RETFAIL){
679
if(S_ISDIR(((db_line*)file_lst->header->tail->data)->perm_o)){
680
a=get_seltree_node(tree,
681
((db_line*)file_lst->header->tail->data)
684
a=new_seltree_node(tree,
685
((db_line*)file_lst->header->tail->data)
688
file_lst=traverse_tree(a,file_lst,attr);
692
error(230,_("File %s does not match\n"),fullname);
694
} else{ /* This dir is not added by default */
697
addfile=check_node_for_match(tree,fullname,addfile,&matchattr);
700
error(240,"%s match=%d\n",fullname, addfile);
701
file_lst=add_file_to_list(file_lst,fullname,matchattr,&addok);
702
if(addfile!=2 && addok!=RETFAIL){
703
if(S_ISDIR(((db_line*)file_lst->header->tail->data)->perm_o)){
704
a=get_seltree_node(tree,
705
((db_line*)file_lst->header->tail->data)
708
a=new_seltree_node(tree,
709
((db_line*)file_lst->header->tail->data)
712
file_lst=traverse_tree(a,file_lst,matchattr);
716
error(230,_("File %s does not match\n"),fullname);
723
if(closedir(dirh)==-1){
724
error(0,"Closedir() failed for %s\n",tree->path);
727
# ifdef HAVE_READDIR_R
732
/* All childs are not necessarily checked yet */
733
if(tree->childs!=NULL){
734
for(r=tree->childs;r;r=r->next){
735
if(!(((seltree*)r->data)->checked)) {
736
file_lst=traverse_tree((seltree*)r->data,file_lst,attr);
745
list* gen_list(list* prxlist,list* nrxlist,list* erxlist)
750
tree=new_seltree_node(NULL,"/",0,NULL);
752
gen_seltree(prxlist,tree,'s');
753
gen_seltree(nrxlist,tree,'n');
754
gen_seltree(erxlist,tree,'e');
761
r=traverse_tree(tree,NULL,0);