Diff for /servers/slapd/overlays/refint.c between versions 1.19.2.1 and 1.19.2.2

version 1.19.2.1, 2006/05/15 17:04:44 version 1.19.2.2, 2006/08/17 23:50:32
Line 1 Line 1
 /* refint.c - referential integrity module */  /* refint.c - referential integrity module */
 /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/refint.c,v 1.22 2006/04/27 14:05:41 hallvard Exp $ */  /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/refint.c,v 1.19.2.1 2006/05/15 17:04:44 kurt 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 */  /* The DN to use in the ModifiersName for all refint updates */
 static BerValue refint_dn = BER_BVC("cn=Referential Integrity Overlay");  static BerValue refint_dn = BER_BVC("cn=Referential Integrity Overlay");
   static BerValue refint_ndn = 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;
Line 53  typedef struct refint_attrs_s { Line 55  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 255  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 267  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 333  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;
                   op->o_dn = op->o_bd->be_rootdn;
                   op->o_ndn = op->o_bd->be_rootndn;
                   slap_op_time( &op->o_time, &op->o_tincr );
   
                   /* 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;
                   **
                   */
   
                   for(dp = rq->attrs; dp; dp = dp->next) {
                           Modifications *m, *first = NULL;
   
                           op->orm_modlist = 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 */                                  /* Set our ModifiersName */
                         mp->sml_type = ia->attr->ad_cname;                                  if ( SLAP_LASTMOD( op->o_bd )) {
                         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_REPLACE;
                         ip->mm = mp;                                          m->sml_flags = SLAP_MOD_INTERNAL;
                         mp = ch_malloc(sizeof(Modifications));                                          m->sml_desc = slap_schema.si_ad_modifiersName;
                         mp->sml_op = LDAP_MOD_DELETE;                                          m->sml_type = m->sml_desc->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));                                          m->sml_values[0] = refint_dn;
                         ber_dupbv(&mp->sml_values[0], &dd->dn);                                          m->sml_nvalues[0] = refint_ndn;
                         ber_dupbv(&mp->sml_nvalues[0], &dd->dn);                                  }
                         mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;                                  if ( !BER_BVISEMPTY( &rq->newdn ) || ( ra->next &&
                         mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;                                          ra->attr == ra->next->attr )) {
                         mp->sml_next = ip->mm;                                          m = op->o_tmpalloc( sizeof(Modifications) +
                         ip->mm = mp;                                                  4*sizeof(BerValue), op->o_tmpmemctx );
                         Debug(LDAP_DEBUG_TRACE, "refint_modrdn_cb: %s: %s\n",                                          m->sml_next = op->orm_modlist;
                                 a->a_desc->ad_cname.bv_val, dd->dn.bv_val, 0);                                          if ( !first )
                                                   first = m;
                                           op->orm_modlist = m;
                                           m->sml_op = LDAP_MOD_ADD;
                                           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;
                                           BER_BVZERO( &m->sml_values[1] );
                                           BER_BVZERO( &m->sml_nvalues[1] );
                                           if ( BER_BVISEMPTY( &rq->newdn )) {
                                                   op->o_tmpfree( ra, op->o_tmpmemctx );
                                                   ra = dp->attrs;
                                                   dp->attrs = ra->next;
                                                   m->sml_values[0] = id->nothing;
                                                   m->sml_nvalues[0] = id->nnothing;
                                           } else {
                                                   m->sml_values[0] = rq->newdn;
                                                   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;
                           slap_op_time( &op->o_time, &op->o_tincr );
                           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 644  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 677  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 693  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   = &dd;  
         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);  
 }  }
   
 /*  /*

Removed from v.1.19.2.1  
changed lines
  Added in v.1.19.2.2


______________
© Copyright 1998-2020, OpenLDAP Foundation, info@OpenLDAP.org