mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-24 00:29:35 -05:00
ITS#6467 Record minCSN in audit container
This commit is contained in:
parent
4b62f3b8d2
commit
66a743f119
1 changed files with 161 additions and 47 deletions
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue