]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/accesslog.c
Fix prev commit
[openldap] / servers / slapd / overlays / accesslog.c
index 91a04b9b61e88a2b6133ce1ae14667346067fa1c..c0454cf20032caf170c73123af0d535b3c1d972c 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2005 The OpenLDAP Foundation.
+ * Copyright 2005-2006 The OpenLDAP Foundation.
  * Portions copyright 2004-2005 Symas Corporation.
  * All rights reserved.
  *
@@ -57,6 +57,8 @@ typedef struct log_info {
        int li_age;
        int li_cycle;
        struct re_s *li_task;
+       Filter *li_oldf;
+       Entry *li_old;
        int li_success;
        ldap_pvt_thread_mutex_t li_op_mutex;
        ldap_pvt_thread_mutex_t li_log_mutex;
@@ -68,7 +70,8 @@ enum {
        LOG_DB = 1,
        LOG_OPS,
        LOG_PURGE,
-       LOG_SUCCESS
+       LOG_SUCCESS,
+       LOG_OLD
 };
 
 static ConfigTable log_cfats[] = {
@@ -90,6 +93,10 @@ static ConfigTable log_cfats[] = {
                log_cf_gen, "( OLcfgOvAt:4.4 NAME 'olcAccessLogSuccess' "
                        "DESC 'Log successful ops only' "
                        "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
+       { "logold", "filter", 2, 2, 0, ARG_MAGIC|LOG_OLD,
+               log_cf_gen, "( OLcfgOvAt:4.5 NAME 'olcAccessLogOld' "
+                       "DESC 'Log old values when modifying entries matching the filter' "
+                       "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
        { NULL }
 };
 
@@ -99,7 +106,8 @@ static ConfigOCs log_cfocs[] = {
                "DESC 'Access log configuration' "
                "SUP olcOverlayConfig "
                "MUST olcAccessLogDB "
-               "MAY ( olcAccessLogOps $ olcAccessLogPurge $ olcAccessLogSuccess ) )",
+               "MAY ( olcAccessLogOps $ olcAccessLogPurge $ olcAccessLogSuccess $ "
+                       "olcAccessLogOld ) )",
                        Cft_Overlay, log_cfats },
        { NULL }
 };
@@ -396,29 +404,29 @@ log_age_parse(char *agestr)
                        return -1;
                t1 *= 24;
                gotdays = 1;
-       } else if ( *endptr != ':' ) {
-       /* No valid delimiter found, fail */
-               return -1;
+               agestr = endptr + 1;
+       } else {
+               if ( agestr[2] != ':' ) {
+                       /* No valid delimiter found, fail */
+                       return -1;
+               }
+               t1 *= 60;
+               agestr += 3;
        }
 
-       agestr += 3;
        t2 = atoi( agestr );
-
-       /* if there's a delimiter, it can only be a colon */
-       if ( agestr[2] && agestr[2] != ':' )
-               return -1;
-
-       /* If we're at the end of the string, and we started with days,
-        * fail because we expected to find minutes too.
-        */
-       if ( gotdays && !agestr[2] )
-               return -1;
-
-       t1 *= 60;
        t1 += t2;
 
-       if ( !agestr[2] )
-               return t1 * 60;
+       if ( agestr[2] ) {
+               /* if there's a delimiter, it can only be a colon */
+               if ( agestr[2] != ':' )
+                       return -1;
+       } else {
+               /* If we're at the end of the string, and we started with days,
+                * fail because we expected to find minutes too.
+                */
+               return gotdays ? -1 : t1 * 60;
+       }
 
        agestr += 3;
        t2 = atoi( agestr );
@@ -429,12 +437,15 @@ log_age_parse(char *agestr)
        t1 *= 60;
        t1 += t2;
 
-       t1 *= 60;
        if ( agestr[2] ) {
                agestr += 3;
                if ( agestr[2] )
                        return -1;
+               t1 *= 60;
                t1 += atoi( agestr );
+       } else if ( gotdays ) {
+               /* only got days+hh:mm */
+               t1 *= 60;
        }
        return t1;
 }
@@ -449,7 +460,7 @@ log_age_unparse( int age, struct berval *agebv )
        age /= 60;
        mm = age % 60;
        age /= 60;
-       hh = age % 60;
+       hh = age % 24;
        age /= 24;
        dd = age;
 
@@ -605,6 +616,14 @@ log_cf_gen(ConfigArgs *c)
                        else
                                rc = 1;
                        break;
+               case LOG_OLD:
+                       if ( li->li_oldf ) {
+                               filter2bv( li->li_oldf, &agebv );
+                               value_add_one( &c->rvalue_vals, &agebv );
+                       }
+                       else
+                               rc = 1;
+                       break;
                }
                break;
        case LDAP_MOD_DELETE:
@@ -635,6 +654,12 @@ log_cf_gen(ConfigArgs *c)
                case LOG_SUCCESS:
                        li->li_success = 0;
                        break;
+               case LOG_OLD:
+                       if ( li->li_oldf ) {
+                               filter_free( li->li_oldf );
+                               li->li_oldf = NULL;
+                       }
+                       break;
                }
                break;
        default:
@@ -680,6 +705,12 @@ log_cf_gen(ConfigArgs *c)
                case LOG_SUCCESS:
                        li->li_success = c->value_int;
                        break;
+               case LOG_OLD:
+                       li->li_oldf = str2filter( c->argv[1] );
+                       if ( !li->li_oldf ) {
+                               sprintf( c->msg, "bad filter!" );
+                               rc = 1;
+                       }
                }
                break;
        }
