int li_age;
int li_cycle;
struct re_s *li_task;
+ Filter *li_filter;
+ Entry *li_old;
int li_success;
ldap_pvt_thread_mutex_t li_op_mutex;
ldap_pvt_thread_mutex_t li_log_mutex;
LOG_DB = 1,
LOG_OPS,
LOG_PURGE,
- LOG_SUCCESS
+ LOG_SUCCESS,
+ LOG_FILTER
};
static ConfigTable log_cfats[] = {
log_cf_gen, "( OLcfgOvAt:4.4 NAME 'olcAccessLogSuccess' "
"DESC 'Log successful ops only' "
"SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
+ { "logoldfilter", NULL, 2, 2, 0, ARG_MAGIC|LOG_FILTER,
+ log_cf_gen, "( OLcfgOvAt:4.5 NAME 'olcAccessLogOldFilter' "
+ "DESC 'Log old values when modifying entries matching the filter' "
+ "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
{ NULL }
};
"DESC 'Access log configuration' "
"SUP olcOverlayConfig "
"MUST olcAccessLogDB "
- "MAY ( olcAccessLogOps $ olcAccessLogPurge $ olcAccessLogSuccess ) )",
+ "MAY ( olcAccessLogOps $ olcAccessLogPurge $ olcAccessLogSuccess $ "
+ "olcAccessLogOldFilter ) )",
Cft_Overlay, log_cfats },
{ NULL }
};
else
rc = 1;
break;
+ case LOG_FILTER:
+ if ( li->li_filter ) {
+ filter2bv( li->li_filter, &agebv );
+ value_add_one( &c->rvalue_vals, &agebv );
+ }
+ else
+ rc = 1;
+ break;
}
break;
case LDAP_MOD_DELETE:
case LOG_SUCCESS:
li->li_success = 0;
break;
+ case LOG_FILTER:
+ if ( li->li_filter ) {
+ filter_free( li->li_filter );
+ li->li_filter = NULL;
+ }
+ break;
}
break;
default:
case LOG_SUCCESS:
li->li_success = c->value_int;
break;
+ case LOG_FILTER:
+ li->li_filter = str2filter( c->argv[1] );
+ if ( !li->li_filter ) {
+ sprintf( c->msg, "bad filter!" );
+ rc = 1;
+ }
}
break;
}
static struct berval simple = BER_BVC("SIMPLE");
+static void accesslog_val2val(AttributeDescription *ad, struct berval *val,
+ char c_op, struct berval *dst) {
+ char *ptr;
+
+ dst->bv_len = ad->ad_cname.bv_len + val->bv_len + 2;
+ if ( c_op ) dst->bv_len++;
+
+ dst->bv_val = ch_malloc( dst->bv_len+1 );
+
+ ptr = lutil_strcopy( dst->bv_val, ad->ad_cname.bv_val );
+ *ptr++ = ':';
+ if ( c_op )
+ *ptr++ = c_op;
+ *ptr++ = ' ';
+ AC_MEMCPY( ptr, val->bv_val, val->bv_len );
+ dst->bv_val[dst->bv_len] = '\0';
+}
+
static int accesslog_response(Operation *op, SlapReply *rs) {
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
log_info *li = on->on_bi.bi_private;
int i;
int logop;
slap_verbmasks *lo;
- Entry *e;
+ Entry *e, *old = NULL;
char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE+8];
struct berval bv;
char *ptr;
if ( lo->mask & LOG_OP_WRITES ) {
ldap_pvt_thread_mutex_lock( &li->li_log_mutex );
+ old = li->li_old;
+ li->li_old = NULL;
ldap_pvt_thread_mutex_unlock( &li->li_op_mutex );
}
switch( logop ) {
case LOG_EN_ADD:
+ case LOG_EN_DELETE: {
+ char c_op;
+ Entry *e2;
+
+ if ( logop == LOG_EN_ADD ) {
+ e2 = op->ora_e;
+ c_op = '+';
+ } else {
+ if ( !old )
+ break;
+ e2 = old;
+ c_op = 0;
+ }
/* count all the vals */
i = 0;
- for ( a=op->ora_e->e_attrs; a; a=a->a_next ) {
+ for ( a=e2->e_attrs; a; a=a->a_next ) {
if ( a->a_vals ) {
for (b=a->a_vals; !BER_BVISNULL( b ); b++) {
i++;
}
vals = ch_malloc( (i+1) * sizeof( struct berval ));
i = 0;
- for ( a=op->ora_e->e_attrs; a; a=a->a_next ) {
+ for ( a=e2->e_attrs; a; a=a->a_next ) {
if ( a->a_vals ) {
for (b=a->a_vals; !BER_BVISNULL( b ); b++,i++) {
- vals[i].bv_len = a->a_desc->ad_cname.bv_len + b->bv_len +3;
- vals[i].bv_val = ch_malloc( vals[i].bv_len+1 );
- ptr = lutil_strcopy( vals[i].bv_val,
- a->a_desc->ad_cname.bv_val );
- *ptr++ = ':';
- *ptr++ = '+';
- *ptr++ = ' ';
- AC_MEMCPY( ptr, b->bv_val, b->bv_len );
- vals[i].bv_val[vals[i].bv_len] = '\0';
+ accesslog_val2val( a->a_desc, b, c_op, &vals[i] );
}
}
}
vals[i].bv_val = NULL;
vals[i].bv_len = 0;
- a = attr_alloc( ad_reqMod );
+ a = attr_alloc( logop == LOG_EN_ADD ? ad_reqMod : ad_reqOld );
a->a_vals = vals;
a->a_nvals = vals;
last_attr->a_next = a;
break;
-
- case LOG_EN_DELETE:
- /* needs nothing else */
- break;
+ }
case LOG_EN_MODIFY:
/* count all the mods */
}
vals = ch_malloc( (i+1) * sizeof( struct berval ));
i = 0;
+
+ /* Zero flags on old entry */
+ if ( old ) {
+ for ( a=old->e_attrs; a; a=a->a_next )
+ a->a_flags = 0;
+ }
+
for ( m=op->orm_modlist; m; m=m->sml_next ) {
+ /* Mark this attribute as modified */
+ if ( old ) {
+ a = attr_find( old->e_attrs, m->sml_desc );
+ if ( a )
+ a->a_flags = 1;
+ }
if ( m->sml_values ) {
for (b=m->sml_values; !BER_BVISNULL( b ); b++,i++) {
char c_op;
- vals[i].bv_len = m->sml_desc->ad_cname.bv_len + b->bv_len +3;
- vals[i].bv_val = ch_malloc( vals[i].bv_len+1 );
- ptr = lutil_strcopy( vals[i].bv_val,
- m->sml_desc->ad_cname.bv_val );
- *ptr++ = ':';
+
switch( m->sml_op ) {
case LDAP_MOD_ADD: c_op = '+'; break;
case LDAP_MOD_DELETE: c_op = '-'; break;
*/
default: c_op = '?'; break;
}
- *ptr++ = c_op;
- *ptr++ = ' ';
- AC_MEMCPY( ptr, b->bv_val, b->bv_len );
- vals[i].bv_val[vals[i].bv_len] = '\0';
+ accesslog_val2val( m->sml_desc, b, c_op, &vals[i] );
}
} else if ( m->sml_op == LDAP_MOD_DELETE ) {
vals[i].bv_len = m->sml_desc->ad_cname.bv_len + 2;
a->a_vals = vals;
a->a_nvals = vals;
last_attr->a_next = a;
+
+ if ( old ) {
+ last_attr = a;
+ /* count all the vals */
+ i = 0;
+ for ( a=old->e_attrs; a; a=a->a_next ) {
+ if ( a->a_vals && a->a_flags ) {
+ for (b=a->a_vals; !BER_BVISNULL( b ); b++) {
+ i++;
+ }
+ }
+ }
+ vals = ch_malloc( (i+1) * sizeof( struct berval ));
+ i = 0;
+ for ( a=old->e_attrs; a; a=a->a_next ) {
+ if ( a->a_vals && a->a_flags ) {
+ for (b=a->a_vals; !BER_BVISNULL( b ); b++,i++) {
+ accesslog_val2val( a->a_desc, b, 0, &vals[i] );
+ }
+ }
+ }
+ vals[i].bv_val = NULL;
+ vals[i].bv_len = 0;
+ a = attr_alloc( ad_reqOld );
+ a->a_vals = vals;
+ a->a_nvals = vals;
+ last_attr->a_next = a;
+ }
break;
case LOG_EN_MODRDN:
entry_free( e );
done:
+ if ( old ) entry_free( old );
ldap_pvt_thread_mutex_unlock( &li->li_log_mutex );
return SLAP_CB_CONTINUE;
}
* overlays like refint to keep working.
*/
ldap_pvt_thread_mutex_lock( &li->li_op_mutex );
+ if ( li->li_filter && ( op->o_tag == LDAP_REQ_DELETE ||
+ op->o_tag == LDAP_REQ_MODIFY )) {
+ int rc;
+ Entry *e;
+
+ op->o_bd->bd_info = on->on_info->oi_orig;
+ rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
+ if ( e ) {
+ if ( test_filter( op, e, li->li_filter ) == LDAP_COMPARE_TRUE )
+ li->li_old = entry_dup( e );
+ be_entry_release_rw( op, e, 0 );
+ }
+ op->o_bd->bd_info = (BackendInfo *)on;
+ }
}
return SLAP_CB_CONTINUE;
}