version 1.22, 2006/04/27 14:05:41
|
version 1.23, 2006/06/12 12:06:00
|
Line 1
|
Line 1
|
/* refint.c - referential integrity module */ |
/* refint.c - referential integrity module */ |
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/refint.c,v 1.21 2006/04/27 00:29:13 hyc Exp $ */ |
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/refint.c,v 1.22 2006/04/27 14:05:41 hallvard Exp $ */ |
/* This work is part of OpenLDAP Software <http://www.openldap.org/>. |
/* This work is part of OpenLDAP Software <http://www.openldap.org/>. |
* |
* |
* Copyright 2004-2006 The OpenLDAP Foundation. |
* Copyright 2004-2006 The OpenLDAP Foundation. |
Line 26
|
Line 26
|
* DN whenever the DN is changed or its entry is deleted, and making |
* DN whenever the DN is changed or its entry is deleted, and making |
* the appropriate update. |
* the appropriate update. |
* |
* |
* Updates are performed using the database rootdn, but the ModifiersName |
* Updates are performed using the database rootdn in a separate task |
* is always set to refint_dn. |
* to allow the original operation to complete immediately. |
*/ |
*/ |
|
|
#ifdef SLAPD_OVER_REFINT |
#ifdef SLAPD_OVER_REFINT |
Line 39
|
Line 39
|
|
|
#include "slap.h" |
#include "slap.h" |
#include "config.h" |
#include "config.h" |
|
#include "ldap_rq.h" |
|
|
static slap_overinst refint; |
static slap_overinst refint; |
|
|
/* The DN to use in the ModifiersName for all refint updates */ |
|
static BerValue refint_dn = BER_BVC("cn=Referential Integrity Overlay"); |
|
|
|
typedef struct refint_attrs_s { |
typedef struct refint_attrs_s { |
struct refint_attrs_s *next; |
struct refint_attrs_s *next; |
AttributeDescription *attr; |
AttributeDescription *attr; |
Line 53 typedef struct refint_attrs_s {
|
Line 51 typedef struct refint_attrs_s {
|
typedef struct dependents_s { |
typedef struct dependents_s { |
struct dependents_s *next; |
struct dependents_s *next; |
BerValue dn; /* target dn */ |
BerValue dn; /* target dn */ |
Modifications *mm; |
BerValue ndn; |
|
refint_attrs *attrs; |
} dependent_data; |
} dependent_data; |
|
|
|
typedef struct refint_q { |
|
struct refint_q *next; |
|
struct refint_data_s *rdata; |
|
dependent_data *attrs; /* entries and attrs returned from callback */ |
|
BackendDB *db; |
|
BerValue olddn; |
|
BerValue oldndn; |
|
BerValue newdn; |
|
BerValue newndn; |
|
} refint_q; |
|
|
typedef struct refint_data_s { |
typedef struct refint_data_s { |
const char *message; /* breadcrumbs */ |
const char *message; /* breadcrumbs */ |
struct refint_attrs_s *attrs; /* list of known attrs */ |
struct refint_attrs_s *attrs; /* list of known attrs */ |
struct dependents_s *mods; /* modifications returned from callback */ |
BerValue dn; /* basedn in parent, */ |
BerValue dn; /* basedn in parent, searchdn in call */ |
|
BerValue newdn; /* replacement value for modrdn callback */ |
|
BerValue nnewdn; /* normalized replacement value */ |
|
BerValue nothing; /* the nothing value, if needed */ |
BerValue nothing; /* the nothing value, if needed */ |
BerValue nnothing; /* normalized nothingness */ |
BerValue nnothing; /* normalized nothingness */ |
|
struct re_s *qtask; |
|
refint_q *qhead; |
|
refint_q *qtail; |
|
ldap_pvt_thread_mutex_t qmutex; |
} refint_data; |
} refint_data; |
|
|
|
#define RUNQ_INTERVAL 36000 /* a long time */ |
|
|
enum { |
enum { |
REFINT_ATTRS = 1, |
REFINT_ATTRS = 1, |
REFINT_NOTHING |
REFINT_NOTHING |
Line 238 refint_db_init(
|
Line 251 refint_db_init(
|
|
|
id->message = "_init"; |
id->message = "_init"; |
on->on_bi.bi_private = id; |
on->on_bi.bi_private = id; |
|
ldap_pvt_thread_mutex_init( &id->qmutex ); |
return(0); |
return(0); |
} |
} |
|
|
Line 249 refint_db_destroy(
|
Line 263 refint_db_destroy(
|
slap_overinst *on = (slap_overinst *)be->bd_info; |
slap_overinst *on = (slap_overinst *)be->bd_info; |
|
|
if ( on->on_bi.bi_private ) { |
if ( on->on_bi.bi_private ) { |
ch_free( on->on_bi.bi_private ); |
refint_data *id = on->on_bi.bi_private; |
on->on_bi.bi_private = NULL; |
on->on_bi.bi_private = NULL; |
|
ldap_pvt_thread_mutex_destroy( &id->qmutex ); |
|
ch_free( id ); |
} |
} |
return(0); |
return(0); |
} |
} |
Line 313 refint_close(
|
Line 329 refint_close(
|
} |
} |
|
|
/* |
/* |
** delete callback |
** search callback |
** generates a list of Modification* from search results |
** generates a list of Attributes from search results |
*/ |
*/ |
|
|
static int |
static int |
refint_delete_cb( |
refint_search_cb( |
Operation *op, |
Operation *op, |
SlapReply *rs |
SlapReply *rs |
) |
) |
{ |
{ |
Attribute *a; |
Attribute *a; |
BerVarray b = NULL; |
BerVarray b = NULL; |
refint_data *dd = op->o_callback->sc_private; |
refint_q *rq = op->o_callback->sc_private; |
refint_attrs *ia, *da = dd->attrs; |
refint_data *dd = rq->rdata; |
|
refint_attrs *ia, *da = dd->attrs, *na; |
dependent_data *ip; |
dependent_data *ip; |
Modifications *mp, *ma; |
|
int i; |
int i; |
|
|
Debug(LDAP_DEBUG_TRACE, "refint_delete_cb <%s>\n", |
Debug(LDAP_DEBUG_TRACE, "refint_search_cb <%s>\n", |
rs->sr_entry ? rs->sr_entry->e_name.bv_val : "NOTHING", 0, 0); |
rs->sr_entry ? rs->sr_entry->e_name.bv_val : "NOTHING", 0, 0); |
|
|
if (rs->sr_type != REP_SEARCH || !rs->sr_entry) return(0); |
if (rs->sr_type != REP_SEARCH || !rs->sr_entry) return(0); |
dd->message = "_delete_cb"; |
|
|
|
/* |
/* |
** foreach configured attribute type: |
** foreach configured attribute type: |
** if this attr exists in the search result, |
** if this attr exists in the search result, |
** and it has a value matching the target: |
** and it has a value matching the target: |
** allocate a Modification; |
** allocate an attr; |
** allocate its array of 2 BerValues; |
** if this is a delete and there's only one value: |
** if only one value, and we have a configured Nothing: |
** allocate the same attr again; |
** allocate additional Modification |
|
** type = MOD_ADD |
|
** BerValues[] = { Nothing, NULL }; |
|
** add to list |
|
** type = MOD_DELETE |
|
** BerValues[] = { our target dn, NULL }; |
|
** add this mod to the list of mods; |
|
** |
** |
*/ |
*/ |
|
|
ip = ch_malloc(sizeof(dependent_data)); |
ip = op->o_tmpalloc(sizeof(dependent_data), op->o_tmpmemctx ); |
ip->dn.bv_val = NULL; |
ber_dupbv_x( &ip->dn, &rs->sr_entry->e_name, op->o_tmpmemctx ); |
ip->next = NULL; |
ber_dupbv_x( &ip->ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx ); |
ip->mm = NULL; |
ip->next = rq->attrs; |
ma = NULL; |
rq->attrs = ip; |
|
ip->attrs = NULL; |
for(ia = da; ia; ia = ia->next) { |
for(ia = da; ia; ia = ia->next) { |
if ( (a = attr_find(rs->sr_entry->e_attrs, ia->attr) ) ) |
if ( (a = attr_find(rs->sr_entry->e_attrs, ia->attr) ) ) |
for(i = 0, b = a->a_nvals; b[i].bv_val; i++) |
for(i = 0, b = a->a_nvals; b[i].bv_val; i++) |
if(bvmatch(&dd->dn, &b[i])) { |
if(bvmatch(&rq->oldndn, &b[i])) { |
if(!ip->dn.bv_val) ber_dupbv(&ip->dn, &rs->sr_entry->e_nname); |
na = op->o_tmpalloc(sizeof( refint_attrs ), op->o_tmpmemctx ); |
if(!b[1].bv_val && dd->nothing.bv_val) { |
na->next = ip->attrs; |
mp = ch_malloc(sizeof(Modifications)); |
ip->attrs = na; |
mp->sml_desc = ia->attr; /* XXX */ |
na->attr = ia->attr; |
mp->sml_type = a->a_desc->ad_cname; |
/* If this is a delete and there's only one value, and |
mp->sml_values = ch_malloc(2 * sizeof(BerValue)); |
* we have a nothing DN configured, allocate the attr again. |
mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue)); |
*/ |
mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0; |
if(!b[1].bv_val && BER_BVISEMPTY( &rq->newdn ) && |
mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL; |
dd->nothing.bv_val) { |
|
na = op->o_tmpalloc(sizeof( refint_attrs ), op->o_tmpmemctx ); |
mp->sml_op = LDAP_MOD_ADD; |
na->next = ip->attrs; |
mp->sml_flags = 0; |
ip->attrs = na; |
ber_dupbv(&mp->sml_values[0], &dd->nothing); |
na->attr = ia->attr; |
ber_dupbv(&mp->sml_nvalues[0], &dd->nnothing); |
|
mp->sml_next = ma; |
|
ma = mp; |
|
} |
} |
/* this might violate the object class */ |
Debug(LDAP_DEBUG_TRACE, "refint_search_cb: %s: %s\n", |
mp = ch_malloc(sizeof(Modifications)); |
a->a_desc->ad_cname.bv_val, rq->olddn.bv_val, 0); |
mp->sml_desc = ia->attr; /* XXX */ |
|
mp->sml_type = a->a_desc->ad_cname; |
|
mp->sml_values = ch_malloc(2 * sizeof(BerValue)); |
|
mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue)); |
|
mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0; |
|
mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL; |
|
mp->sml_op = LDAP_MOD_DELETE; |
|
mp->sml_flags = 0; |
|
ber_dupbv(&mp->sml_values[0], &dd->dn); |
|
ber_dupbv(&mp->sml_nvalues[0], &mp->sml_values[0]); |
|
mp->sml_next = ma; |
|
ma = mp; |
|
Debug(LDAP_DEBUG_TRACE, "refint_delete_cb: %s: %s\n", |
|
a->a_desc->ad_cname.bv_val, dd->dn.bv_val, 0); |
|
break; |
break; |
} |
} |
} |
} |
ip->mm = ma; |
|
ip->next = dd->mods; |
|
dd->mods = ip; |
|
|
|
return(0); |
return(0); |
} |
} |
|
|
/* |
static void * |
** null callback |
refint_qtask( void *ctx, void *arg ) |
** does nothing |
|
*/ |
|
|
|
static int |
|
refint_null_cb( |
|
Operation *op, |
|
SlapReply *rs |
|
) |
|
{ |
{ |
((refint_data *)op->o_callback->sc_private)->message = "_null_cb"; |
struct re_s *rtask = arg; |
return(LDAP_SUCCESS); |
refint_data *id = rtask->arg; |
} |
Connection conn = {0}; |
|
OperationBuffer opbuf; |
/* |
Operation *op; |
** modrdn callback |
SlapReply rs = {REP_RESULT}; |
** generates a list of Modification* from search results |
slap_callback cb = { NULL, NULL, NULL, NULL }; |
*/ |
Filter ftop, *fptr; |
|
refint_q *rq; |
static int |
dependent_data *dp; |
refint_modrdn_cb( |
refint_attrs *ra, *ip; |
Operation *op, |
int rc; |
SlapReply *rs |
|
) |
|
{ |
|
Attribute *a; |
|
BerVarray b = NULL; |
|
refint_data *dd = op->o_callback->sc_private; |
|
refint_attrs *ia, *da = dd->attrs; |
|
dependent_data *ip = NULL; |
|
Modifications *mp; |
|
int i, fix; |
|
|
|
Debug(LDAP_DEBUG_TRACE, "refint_modrdn_cb <%s>\n", |
|
rs->sr_entry ? rs->sr_entry->e_name.bv_val : "NOTHING", 0, 0); |
|
|
|
if (rs->sr_type != REP_SEARCH || !rs->sr_entry) return(0); |
op = (Operation *) &opbuf; |
dd->message = "_modrdn_cb"; |
connection_fake_init( &conn, op, ctx ); |
|
|
/* |
/* |
** foreach configured attribute type: |
** build a search filter for all configured attributes; |
** if this attr exists in the search result, |
** populate our Operation; |
** and it has a value matching the target: |
** pass our data (attr list, dn) to backend via sc_private; |
** allocate a pair of Modifications; |
** call the backend search function; |
** make it MOD_ADD the new value and MOD_DELETE the old; |
** nb: (|(one=thing)) is valid, but do smart formatting anyway; |
** allocate its array of BerValues; |
** nb: 16 is arbitrarily a dozen or so extra bytes; |
** foreach value in the search result: |
|
** if it matches our target value, replace it; |
|
** otherwise, copy from the search result; |
|
** terminate the array of BerValues; |
|
** add these mods to the list of mods; |
|
** |
** |
*/ |
*/ |
|
|
for(ia = da; ia; ia = ia->next) { |
ftop.f_choice = LDAP_FILTER_OR; |
if((a = attr_find(rs->sr_entry->e_attrs, ia->attr))) { |
ftop.f_next = NULL; |
for(fix = 0, i = 0, b = a->a_nvals; b[i].bv_val; i++) |
ftop.f_or = NULL; |
if(bvmatch(&dd->dn, &b[i])) { fix++; break; } |
op->ors_filter = &ftop; |
if(fix) { |
for(ip = id->attrs; ip; ip = ip->next) { |
if (!ip) { |
fptr = op->o_tmpalloc( sizeof(Filter) + sizeof(AttributeAssertion), |
ip = ch_malloc(sizeof(dependent_data)); |
op->o_tmpmemctx ); |
ip->next = NULL; |
fptr->f_choice = LDAP_FILTER_EQUALITY; |
ip->mm = NULL; |
fptr->f_ava = (AttributeAssertion *)(fptr+1); |
ber_dupbv(&ip->dn, &rs->sr_entry->e_nname); |
fptr->f_ava->aa_desc = ip->attr; |
|
fptr->f_next = ftop.f_or; |
|
ftop.f_or = fptr; |
|
} |
|
|
|
for (;;) { |
|
/* Dequeue an op */ |
|
ldap_pvt_thread_mutex_lock( &id->qmutex ); |
|
rq = id->qhead; |
|
if ( rq ) { |
|
id->qhead = rq->next; |
|
if ( !id->qhead ) |
|
id->qtail = NULL; |
|
} |
|
ldap_pvt_thread_mutex_unlock( &id->qmutex ); |
|
if ( !rq ) |
|
break; |
|
|
|
for (fptr = ftop.f_or; fptr; fptr=fptr->f_next ) |
|
fptr->f_av_value = rq->oldndn; |
|
|
|
filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); |
|
|
|
/* callback gets the searched dn instead */ |
|
cb.sc_private = rq; |
|
cb.sc_response = refint_search_cb; |
|
op->o_callback = &cb; |
|
op->o_tag = LDAP_REQ_SEARCH; |
|
op->ors_scope = LDAP_SCOPE_SUBTREE; |
|
op->ors_deref = LDAP_DEREF_NEVER; |
|
op->ors_limit = NULL; |
|
op->ors_slimit = SLAP_NO_LIMIT; |
|
op->ors_tlimit = SLAP_NO_LIMIT; |
|
|
|
/* no attrs! */ |
|
op->ors_attrs = slap_anlist_no_attrs; |
|
|
|
op->o_req_ndn = id->dn; |
|
op->o_req_dn = id->dn; |
|
op->o_bd = rq->db; |
|
|
|
/* search */ |
|
rc = op->o_bd->be_search(op, &rs); |
|
|
|
op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); |
|
|
|
if(rc != LDAP_SUCCESS) { |
|
Debug( LDAP_DEBUG_TRACE, |
|
"refint_response: search failed: %d\n", |
|
rc, 0, 0 ); |
|
continue; |
|
} |
|
|
|
/* safety? paranoid just in case */ |
|
if(!cb.sc_private) { |
|
Debug( LDAP_DEBUG_TRACE, |
|
"refint_response: callback wiped out sc_private?!\n", |
|
0, 0, 0 ); |
|
continue; |
|
} |
|
|
|
/* Set up the Modify requests */ |
|
cb.sc_response = &slap_null_cb; |
|
op->o_tag = LDAP_REQ_MODIFY; |
|
|
|
/* |
|
** [our search callback builds a list of attrs] |
|
** foreach attr: |
|
** make sure its dn has a backend; |
|
** build Modification* chain; |
|
** call the backend modify function; |
|
** |
|
*/ |
|
|
|
op->orm_modlist = NULL; |
|
|
|
for(dp = rq->attrs; dp; dp = dp->next) { |
|
Modifications *m, *first = NULL; |
|
|
|
op->o_req_dn = dp->dn; |
|
op->o_req_ndn = dp->ndn; |
|
op->o_bd = select_backend(&dp->ndn, 0, 1); |
|
if(!op->o_bd) { |
|
Debug( LDAP_DEBUG_TRACE, |
|
"refint_response: no backend for DN %s!\n", |
|
dp->dn.bv_val, 0, 0 ); |
|
goto done; |
} |
} |
mp = ch_malloc(sizeof(Modifications)); |
rs.sr_type = REP_RESULT; |
mp->sml_op = LDAP_MOD_ADD; |
for (ra = dp->attrs; ra; ra = dp->attrs) { |
mp->sml_flags = 0; |
dp->attrs = ra->next; |
mp->sml_desc = ia->attr; /* XXX */ |
if ( !BER_BVISEMPTY( &rq->newdn ) || ( ra->next && |
mp->sml_type = ia->attr->ad_cname; |
ra->attr == ra->next->attr )) { |
mp->sml_values = ch_malloc(2 * sizeof(BerValue)); |
m = op->o_tmpalloc( sizeof(Modifications) + |
mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue)); |
4*sizeof(BerValue), op->o_tmpmemctx ); |
ber_dupbv(&mp->sml_values[0], &dd->newdn); |
m->sml_next = op->orm_modlist; |
ber_dupbv(&mp->sml_nvalues[0], &dd->nnewdn); |
if ( !first ) |
mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0; |
first = m; |
mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL; |
op->orm_modlist = m; |
mp->sml_next = ip->mm; |
m->sml_op = LDAP_MOD_ADD; |
ip->mm = mp; |
m->sml_flags = 0; |
mp = ch_malloc(sizeof(Modifications)); |
m->sml_desc = ra->attr; |
mp->sml_op = LDAP_MOD_DELETE; |
m->sml_type = ra->attr->ad_cname; |
mp->sml_flags = 0; |
m->sml_values = (BerVarray)(m+1); |
mp->sml_desc = ia->attr; /* XXX */ |
m->sml_nvalues = m->sml_values+2; |
mp->sml_type = ia->attr->ad_cname; |
BER_BVZERO( &m->sml_values[1] ); |
mp->sml_values = ch_malloc(2 * sizeof(BerValue)); |
BER_BVZERO( &m->sml_nvalues[1] ); |
mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue)); |
if ( BER_BVISEMPTY( &rq->newdn )) { |
ber_dupbv(&mp->sml_values[0], &dd->dn); |
op->o_tmpfree( ra, op->o_tmpmemctx ); |
ber_dupbv(&mp->sml_nvalues[0], &dd->dn); |
ra = dp->attrs; |
mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0; |
dp->attrs = ra->next; |
mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL; |
m->sml_values[0] = id->nothing; |
mp->sml_next = ip->mm; |
m->sml_nvalues[0] = id->nnothing; |
ip->mm = mp; |
} else { |
Debug(LDAP_DEBUG_TRACE, "refint_modrdn_cb: %s: %s\n", |
m->sml_values[0] = rq->newdn; |
a->a_desc->ad_cname.bv_val, dd->dn.bv_val, 0); |
m->sml_nvalues[0] = rq->newndn; |
|
} |
|
} |
|
m = op->o_tmpalloc( sizeof(Modifications) + 4*sizeof(BerValue), |
|
op->o_tmpmemctx ); |
|
m->sml_next = op->orm_modlist; |
|
op->orm_modlist = m; |
|
if ( !first ) |
|
first = m; |
|
m->sml_op = LDAP_MOD_DELETE; |
|
m->sml_flags = 0; |
|
m->sml_desc = ra->attr; |
|
m->sml_type = ra->attr->ad_cname; |
|
m->sml_values = (BerVarray)(m+1); |
|
m->sml_nvalues = m->sml_values+2; |
|
m->sml_values[0] = rq->olddn; |
|
m->sml_nvalues[0] = rq->oldndn; |
|
BER_BVZERO( &m->sml_values[1] ); |
|
BER_BVZERO( &m->sml_nvalues[1] ); |
|
op->o_tmpfree( ra, op->o_tmpmemctx ); |
|
} |
|
|
|
op->o_dn = op->o_bd->be_rootdn; |
|
op->o_ndn = op->o_bd->be_rootndn; |
|
if((rc = op->o_bd->be_modify(op, &rs)) != LDAP_SUCCESS) { |
|
Debug( LDAP_DEBUG_TRACE, |
|
"refint_response: dependent modify failed: %d\n", |
|
rs.sr_err, 0, 0 ); |
|
} |
|
|
|
while (( m = op->orm_modlist )) { |
|
op->orm_modlist = m->sml_next; |
|
op->o_tmpfree( m, op->o_tmpmemctx ); |
|
if ( m == first ) break; |
|
} |
|
slap_mods_free( op->orm_modlist, 1 ); |
|
op->o_tmpfree( dp->ndn.bv_val, op->o_tmpmemctx ); |
|
op->o_tmpfree( dp->dn.bv_val, op->o_tmpmemctx ); |
|
op->o_tmpfree( dp, op->o_tmpmemctx ); |
} |
} |
} |
done: |
} |
if ( !BER_BVISNULL( &rq->newndn )) { |
if (ip) { |
ch_free( rq->newndn.bv_val ); |
ip->next = dd->mods; |
ch_free( rq->newdn.bv_val ); |
dd->mods = ip; |
} |
|
ch_free( rq->oldndn.bv_val ); |
|
ch_free( rq->olddn.bv_val ); |
|
ch_free( rq ); |
} |
} |
|
|
return(0); |
/* wait until we get explicitly scheduled again */ |
} |
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); |
|
ldap_pvt_runqueue_stoptask( &slapd_rq, id->qtask ); |
|
ldap_pvt_runqueue_resched( &slapd_rq,id->qtask, 1 ); |
|
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); |
|
|
|
return NULL; |
|
} |
|
|
/* |
/* |
** refint_response |
** refint_response |
Line 523 refint_response(
|
Line 617 refint_response(
|
SlapReply *rs |
SlapReply *rs |
) |
) |
{ |
{ |
Operation nop = *op; |
|
SlapReply nrs = { REP_RESULT }; |
|
slap_callback cb = { NULL, NULL, NULL, NULL }; |
|
slap_callback cb2 = { NULL, slap_replog_cb, NULL, NULL }; |
|
slap_callback *cbo, *cbp; |
|
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; |
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; |
refint_data *id = on->on_bi.bi_private; |
refint_data *id = on->on_bi.bi_private; |
refint_data dd = *id; |
|
refint_attrs *ip; |
|
dependent_data *dp; |
|
BerValue pdn; |
BerValue pdn; |
int rc, ac; |
int rc, ac; |
Filter ftop, *fptr; |
refint_q *rq; |
|
BackendDB *db; |
|
refint_attrs *ip; |
|
|
id->message = "_refint_response"; |
id->message = "_refint_response"; |
|
|
Line 562 refint_response(
|
Line 650 refint_response(
|
** |
** |
*/ |
*/ |
|
|
nop.o_bd = select_backend(&id->dn, 0, 1); |
db = select_backend(&id->dn, 0, 1); |
|
|
if(nop.o_bd) { |
if(db) { |
if (!nop.o_bd->be_search || !nop.o_bd->be_modify) { |
if (!db->be_search || !db->be_modify) { |
Debug( LDAP_DEBUG_TRACE, |
Debug( LDAP_DEBUG_TRACE, |
"refint_response: backend missing search and/or modify\n", |
"refint_response: backend missing search and/or modify\n", |
0, 0, 0 ); |
0, 0, 0 ); |
Line 578 refint_response(
|
Line 666 refint_response(
|
return SLAP_CB_CONTINUE; |
return SLAP_CB_CONTINUE; |
} |
} |
|
|
cb2.sc_next = &cb; |
rq = ch_calloc( 1, sizeof( refint_q )); |
|
ber_dupbv( &rq->olddn, &op->o_req_dn ); |
/* |
ber_dupbv( &rq->oldndn, &op->o_req_ndn ); |
** if delete: set delete callback; |
rq->db = db; |
** else modrdn: create a newdn, set modify callback; |
rq->rdata = id; |
** |
|
*/ |
|
|
|
if(op->o_tag == LDAP_REQ_DELETE) { |
if(op->o_tag == LDAP_REQ_MODRDN) { |
cb.sc_response = &refint_delete_cb; |
|
dd.newdn.bv_val = NULL; |
|
dd.nnewdn.bv_val = NULL; |
|
} else { |
|
cb.sc_response = &refint_modrdn_cb; |
|
if ( op->oq_modrdn.rs_newSup ) { |
if ( op->oq_modrdn.rs_newSup ) { |
pdn = *op->oq_modrdn.rs_newSup; |
pdn = *op->oq_modrdn.rs_newSup; |
} else { |
} else { |
dnParent( &op->o_req_dn, &pdn ); |
dnParent( &op->o_req_dn, &pdn ); |
} |
} |
build_new_dn( &dd.newdn, &pdn, &op->orr_newrdn, NULL ); |
build_new_dn( &rq->newdn, &pdn, &op->orr_newrdn, NULL ); |
if ( op->oq_modrdn.rs_nnewSup ) { |
if ( op->oq_modrdn.rs_nnewSup ) { |
pdn = *op->oq_modrdn.rs_nnewSup; |
pdn = *op->oq_modrdn.rs_nnewSup; |
} else { |
} else { |
dnParent( &op->o_req_ndn, &pdn ); |
dnParent( &op->o_req_ndn, &pdn ); |
} |
} |
build_new_dn( &dd.nnewdn, &pdn, &op->orr_nnewrdn, NULL ); |
build_new_dn( &rq->newndn, &pdn, &op->orr_nnewrdn, NULL ); |
} |
|
|
|
/* |
|
** build a search filter for all configured attributes; |
|
** populate our Operation; |
|
** pass our data (attr list, dn) to backend via sc_private; |
|
** call the backend search function; |
|
** nb: (|(one=thing)) is valid, but do smart formatting anyway; |
|
** nb: 16 is arbitrarily a dozen or so extra bytes; |
|
** |
|
*/ |
|
|
|
ftop.f_choice = LDAP_FILTER_OR; |
|
ftop.f_next = NULL; |
|
ftop.f_or = NULL; |
|
nop.ors_filter = &ftop; |
|
for(ip = id->attrs; ip; ip = ip->next) { |
|
fptr = ch_malloc( sizeof(Filter) + sizeof(AttributeAssertion) ); |
|
fptr->f_choice = LDAP_FILTER_EQUALITY; |
|
fptr->f_ava = (AttributeAssertion *)(fptr+1); |
|
fptr->f_ava->aa_desc = ip->attr; |
|
fptr->f_ava->aa_value = op->o_req_ndn; |
|
fptr->f_next = ftop.f_or; |
|
ftop.f_or = fptr; |
|
} |
|
filter2bv( nop.ors_filter, &nop.ors_filterstr ); |
|
|
|
/* callback gets the searched dn instead */ |
|
dd.dn = op->o_req_ndn; |
|
dd.message = "_dependent_search"; |
|
dd.mods = NULL; |
|
cb.sc_private = ⅆ |
|
nop.o_callback = &cb; |
|
nop.o_tag = LDAP_REQ_SEARCH; |
|
nop.ors_scope = LDAP_SCOPE_SUBTREE; |
|
nop.ors_deref = LDAP_DEREF_NEVER; |
|
nop.ors_limit = NULL; |
|
nop.ors_slimit = SLAP_NO_LIMIT; |
|
nop.ors_tlimit = SLAP_NO_LIMIT; |
|
|
|
/* no attrs! */ |
|
nop.ors_attrs = slap_anlist_no_attrs; |
|
nop.ors_attrsonly = 1; |
|
|
|
nop.o_req_ndn = id->dn; |
|
nop.o_req_dn = id->dn; |
|
|
|
/* search */ |
|
rc = nop.o_bd->be_search(&nop, &nrs); |
|
|
|
ch_free( nop.ors_filterstr.bv_val ); |
|
while ( (fptr = ftop.f_or) != NULL ) { |
|
ftop.f_or = fptr->f_next; |
|
ch_free( fptr ); |
|
} |
|
ch_free(dd.nnewdn.bv_val); |
|
ch_free(dd.newdn.bv_val); |
|
dd.newdn.bv_val = NULL; |
|
dd.nnewdn.bv_val = NULL; |
|
|
|
if(rc != LDAP_SUCCESS) { |
|
Debug( LDAP_DEBUG_TRACE, |
|
"refint_response: search failed: %d\n", |
|
rc, 0, 0 ); |
|
goto done; |
|
} |
|
|
|
/* safety? paranoid just in case */ |
|
if(!cb.sc_private) { |
|
Debug( LDAP_DEBUG_TRACE, |
|
"refint_response: callback wiped out sc_private?!\n", |
|
0, 0, 0 ); |
|
goto done; |
|
} |
} |
|
|
/* presto! now it's a modify request with null callback */ |
ldap_pvt_thread_mutex_lock( &id->qmutex ); |
cb.sc_response = &refint_null_cb; |
if ( id->qtail ) { |
nop.o_tag = LDAP_REQ_MODIFY; |
id->qtail->next = rq; |
dd.message = "_dependent_modify"; |
} else { |
|
id->qhead = rq; |
/* See if the parent operation is going into the replog */ |
|
for (cbo=op->o_callback, cbp = cbo->sc_next; cbp; cbo=cbp,cbp=cbp->sc_next) { |
|
if (cbp->sc_response == slap_replog_cb) { |
|
/* Invoke replog now, arrange for our |
|
* dependent mods to also be logged |
|
*/ |
|
cbo->sc_next = cbp->sc_next; |
|
replog( op ); |
|
nop.o_callback = &cb2; |
|
break; |
|
} |
|
} |
} |
|
id->qtail = rq; |
|
ldap_pvt_thread_mutex_unlock( &id->qmutex ); |
|
|
/* |
ac = 0; |
** [our search callback builds a list of mods] |
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); |
** foreach mod: |
if ( !id->qtask ) { |
** make sure its dn has a backend; |
id->qtask = ldap_pvt_runqueue_insert( &slapd_rq, RUNQ_INTERVAL, |
** connect Modification* chain to our op; |
refint_qtask, id, "refint_qtask", |
** call the backend modify function; |
op->o_bd->be_suffix[0].bv_val ); |
** pass any errors upstream; |
ac = 1; |
** |
} else { |
*/ |
if ( !ldap_pvt_runqueue_isrunning( &slapd_rq, id->qtask ) && |
|
!id->qtask->next_sched.tv_sec ) { |
for(dp = dd.mods; dp; dp = dp->next) { |
id->qtask->interval.tv_sec = 0; |
nop.o_req_dn = dp->dn; |
ldap_pvt_runqueue_resched( &slapd_rq, id->qtask, 0 ); |
nop.o_req_ndn = dp->dn; |
id->qtask->interval.tv_sec = RUNQ_INTERVAL; |
nop.o_bd = select_backend(&dp->dn, 0, 1); |
ac = 1; |
if(!nop.o_bd) { |
|
Debug( LDAP_DEBUG_TRACE, |
|
"refint_response: no backend for DN %s!\n", |
|
dp->dn.bv_val, 0, 0 ); |
|
goto done; |
|
} |
|
nrs.sr_type = REP_RESULT; |
|
nop.orm_modlist = dp->mm; /* callback did all the work */ |
|
nop.o_dn = refint_dn; |
|
nop.o_ndn = refint_dn; |
|
nop.o_dn = nop.o_bd->be_rootdn; |
|
nop.o_ndn = nop.o_bd->be_rootndn; |
|
if(rs->sr_err != LDAP_SUCCESS) goto done; |
|
if((rc = nop.o_bd->be_modify(&nop, &nrs)) != LDAP_SUCCESS) { |
|
Debug( LDAP_DEBUG_TRACE, |
|
"refint_response: dependent modify failed: %d\n", |
|
nrs.sr_err, 0, 0 ); |
|
goto done; |
|
} |
} |
} |
} |
|
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); |
|
if ( ac ) |
|
slap_wake_listener(); |
|
|
done: |
return SLAP_CB_CONTINUE; |
for(dp = dd.mods; dp; dp = dd.mods) { |
|
dd.mods = dp->next; |
|
ch_free(dp->dn.bv_val); |
|
slap_mods_free(dp->mm, 1); |
|
} |
|
dd.mods = NULL; |
|
|
|
return(SLAP_CB_CONTINUE); |
|
} |
} |
|
|
/* |
/* |