@@ -782,6 +813,24 @@ static struct berval derefs[] = {
 
 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;
@@ -791,7 +840,7 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
        int i;
        int logop;
        slap_verbmasks *lo;
-       Entry *e;
+       Entry *e = NULL, *old = NULL;
        char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE+8];
        struct berval bv;
        char *ptr;
@@ -821,6 +870,8 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
 
        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 );
        }
 
@@ -844,9 +895,22 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
 
        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++;
@@ -855,32 +919,21 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
                }
                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 */
@@ -896,15 +949,24 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
                }
                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;
@@ -917,10 +979,7 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
                                         */
                                        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;
@@ -939,6 +998,34 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
                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:
@@ -990,7 +1077,9 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
 
                bv.bv_len = sprintf( bv.bv_val, "%d", op->ors_tlimit );
                attr_merge_one( e, ad_reqTimeLimit, &bv, NULL );
-               /* FIXME: slimit was zeroed by the backends */
+
+               bv.bv_len = sprintf( bv.bv_val, "%d", op->ors_slimit );
+               attr_merge_one( e, ad_reqSizeLimit, &bv, NULL );
                break;
 
        case LOG_EN_BIND:
@@ -1038,10 +1127,12 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
        }
 
        op2.o_bd->be_add( &op2, &rs2 );
-       entry_free( e );
 
 done:
-       ldap_pvt_thread_mutex_unlock( &li->li_log_mutex );
+       if ( lo->mask & LOG_OP_WRITES )
+               ldap_pvt_thread_mutex_unlock( &li->li_log_mutex );
+       if ( e ) entry_free( e );
+       if ( old ) entry_free( old );
        return SLAP_CB_CONTINUE;
 }
 
@@ -1097,6 +1188,20 @@ accesslog_op_mod( Operation *op, SlapReply *rs )
                 * overlays like refint to keep working.
                 */
                ldap_pvt_thread_mutex_lock( &li->li_op_mutex );
+               if ( li->li_oldf && ( 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_oldf ) == 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;
 }
@@ -1110,7 +1215,7 @@ accesslog_unbind( Operation *op, SlapReply *rs )
        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
        if ( op->o_conn->c_authz_backend == on->on_info->oi_origdb ) {
                log_info *li = on->on_bi.bi_private;
-               Operation op2;
+               Operation op2 = {0};
                void *cids[SLAP_MAX_CIDS];
                SlapReply rs2 = {REP_RESULT};
                Entry *e;
@@ -1130,7 +1235,6 @@ accesslog_unbind( Operation *op, SlapReply *rs )
                op2.o_callback = &nullsc;
                op2.o_controls = cids;
                memset(cids, 0, sizeof( cids ));
-               memset(op2.o_ctrlflag, 0, sizeof( op2.o_ctrlflag ));
 
                op2.o_bd->be_add( &op2, &rs2 );
                entry_free( e );
@@ -1143,7 +1247,7 @@ accesslog_abandon( Operation *op, SlapReply *rs )
 {
        slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
        log_info *li = on->on_bi.bi_private;
-       Operation op2;
+       Operation op2 = {0};
        void *cids[SLAP_MAX_CIDS];
        SlapReply rs2 = {REP_RESULT};
        Entry *e;
@@ -1169,7 +1273,6 @@ accesslog_abandon( Operation *op, SlapReply *rs )
        op2.o_callback = &nullsc;
        op2.o_controls = cids;
        memset(cids, 0, sizeof( cids ));
-       memset(op2.o_ctrlflag, 0, sizeof( op2.o_ctrlflag ));
 
        op2.o_bd->be_add( &op2, &rs2 );
        entry_free( e );
@@ -1233,12 +1336,16 @@ accesslog_db_open(
 
        rc = be_entry_get_rw( op, li->li_db->be_nsuffix, NULL, NULL, 0, &e );
 
-       if ( !e ) {
+       if ( e ) {
+               be_entry_release_rw( op, e, 0 );
+       } else {
                SlapReply rs = {REP_RESULT};
                struct berval rdn, nrdn, attr;
                char *ptr;
                AttributeDescription *ad = NULL;
                const char *text = NULL;
+               Entry *e_ctx;
+
                e = ch_calloc( 1, sizeof( Entry ));
                e->e_name = *li->li_db->be_suffix;
                e->e_nname = *li->li_db->be_nsuffix;
@@ -1264,6 +1371,25 @@ accesslog_db_open(
                nrdn.bv_val = ptr+1;
                attr_merge_one( e, ad, &rdn, &nrdn );
 
+               /* Get contextCSN from main DB */
+               op->o_bd = be;
+               op->o_bd->bd_info = on->on_info->oi_orig;
+               rc = be_entry_get_rw( op, be->be_nsuffix, NULL,
+                       slap_schema.si_ad_contextCSN, 0, &e_ctx );
+
+               if ( e_ctx ) {
+                       Attribute *a;
+
+                       a = attr_find( e_ctx->e_attrs, slap_schema.si_ad_contextCSN );
+                       if ( a ) {
+                               attr_merge( e, slap_schema.si_ad_entryCSN, a->a_vals, NULL );
+                               attr_merge( e, a->a_desc, a->a_vals, NULL );
+                       }
+                       be_entry_release_rw( op, e_ctx, 0 );
+               }
+               op->o_bd->bd_info = (BackendInfo *)on;
+               op->o_bd = li->li_db;
+
                op->ora_e = e;
                op->o_req_dn = e->e_name;
                op->o_req_ndn = e->e_nname;