ITS#6467 Record minCSN in audit container

This commit is contained in:
Ondřej Kuzník 2017-11-03 13:54:58 +00:00 committed by Ondřej Kuzník
parent 4b62f3b8d2
commit 66a743f119

View 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,12 +714,37 @@ 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;
if ( pd.mincsn_updated ) {
Modifications mod;
/* 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 = 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->orm_modlist = &mod;
op->orm_no_opattrs = 1;
op->o_req_dn = li->li_db->be_suffix[0];
op->o_req_ndn = li->li_db->be_nsuffix[0];
op->o_no_schema_check = 1;
op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
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];
@ -709,34 +758,6 @@ accesslog_purge( void *ctx, void *arg )
}
ch_free( pd.ndn );
ch_free( pd.dn );
{
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]);
mod.sml_nvalues = NULL;
mod.sml_desc = slap_schema.si_ad_entryCSN;
mod.sml_op = LDAP_MOD_REPLACE;
mod.sml_flags = SLAP_MOD_INTERNAL;
mod.sml_next = NULL;
op->o_tag = LDAP_REQ_MODIFY;
op->orm_modlist = &mod;
op->orm_no_opattrs = 1;
op->o_req_dn = li->li_db->be_suffix[0];
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 );
}
}
}
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 ) {
be_entry_release_rw( op, e, 0 );
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 );
}