]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#6467 Record minCSN in audit container
authorOndřej Kuzník <ondra@openldap.org>
Fri, 3 Nov 2017 13:54:58 +0000 (13:54 +0000)
committerOndřej Kuzník <ondra@mistotebe.net>
Wed, 22 Jul 2020 21:25:10 +0000 (22:25 +0100)
servers/slapd/overlays/accesslog.c

index 756fd54bca6e5744ad2c4ca9151c0cb28b1049f3..2742fd0d9512cc02abd16f183aa9211c3b7adda6 100644 (file)
@@ -76,6 +76,8 @@ typedef struct log_info {
        struct berval li_uuid;
        int li_success;
        log_base *li_bases;
+       BerVarray li_mincsn;
+       int *li_sids, li_numcsns;
        ldap_pvt_thread_mutex_t li_op_rmutex;
        ldap_pvt_thread_mutex_t li_log_mutex;
 } log_info;
@@ -198,7 +200,8 @@ static AttributeDescription *ad_reqDN, *ad_reqStart, *ad_reqEnd, *ad_reqType,
        *ad_reqScope, *ad_reqFilter, *ad_reqAttr, *ad_reqEntries,
        *ad_reqSizeLimit, *ad_reqTimeLimit, *ad_reqAttrsOnly, *ad_reqData,
        *ad_reqId, *ad_reqMessage, *ad_reqVersion, *ad_reqDerefAliases,
-       *ad_reqReferral, *ad_reqOld, *ad_auditContext, *ad_reqEntryUUID;
+       *ad_reqReferral, *ad_reqOld, *ad_auditContext, *ad_reqEntryUUID,
+       *ad_minCSN;
 
 static int
 logSchemaControlValidate(
@@ -411,6 +414,17 @@ static struct {
                "ORDERING UUIDOrderingMatch "
                "SYNTAX 1.3.6.1.1.16.1 "
                "SINGLE-VALUE )", &ad_reqEntryUUID },
+
+       /*
+        * ITS#8486
+        */
+       { "( " LOG_SCHEMA_AT ".32 NAME 'minCSN' "
+               "DESC 'CSN set that the logs are recorded from' "
+               "EQUALITY CSNMatch "
+               "ORDERING CSNOrderingMatch "
+               "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1{64} "
+               "NO-USER-MODIFICATION "
+               "USAGE dSAOperation )", &ad_minCSN },
        { NULL, NULL }
 };
 
