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

version 1.19, 2006/04/04 20:16:24 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.18 2006/01/03 22:12:25 kurt 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 38 Line 38
 #include <ac/socket.h>  #include <ac/socket.h>
   
 #include "slap.h"  #include "slap.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 52  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 {
           REFINT_ATTRS = 1,
           REFINT_NOTHING
   };
   
   static ConfigDriver refint_cf_gen;
   
   static ConfigTable refintcfg[] = {
           { "refint_attributes", "attribute...", 2, 0, 0,
             ARG_MAGIC|REFINT_ATTRS, refint_cf_gen,
             "( OLcfgOvAt:11.1 NAME 'olcRefintAttribute' "
             "DESC 'Attributes for referential integrity' "
             "SYNTAX OMsDirectoryString )", NULL, NULL },
           { "refint_nothing", "string", 2, 2, 0,
             ARG_DN|ARG_MAGIC|REFINT_NOTHING, refint_cf_gen,
             "( OLcfgOvAt:11.2 NAME 'olcRefintNothing' "
             "DESC 'Replacement DN to supply when needed' "
             "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
           { NULL, NULL, 0, 0, 0, ARG_IGNORED }
   };
   
   static ConfigOCs refintocs[] = {
           { "( OLcfgOvOc:11.1 "
             "NAME 'olcRefintConfig' "
             "DESC 'Referential integrity configuration' "
             "SUP olcOverlayConfig "
             "MAY ( olcRefintAttribute $ olcRefintNothing ) )",
             Cft_Overlay, refintcfg },
           { NULL, 0, NULL }
   };
   
   static int
   refint_cf_gen(ConfigArgs *c)
   {
           slap_overinst *on = (slap_overinst *)c->bi;
           refint_data *dd = (refint_data *)on->on_bi.bi_private;
           refint_attrs *ip, *pip, **pipp = NULL;
           AttributeDescription *ad;
           const char *text;
           int rc = ARG_BAD_CONF;
           int i;
   
           switch ( c->op ) {
           case SLAP_CONFIG_EMIT:
                   switch ( c->type ) {
                   case REFINT_ATTRS:
                           ip = dd->attrs;
                           while ( ip ) {
                                   value_add_one( &c->rvalue_vals,
                                                  &ip->attr->ad_cname );
                                   ip = ip->next;
                           }
                           rc = 0;
                           break;
                   case REFINT_NOTHING:
                           if ( !BER_BVISEMPTY( &dd->nothing )) {
                                   rc = value_add_one( &c->rvalue_vals,
                                                       &dd->nothing );
                                   if ( rc ) return rc;
                                   rc = value_add_one( &c->rvalue_nvals,
                                                       &dd->nnothing );
                                   return rc;
                           }
                           rc = 0;
                           break;
                   default:
                           abort ();
                   }
                   break;
           case LDAP_MOD_DELETE:
                   switch ( c->type ) {
                   case REFINT_ATTRS:
                           pipp = &dd->attrs;
                           if ( c->valx < 0 ) {
                                   ip = *pipp;
                                   *pipp = NULL;
                                   while ( ip ) {
                                           pip = ip;
                                           ip = ip->next;
                                           ch_free ( pip );
                                   }
                           } else {
                                   /* delete from linked list */
                                   for ( i=0; i < c->valx; ++i ) {
                                           pipp = &(*pipp)->next;
                                   }
                                   ip = *pipp;
                                   *pipp = (*pipp)->next;
   
                                   /* AttributeDescriptions are global so
                                    * shouldn't be freed here... */
                                   ch_free ( ip );
                           }
                           rc = 0;
                           break;
                   case REFINT_NOTHING:
                           if ( dd->nothing.bv_val )
                                   ber_memfree ( dd->nothing.bv_val );
                           if ( dd->nnothing.bv_val )
                                   ber_memfree ( dd->nnothing.bv_val );
                           dd->nothing.bv_len = 0;
                           dd->nnothing.bv_len = 0;
                           rc = 0;
                           break;
                   default:
                           abort ();
                   }
                   break;
           case SLAP_CONFIG_ADD:
                   /* fallthrough to LDAP_MOD_ADD */
           case LDAP_MOD_ADD:
                   switch ( c->type ) {
                   case REFINT_ATTRS:
                           rc = 0;
                           for ( i=1; i < c->argc; ++i ) {
                                   ad = NULL;
                                   if ( slap_str2ad ( c->argv[i], &ad, &text )
                                        == LDAP_SUCCESS) {
                                           ip = ch_malloc (
                                                   sizeof ( refint_attrs ) );
                                           ip->attr = ad;
                                           ip->next = dd->attrs;
                                           dd->attrs = ip;
                                   } else {
                                           Debug ( LDAP_DEBUG_CONFIG,
                                                   "refint add: <%s>: %s\n",
                                                   c->argv[i], text, NULL );
                                           strncpy ( c->msg,
                                                     text,
                                                     SLAP_TEXT_BUFLEN-1 );
                                           c->msg[SLAP_TEXT_BUFLEN-1] = '\0';
                                           rc = ARG_BAD_CONF;
                                   }
                           }
                           break;
                   case REFINT_NOTHING:
                           if ( dd->nothing.bv_val )
                                   ber_memfree ( dd->nothing.bv_val );
                           if ( dd->nnothing.bv_val )
                                   ber_memfree ( dd->nnothing.bv_val );
                           dd->nothing = c->value_dn;
                           dd->nnothing = c->value_ndn;
                           rc = 0;
                           break;
                   default:
                           abort ();
                   }
                   break;
           default:
                   abort ();
           }
   
           return rc;
   }
   
 /*  /*
 ** allocate new refint_data;  ** allocate new refint_data;
 ** initialize, copy basedn;  
 ** store in on_bi.bi_private;  ** store in on_bi.bi_private;
 **  **
 */  */
Line 79  refint_db_init( Line 251  refint_db_init(
 )  )
 {  {
         slap_overinst *on = (slap_overinst *)be->bd_info;          slap_overinst *on = (slap_overinst *)be->bd_info;
         refint_data *id = ch_malloc(sizeof(refint_data));          refint_data *id = ch_calloc(1,sizeof(refint_data));
   
         id->message = "_init";          id->message = "_init";
         id->attrs = NULL;  
         id->newdn.bv_val = NULL;  
         id->nothing.bv_val = NULL;  
         id->nnothing.bv_val = NULL;  
         ber_dupbv( &id->dn, &be->be_nsuffix[0] );  
         on->on_bi.bi_private = id;          on->on_bi.bi_private = id;
           ldap_pvt_thread_mutex_init( &id->qmutex );
         return(0);          return(0);
 }  }
   
   
 /*  
 ** if command = attributes:  
 **      foreach argument:  
 **              convert to attribute;  
 **              add to configured attribute list;  
 ** elseif command = basedn:  
 **      set our basedn to argument;  
 **  
 */  
   
 static int  static int
 refint_config(  refint_db_destroy(
         BackendDB       *be,          BackendDB       *be
         const char      *fname,  
         int             lineno,  
         int             argc,  
         char            **argv  
 )  )
 {  {
         slap_overinst *on       = (slap_overinst *) be->bd_info;          slap_overinst *on = (slap_overinst *)be->bd_info;
         refint_data *id = on->on_bi.bi_private;  
         refint_attrs *ip;  
         const char *text;  
         AttributeDescription *ad;  
         BerValue dn;  
         int i;  
   
         if(!strcasecmp(*argv, "refint_attributes")) {          if ( on->on_bi.bi_private ) {
                 for(i = 1; i < argc; i++) {                  refint_data *id = on->on_bi.bi_private;
                         for(ip = id->attrs; ip; ip = ip->next)                  on->on_bi.bi_private = NULL;
                             if(!strcmp(argv[i], ip->attr->ad_cname.bv_val)) {                  ldap_pvt_thread_mutex_destroy( &id->qmutex );
                                 Debug(LDAP_DEBUG_ANY,                  ch_free( id );
                                         "%s: line %d: duplicate attribute <s>, ignored\n",  
                                         fname, lineno, argv[i]);  
                                 continue;  
                         }  
                         ad = NULL;  
                         if(slap_str2ad(argv[i], &ad, &text) != LDAP_SUCCESS) {  
                                 Debug(LDAP_DEBUG_ANY,  
                                         "%s: line %d: bad attribute <%s>, ignored\n",  
                                         fname, lineno, text);  
                                 continue;               /* XXX */  
                         } else if(ad->ad_next) {  
                                 Debug(LDAP_DEBUG_ANY,  
                                         "%s: line %d: multiple attributes match <%s>, ignored\n",  
                                         fname, lineno, argv[i]);  
                                 continue;  
                         }  
                         ip = ch_malloc(sizeof(refint_attrs));  
                         ip->attr = ad;  
                         ip->next = id->attrs;  
                         id->attrs = ip;  
                         Debug(LDAP_DEBUG_ANY, "%s: line %d: new attribute <%s>\n",  
                                 fname, lineno, argv[i]);  
                 }  
         } else if(!strcasecmp(*argv, "refint_base")) {  
                 /* XXX only one basedn (yet) - need validate argument! */  
                 if(id->dn.bv_val) ch_free(id->dn.bv_val);  
                 ber_str2bv( argv[1], 0, 0, &dn );  
                 Debug(LDAP_DEBUG_ANY, "%s: line %d: new baseDN <%s>\n",  
                         fname, lineno, argv[1]);  
                 if(dnNormalize(0, NULL, NULL, &dn, &id->dn, NULL)) {  
                         Debug(LDAP_DEBUG_ANY, "%s: line %d: bad baseDN!\n", fname, lineno, 0);  
                         return(1);  
                 }  
         } else if(!strcasecmp(*argv, "refint_nothing")) {  
                 if(id->nothing.bv_val) ch_free(id->nothing.bv_val);  
                 if(id->nnothing.bv_val) ch_free(id->nnothing.bv_val);  
                 ber_str2bv( argv[1], 0, 1, &id->nothing );  
                 if(dnNormalize(0, NULL, NULL, &id->nothing, &id->nnothing, NULL)) {  
                         Debug(LDAP_DEBUG_ANY, "%s: line %d: bad nothingDN!\n", fname, lineno, 0);  
                         return(1);  
                 }  
                 Debug(LDAP_DEBUG_ANY, "%s: line %d: new nothingDN<%s>\n",  
                         fname, lineno, argv[1]);  
         } else {  
                 return(SLAP_CONF_UNKNOWN);  
         }          }
   
         id->message = "_config";  
         return(0);          return(0);
 }  }
   
   
 /*  /*
 ** nothing really happens here;  ** initialize, copy basedn if not already set
 **  **
 */  */
   
Line 189  refint_open( Line 288  refint_open(
         slap_overinst *on       = (slap_overinst *)be->bd_info;          slap_overinst *on       = (slap_overinst *)be->bd_info;
         refint_data *id = on->on_bi.bi_private;          refint_data *id = on->on_bi.bi_private;
         id->message             = "_open";          id->message             = "_open";
   
           if ( BER_BVISNULL( &id->dn )) {
                   if ( BER_BVISNULL( &be->be_nsuffix[0] ))
                           return -1;
                   ber_dupbv( &id->dn, &be->be_nsuffix[0] );
           }
         return(0);          return(0);
 }  }
   
Line 222  refint_close( Line 327  refint_close(
         ch_free(id->nothing.bv_val);          ch_free(id->nothing.bv_val);
         ch_free(id->nnothing.bv_val);          ch_free(id->nnothing.bv_val);
   
         on->on_bi.bi_private = NULL;    /* XXX */          memset( id, 0, sizeof(*id));
   
         ch_free(id);  
   
         return(0);          return(0);
 }  }
   
 /*  /*
 ** 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 440  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 479  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 495  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 );
           rq->db = db;
           rq->rdata = id;
   
         /*          if(op->o_tag == LDAP_REQ_MODRDN) {
         ** if delete: set delete callback;  
         ** else modrdn: create a newdn, set modify callback;  
         **  
         */  
   
         if(op->o_tag == LDAP_REQ_DELETE) {  
                 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 );
         }          }
   
         /*          ldap_pvt_thread_mutex_lock( &id->qmutex );
         ** build a search filter for all configured attributes;          if ( id->qtail ) {
         ** populate our Operation;                  id->qtail->next = rq;
         ** pass our data (attr list, dn) to backend via sc_private;          } else {
         ** call the backend search function;                  id->qhead = rq;
         ** 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 */  
         cb.sc_response  = &refint_null_cb;  
         nop.o_tag       = LDAP_REQ_MODIFY;  
         dd.message      = "_dependent_modify";  
   
         /* 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);  
 }  }
   
 /*  /*
Line 666  done: Line 752  done:
 */  */
   
 int refint_initialize() {  int refint_initialize() {
           int rc;
   
         /* statically declared just after the #includes at top */          /* statically declared just after the #includes at top */
         refint.on_bi.bi_type = "refint";          refint.on_bi.bi_type = "refint";
         refint.on_bi.bi_db_init = refint_db_init;          refint.on_bi.bi_db_init = refint_db_init;
         refint.on_bi.bi_db_config = refint_config;          refint.on_bi.bi_db_destroy = refint_db_destroy;
         refint.on_bi.bi_db_open = refint_open;          refint.on_bi.bi_db_open = refint_open;
         refint.on_bi.bi_db_close = refint_close;          refint.on_bi.bi_db_close = refint_close;
         refint.on_response = refint_response;          refint.on_response = refint_response;
   
           refint.on_bi.bi_cf_ocs = refintocs;
           rc = config_register_schema ( refintcfg, refintocs );
           if ( rc ) return rc;
   
         return(overlay_register(&refint));          return(overlay_register(&refint));
 }  }
   

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


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