ausearch improvements
PATCH 1/1 ausearch improvements
Hello,
the attached patch adds some functionality to ausearch. It consists of two main parts:
ausearch_add_interpreted_item() behaves like ausearch_add_item(), but the conditions are evaluated by comparing the interpreted field value, not the raw value (e.g. ("uid", "=", "mitr") instead of ("uid", "=", "500"). In principle, the application using ausearch could contain it's own code to "un-interpret" field values, but I think it is cleaner when the only place that maps raw and interpreted value is libauparse. The current implementation simply interprets the value of each field before performing the comparison; in the future, the implementation could be changed to "un-interpret" the supplied value when creating the rule if the current implementation turns out to be too slow.
ausearch_add_timestamp_item() allows placing conditions on event timestamp.
In addition, the patch fixes checking whether the operator is unknown in ausearch_add_item().
Mirek
auparse/auparse.c +140 -22
@@ -316,12 +316,13 @@ } -int ausearch_add_item (auparse_state_t *au,const char *field,const char *op, -const char *value,ausearch_rule_t how) +static int ausearch_add_item_internal (auparse_state_t *au,const char *field, +const char *op,const char *value,ausearch_rule_t how, +ausearch_op_t op_flag) {aurulenode rn;int t_op =lookup_op (op); -if (op <0 ) +if (t_op <0 ) goto err_out;// Make sure there's a field
@@ -344,15 +345,85 @@ }// All pre-checks are done, build a rule - rn.search_op = t_op; + rn.search_op = t_op | op_flag;if (t_op ==AUSEARCH_EXISTS ) - rn.val =NULL ; + rn.v.field.val =NULL ;else {if (value ==NULL ) goto err_out; - rn.val =strdup (value); + rn.v.field.val =strdup (value); + } + rn.v.field.field =strdup (field); +aurule_append (&au->rules, &rn); + au->search_how = how; + +return 0 ; +err_out: + errno =EINVAL ; +return -1 ; +} + +int ausearch_add_item (auparse_state_t *au,const char *field,const char *op, +const char *value,ausearch_rule_t how) +{ +return ausearch_add_item_internal (au, field, op, value, how,0 ); +} + +int ausearch_add_interpreted_item (auparse_state_t *au,const char *field, +const char *op,const char *value,ausearch_rule_t how) +{ +return ausearch_add_item_internal (au, field, op, value, how, +AUSEARCH_INTERPRETED ); +} + +static int lookup_ts_op (const char *op) +{ +static const struct nv_pair ts_tab[] = { + {AUSEARCH_TIME_LT ,"<" }, + {AUSEARCH_TIME_LE ,"<=" }, + {AUSEARCH_TIME_GE ,">=" }, + {AUSEARCH_TIME_GT ,">" }, + {AUSEARCH_TIME_EQ ,"=" }, + }; + +size_t i; + +for (i =0 ; i <sizeof (ts_tab) /sizeof (*ts_tab); i++) +if (strcmp (ts_tab[i].name, op) ==0 ) +return ts_tab[i].value; + +return -1 ; +} + +int ausearch_add_timestamp_item (auparse_state_t *au,const char *op,time_t sec, +unsigned milli,ausearch_rule_t how) +{ +aurulenode rn; +int t_op =lookup_ts_op (op); +if (op <0 ) + goto err_out; +if (milli >=1000 ) + goto err_out; + +// Do not allow regex to get replaced this way +if (au->search_how ==AUSEARCH_RULE_REGEX ) + goto err_out; + +// Make sure how is within range +if (how <AUSEARCH_RULE_CLEAR || how >AUSEARCH_RULE_AND ) + goto err_out; +if (how ==AUSEARCH_RULE_CLEAR ) { +aurule_clear (&au->rules); + }else if (how != au->search_how + && au->search_how !=AUSEARCH_RULE_CLEAR ) { + errno =EEXIST ; +return -1 ; } - rn.field =strdup (field); + +// All pre-checks are done, build a rule + rn.search_op = t_op; + rn.v.timestamp.sec = sec; + rn.v.timestamp.milli = milli;aurule_append (&au->rules, &rn); au->search_how = how;
@@ -381,9 +452,9 @@ }// Store it away just in case. - rn.field =strdup (expr); rn.search_op =AUSEARCH_UNSET ; - rn.val =NULL ; + rn.v.field.field =strdup (expr); + rn.v.field.val =NULL ;aurule_append (&au->rules, &rn); au->search_how =AUSEARCH_RULE_REGEX ;
@@ -780,14 +851,71 @@return rc; } +/* Return the result of interpreting rule on the event record r. */ +static int ausearch_interpret_rule (auparse_state_t *au,rnode *r, +aurulenode *rule) +{ +int search_op; + + search_op = (rule->search_op & ~AUSEARCH_INTERPRETED ); +if (AUSEARCH_OP_IS_TIME__ (search_op)) { +int val; + +if (au->le.e.sec < rule->v.timestamp.sec) + val =-1 ; +else if (au->le.e.sec > rule->v.timestamp.sec) + val =1 ; +else if (au->le.e.milli < rule->v.timestamp.milli) + val =-1 ; +else if (au->le.e.milli > rule->v.timestamp.milli) + val =1 ; +else + val =0 ; +switch (search_op) { +case AUSEARCH_TIME_LT : +return val <0 ; +case AUSEARCH_TIME_LE : +return val <=0 ; +case AUSEARCH_TIME_GE : +return val >=0 ; +case AUSEARCH_TIME_GT : +return val >0 ; +case AUSEARCH_TIME_EQ : +return val ==0 ; +default : +abort (); + } + }else { +int found, rc; +const char *val; + + found =nvlist_find_name (&r->nv, rule->v.field.field); +if (!found) +return 0 ; +if (search_op ==AUSEARCH_EXISTS ) +return 1 ; + +if ((rule->search_op &AUSEARCH_INTERPRETED ) !=0 ) + val =nvlist_interp_cur_val (r); +else + val =nvlist_get_cur_val (&r->nv); + rc =strcmp (rule->v.field.val, val); +if (search_op ==AUSEARCH_EQUAL ) +return rc ==0 ; +else +return rc !=0 ; + } +} +/* This is called during search once per each record. It walks the list * of nvpairs and decides if a field matches. */ static int ausearch_compare (auparse_state_t *au) {rnode *r; -int rc;if (au->search_how ==AUSEARCH_RULE_REGEX ) { +int rc; +if (au->rules.cnt ==0 ) { errno =EINVAL ;return -1 ;
@@ -805,22 +933,12 @@int results = (au->search_how ==AUSEARCH_RULE_AND );aurule_first (&au->rules); do { - int tmp = 0; + int tmp; aurulenode *rule = aurule_get_cur(&au->rules); if (rule == NULL) continue; - rc = nvlist_find_name(&r->nv, rule->field); - if (rc) { - if (rule->search_op == AUSEARCH_EXISTS) - return 1; - rc = strcmp(rule->val, - nvlist_get_cur_val(&r->nv)); - if (rule->search_op == AUSEARCH_EQUAL) - tmp = (rc == 0); - else - tmp = (rc != 0); - } + tmp = ausearch_interpret_rule(au, r, rule); if (au->search_how == AUSEARCH_RULE_AND) { if (tmp == 0) return 0; /* all must match */
auparse/auparse-defs.h +13 -2
@@ -38,8 +38,19 @@ AUSOURCE_DESCRIPTOR, AUSOURCE_FILE_POINTER, AUSOURCE_FEED } ausource_t;/* This defines the types of searches that can be done */ -typedef enum {AUSEARCH_UNSET ,AUSEARCH_EXISTS ,AUSEARCH_EQUAL , -AUSEARCH_NOT_EQUAL }ausearch_op_t ; +typedef enum { +AUSEARCH_UNSET , +AUSEARCH_EXISTS , +AUSEARCH_EQUAL ,AUSEARCH_NOT_EQUAL , +AUSEARCH_TIME_LT ,AUSEARCH_TIME_LE ,AUSEARCH_TIME_GE ,AUSEARCH_TIME_GT , +AUSEARCH_TIME_EQ , +/* When comparing, use the value that would be returned by +auparse_interpret_field() instead of the raw value. */ +AUSEARCH_INTERPRETED =0x40000000 +}ausearch_op_t ; + +#define AUSEARCH_OP_IS_TIME__ (OP ) \ + ((OP) >= AUSEARCH_TIME_LT && (OP) <= AUSEARCH_TIME_EQ)/* This determines where to position the cursor when a search completes */ typedef enum { AUSEARCH_STOP_EVENT, AUSEARCH_STOP_RECORD,
auparse/auparse.h +4 -0
@@ -53,6 +53,10 @@/* Functions that are part of the search interface */ int ausearch_add_item (auparse_state_t *au,const char *field,const char *op,const char *value,ausearch_rule_t how); +int ausearch_add_interpreted_item (auparse_state_t *au,const char *field, +const char *op,const char *value,ausearch_rule_t how); +int ausearch_add_timestamp_item (auparse_state_t *au,const char *op,time_t sec, +unsigned milli,ausearch_rule_t how);int ausearch_add_regex (auparse_state_t *au,const char *expr);int ausearch_set_stop (auparse_state_t *au,austop_t where);void ausearch_clear (auparse_state_t *au);
auparse/rlist.c +5 -5
@@ -52,9 +52,7 @@ {aurulenode * newnode =malloc (sizeof (aurulenode)); - newnode->field = node->field; - newnode->search_op = node->search_op; - newnode->val = node->val; + *newnode = *node; newnode->item = l->cnt; newnode->next =NULL ;
@@ -85,8 +83,10 @@ current = l->head;while (current) { nextnode=current->next; -free (current->field); -free (current->val); +if (!AUSEARCH_OP_IS_TIME__ (current->search_op)) { +free (current->v.field.field); +free (current->v.field.val); + }free (current); current=nextnode; }
auparse/rlist.h +11 -3
@@ -31,10 +31,18 @@/* This is the node of the linked list. Any data elements that are * per item goes here. */ typedef struct _aurulenode { -char *field;// The field name string ausearch_op_t search_op;// What search op is being done -char *val;// The value field -unsigned int item;// Which item of the same event +union { +struct { +char *field;// The field name string +char *val;// The value field + } field; +struct {// For search_op == AUSEARCH_TIME_* +time_t sec; +unsigned int milli; + } timestamp; + } v; +unsigned int item;// Which item in the rule list struct _aurulenode * next;// Next aurule node pointer }aurulenode ;
bindings/python/auparse_python.c +134 -0
152 lines not on this page · raw message
docs/ausearch_add_interpreted_item.3 +56 -0
56 lines not on this page · raw message
docs/ausearch_add_item.3 +5 -1
@@ -1,4 +1,4 @@ -.TH "AUSEARCH_ADD_ITEM" "3" "Feb 2007" "Red Hat" "Linux Audit API" +.TH "AUSEARCH_ADD_ITEM" "3" "Nov 2007" "Red Hat" "Linux Audit API" .SH NAME ausearch_add_item \- build up search rule .SH "SYNOPSIS"
@@ -22,6 +22,8 @@ locate the field name and check that the value associated with it is NOT equal to the value given in this rule. .RE +The value parameter is compared to the uninterpreted field value. + The how value determines how this search condition will be stored internally. The possible values are: .RS .TP
@@ -43,6 +45,8 @@ .SH "SEE ALSO" +.BR ausearch_add_interpreted_item (3), +.BR ausearch_add_timestamp_item (3), .BR ausearch_add_regex (3), .BR ausearch_set_stop (3), .BR ausearch_clear (3),
docs/ausearch_add_timestamp_item.3 +50 -0
50 lines not on this page · raw message
docs/Makefile.am +3 -2
@@ -43,8 +43,9 @@ auparse_get_type.3 auparse_init.3 auparse_interpret_field.3 \ auparse_next_event.3 auparse_next_field.3 auparse_next_record.3 \ auparse_node_compare.3 auparse_reset.3 auparse_timestamp_compare.3 \ -aureport.8 ausearch.8 ausearch_add_item.3 ausearch_add_regex.3 \ -ausearch_clear.3 ausearch_next_event.3 ausearch_set_stop.3 \ +aureport.8 ausearch.8 ausearch_add_item.3 ausearch_add_interpreted_item.3 \ +ausearch_add_timestamp_item.3 ausearch_add_regex.3 ausearch_clear.3 \ +ausearch_next_event.3 ausearch_set_stop.3 \ autrace.8 get_auditfail_action.3 set_aumessage_mode.3 \ audispd.8 audispd.conf.5
Quoted 2 lines · Miloslav Trmac
the attached patch adds some functionality to ausearch. It consists of two main parts:
Merged. Thanks for the patch!
-Steve