@@ -587,36 +601,49 @@ static slap_callback nullsc;
 #define PURGE_INCREMENT        100
 
 typedef struct purge_data {
+       struct log_info *li;
        int slots;
        int used;
+       int mincsn_updated;
        BerVarray dn;
        BerVarray ndn;
-       struct berval csn;      /* an arbitrary old CSN */
 } purge_data;
 
 static int
 log_old_lookup( Operation *op, SlapReply *rs )
 {
        purge_data *pd = op->o_callback->sc_private;
+       struct log_info *li = pd->li;
        Attribute *a;
 
        if ( rs->sr_type != REP_SEARCH) return 0;
 
        if ( slapd_shutdown ) return 0;
 
-       /* Remember max CSN: should always be the last entry
-        * seen, since log entries are ordered chronologically...
-        */
+       /* Update minCSN */
        a = attr_find( rs->sr_entry->e_attrs,
                slap_schema.si_ad_entryCSN );
        if ( a ) {
                ber_len_t len = a->a_nvals[0].bv_len;
+               int i, sid;
+
+               /* Find the correct sid */
+               sid = slap_parse_csn_sid( &a->a_nvals[0] );
+               for ( i=0; i < li->li_numcsns; i++ ) {
+                       if ( sid <= li->li_sids[i] ) break;
+               }
+               if ( i >= li->li_numcsns || sid != li->li_sids[i] ) {
+                       Debug( LDAP_DEBUG_ANY, "log_old_lookup: "
+                                       "csn=%s with sid not in minCSN set!\n",
+                                       a->a_nvals[0].bv_val );
+               }
+
                /* Paranoid len check, normalized CSNs are always the same length */
-               if ( len > LDAP_PVT_CSNSTR_BUFSIZE )
-                       len = LDAP_PVT_CSNSTR_BUFSIZE;
-               if ( memcmp( a->a_nvals[0].bv_val, pd->csn.bv_val, len ) > 0 ) {
-                       AC_MEMCPY( pd->csn.bv_val, a->a_nvals[0].bv_val, len );
-                       pd->csn.bv_len = len;
+               if ( len > li->li_mincsn[i].bv_len )
+                       len = li->li_mincsn[i].bv_len;
+               if ( ber_bvcmp( &li->li_mincsn[i], &a->a_nvals[0] ) < 0 ) {
+                       pd->mincsn_updated = 1;
+                       AC_MEMCPY( li->li_mincsn[i].bv_val, a->a_nvals[0].bv_val, len );
                }
        }
        if ( pd->used >= pd->slots ) {
@@ -644,7 +671,7 @@ accesslog_purge( void *ctx, void *arg )
        slap_callback cb = { NULL, log_old_lookup, NULL, NULL, NULL };
        Filter f;
        AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
-       purge_data pd = {0};
+       purge_data pd = { .li = li };
        char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE];
        char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
        time_t old = slap_get_time();
@@ -679,9 +706,6 @@ accesslog_purge( void *ctx, void *arg )
        op->ors_attrs = slap_anlist_no_attrs;
        op->ors_attrsonly = 1;
        
-       pd.csn.bv_len = sizeof( csnbuf );
-       pd.csn.bv_val = csnbuf;
-       csnbuf[0] = '\0';
        cb.sc_private = &pd;
 
        op->o_bd->be_search( op, &rs );
@@ -690,37 +714,16 @@ accesslog_purge( void *ctx, void *arg )
        if ( pd.used ) {
                int i;
 
-               /* delete the expired entries */
-               op->o_tag = LDAP_REQ_DELETE;
                op->o_callback = &nullsc;
-               op->o_csn = pd.csn;
                op->o_dont_replicate = 1;
 
-               for (i=0; i<pd.used; i++) {
-                       op->o_req_dn = pd.dn[i];
-                       op->o_req_ndn = pd.ndn[i];
-                       if ( !slapd_shutdown ) {
-                               rs_reinit( &rs, REP_RESULT );
-                               op->o_bd->be_delete( op, &rs );
-                       }
-                       ch_free( pd.ndn[i].bv_val );
-                       ch_free( pd.dn[i].bv_val );
-                       ldap_pvt_thread_pool_pausecheck( &connection_pool );
-               }
-               ch_free( pd.ndn );
-               ch_free( pd.dn );
-
-               {
+               if ( pd.mincsn_updated ) {
                        Modifications mod;
-                       struct berval bv[2];
-                       rs_reinit( &rs, REP_RESULT );
-                       /* update context's entryCSN to reflect oldest CSN */
-                       mod.sml_numvals = 1;
-                       mod.sml_values = bv;
-                       bv[0] = pd.csn;
-                       BER_BVZERO(&bv[1]);
+                       /* update context's minCSN to reflect oldest CSN */
+                       mod.sml_numvals = li->li_numcsns;
+                       mod.sml_values = li->li_mincsn;
                        mod.sml_nvalues = NULL;
-                       mod.sml_desc = slap_schema.si_ad_entryCSN;
+                       mod.sml_desc = ad_minCSN;
                        mod.sml_op = LDAP_MOD_REPLACE;
                        mod.sml_flags = SLAP_MOD_INTERNAL;
                        mod.sml_next = NULL;
@@ -732,11 +735,29 @@ accesslog_purge( void *ctx, void *arg )
                        op->o_req_ndn = li->li_db->be_nsuffix[0];
                        op->o_no_schema_check = 1;
                        op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
-                       op->o_bd->be_modify( op, &rs );
-                       if ( mod.sml_next ) {
-                               slap_mods_free( mod.sml_next, 1 );
+                       if ( !slapd_shutdown ) {
+                               Debug( LDAP_DEBUG_SYNC, "accesslog_purge: "
+                                               "updating minCSN with %d values\n",
+                                               li->li_numcsns );
+                               op->o_bd->be_modify( op, &rs );
                        }
                }
+
+               /* delete the expired entries */
+               op->o_tag = LDAP_REQ_DELETE;
+               for (i=0; i<pd.used; i++) {
+                       op->o_req_dn = pd.dn[i];
+                       op->o_req_ndn = pd.ndn[i];
+                       if ( !slapd_shutdown ) {
+                               rs_reinit( &rs, REP_RESULT );
+                               op->o_bd->be_delete( op, &rs );
+                       }
+                       ch_free( pd.ndn[i].bv_val );
+                       ch_free( pd.dn[i].bv_val );
+                       ldap_pvt_thread_pool_pausecheck( &connection_pool );
+               }
+               ch_free( pd.ndn );
+               ch_free( pd.dn );
        }
 
        ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
@@ -1886,6 +1907,59 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
        if ( e == op2.ora_e ) entry_free( e );
        e = NULL;
 
+       /* TODO: What to do about minCSN when we have an op without a CSN? */
+       if ( !BER_BVISEMPTY( &op->o_csn ) ) {
+               Modifications mod;
+               int i, sid = slap_parse_csn_sid( &op->o_csn );
+
+               for ( i=0; i < li->li_numcsns; i++ ) {
+                       if ( sid <= li->li_sids[i] ) break;
+               }
+               if ( i >= li->li_numcsns || sid != li->li_sids[i] ) {
+                       /* SID not in minCSN set, add */
+                       struct berval bv[2];
+
+                       Debug( LDAP_DEBUG_TRACE, "accesslog_response: "
+                                       "adding minCSN %s\n",
+                                       op->o_csn.bv_val );
+                       slap_insert_csn_sids( (struct sync_cookie *)&li->li_mincsn, i,
+                                       sid, &op->o_csn );
+
+                       op2.o_tag = LDAP_REQ_MODIFY;
+                       op2.o_req_dn = li->li_db->be_suffix[0];
+                       op2.o_req_ndn = li->li_db->be_nsuffix[0];
+
+                       bv[0] = op->o_csn;
+                       BER_BVZERO( &bv[1] );
+
+                       mod.sml_numvals = 1;
+                       mod.sml_values = bv;
+                       mod.sml_nvalues = bv;
+                       mod.sml_desc = ad_minCSN;
+                       mod.sml_op = LDAP_MOD_ADD;
+                       mod.sml_flags = SLAP_MOD_INTERNAL;
+                       mod.sml_next = NULL;
+
+                       op2.orm_modlist = &mod;
+                       op2.orm_no_opattrs = 1;
+
+                       Debug( LDAP_DEBUG_SYNC, "accesslog_response: "
+                                       "adding a new csn=%s into minCSN\n",
+                                       bv[0].bv_val );
+                       rs_reinit( &rs2, REP_RESULT );
+                       op2.o_bd->be_modify( &op2, &rs2 );
+                       if ( rs2.sr_err != LDAP_SUCCESS ) {
+                               Debug( LDAP_DEBUG_SYNC, "accesslog_response: "
+                                               "got result 0x%x adding minCSN %s\n",
+                                               rs2.sr_err, op->o_csn.bv_val );
+                       }
+               } else if ( ber_bvcmp( &op->o_csn, &li->li_mincsn[i] ) < 0 ) {
+                       Debug( LDAP_DEBUG_ANY, "accesslog_response: "
+                                       "csn=%s older than existing minCSN csn=%s for this sid\n",
+                                       op->o_csn.bv_val, li->li_mincsn[i].bv_val );
+               }
+       }
+
 done:
        if ( lo->mask & LOG_OP_WRITES )
                ldap_pvt_thread_mutex_unlock( &li->li_log_mutex );
@@ -2162,7 +2236,7 @@ accesslog_db_destroy(
        return LDAP_SUCCESS;
 }
 
-/* Create the logdb's root entry if it's missing */
+/* Create the logdb's root entry if it's missing, load mincsn */
 static void *
 accesslog_db_root(
        void *ctx,
@@ -2187,8 +2261,47 @@ accesslog_db_root(
        rc = be_entry_get_rw( op, li->li_db->be_nsuffix, NULL, NULL, 0, &e );
 
        if ( e ) {
+               Attribute *a = attr_find( e->e_attrs, ad_minCSN );
+               if ( !a ) {
+                       /* TODO: find the lowest CSN we are safe to put in */
+                       a = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN );
+                       if ( a ) {
+                               SlapReply rs = {REP_RESULT};
+                               Modifications mod;
+                               BackendDB db = *li->li_db;
+
+                               op->o_bd = &db;
+
+                               mod.sml_numvals = a->a_numvals;
+                               mod.sml_values = a->a_vals;
+                               mod.sml_nvalues = a->a_nvals;
+                               mod.sml_desc = ad_minCSN;
+                               mod.sml_op = LDAP_MOD_REPLACE;
+                               mod.sml_flags = SLAP_MOD_INTERNAL;
+                               mod.sml_next = NULL;
+
+                               op->o_tag = LDAP_REQ_MODIFY;
+                               op->o_req_dn = e->e_name;
+                               op->o_req_ndn = e->e_nname;
+                               op->o_callback = &nullsc;
+                               SLAP_DBFLAGS( op->o_bd ) |= SLAP_DBFLAG_NOLASTMOD;
+
+                               Debug( LDAP_DEBUG_SYNC, "accesslog_db_root: "
+                                               "setting up minCSN with %d values\n",
+                                               a->a_numvals );
+
+                               op->orm_modlist = &mod;
+                               op->orm_no_opattrs = 1;
+                               rc = op->o_bd->be_modify( op, &rs );
+                       }
+               }
+               if ( a ) {
+                       ber_bvarray_dup_x( &li->li_mincsn, a->a_vals, NULL );
+                       li->li_numcsns = a->a_numvals;
+                       li->li_sids = slap_parse_csn_sids( li->li_mincsn, li->li_numcsns, NULL );
+                       slap_sort_csn_sids( li->li_mincsn, li->li_sids, li->li_numcsns, NULL );
+               }
                be_entry_release_rw( op, e, 0 );
-
        } else {
                SlapReply rs = {REP_RESULT};
                struct berval rdn, nrdn, attr;
@@ -2238,6 +2351,7 @@ accesslog_db_root(
                                attr_merge_one( e, slap_schema.si_ad_entryCSN,
                                        &a->a_vals[0], &a->a_nvals[0] );
                                attr_merge( e, a->a_desc, a->a_vals, a->a_nvals );
+                               attr_merge( e, ad_minCSN, a->a_vals, a->a_nvals );
                        }
                        be_entry_release_rw( op, e_ctx, 0 );
                }