]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/refint.c
Happy New Year
[openldap] / servers / slapd / overlays / refint.c
index 03a5e0e101dd604bfe701eec28cd1e1a109faf36..da9c7fdfe581930143c4220487a905cb128f662d 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2004-2015 The OpenLDAP Foundation.
+ * Copyright 2004-2018 The OpenLDAP Foundation.
  * Portions Copyright 2004 Symas Corporation.
  * All rights reserved.
  *
@@ -74,6 +74,7 @@ typedef struct refint_q {
        BerValue oldndn;
        BerValue newdn;
        BerValue newndn;
+       int do_sub;
 } refint_q;
 
 typedef struct refint_data_s {
@@ -86,9 +87,15 @@ typedef struct refint_data_s {
        struct re_s *qtask;
        refint_q *qhead;
        refint_q *qtail;
+       BackendDB *db;
        ldap_pvt_thread_mutex_t qmutex;
 } refint_data;
 
+typedef struct refint_pre_s {
+       slap_overinst *on;
+       int do_sub;
+} refint_pre;
+
 #define        RUNQ_INTERVAL   36000   /* a long time */
 
 static MatchingRule    *mr_dnSubtreeMatch;
@@ -228,7 +235,7 @@ refint_cf_gen(ConfigArgs *c)
                }
                break;
        case SLAP_CONFIG_ADD:
-               /* fallthrough to LDAP_MOD_ADD */
+               /* fallthru to LDAP_MOD_ADD */
        case LDAP_MOD_ADD:
                switch ( c->type ) {
                case REFINT_ATTRS:
@@ -357,6 +364,36 @@ refint_open(
                ber_dupbv( &id->refint_dn, &refint_dn );
                ber_dupbv( &id->refint_ndn, &refint_ndn );
        }
+
+       /*
+       ** find the backend that matches our configured basedn;
+       ** make sure it exists and has search and modify methods;
+       **
+       */
+
+       if ( on->on_info->oi_origdb != frontendDB ) {
+               BackendDB *db = select_backend(&id->dn, 1);
+
+               if ( db ) {
+                       BackendInfo *bi;
+                       if ( db == be )
+                               bi = on->on_info->oi_orig;
+                       else
+                               bi = db->bd_info;
+                       if ( !bi->bi_op_search || !bi->bi_op_modify ) {
+                               Debug( LDAP_DEBUG_CONFIG,
+                                       "refint_response: backend missing search and/or modify\n",
+                                       0, 0, 0 );
+                               return -1;
+                       }
+                       id->db = db;
+               } else {
+                       Debug( LDAP_DEBUG_CONFIG,
+                               "refint_response: no backend for our baseDN %s??\n",
+                               id->dn.bv_val, 0, 0 );
+                       return -1;
+               }
+       }
        return(0);
 }
 
@@ -433,6 +470,8 @@ refint_search_cb(
 
                        na = NULL;
 
+                       /* Are we doing subtree matching or simple equality? */
+                       if ( rq->do_sub ) {
                        for(i = 0, b = a->a_nvals; b[i].bv_val; i++) {
                                if(dnIsSuffix(&b[i], &rq->oldndn)) {
                                        is_exact = b[i].bv_len == rq->oldndn.bv_len;
@@ -504,9 +543,24 @@ refint_search_cb(
                                        ber_bvarray_add_x( &na->new_nvals, &dn, op->o_tmpmemctx );
                                }
                        }
+                       } else {
+                               /* entry has no children, just equality matching */
+                               is_exact = attr_valfind( a,
+                                       SLAP_MR_EQUALITY|SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH|
+                                       SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, &rq->oldndn, &i, NULL );
+                               if ( is_exact == LDAP_SUCCESS ) {
+                                       na = op->o_tmpcalloc( 1,
+                                               sizeof( refint_attrs ),
+                                               op->o_tmpmemctx );
+                                       na->next = ip->attrs;
+                                       ip->attrs = na;
+                                       na->attr = ia->attr;
+                                       na->ra_numvals = 1;
+                               }
+                       }
 
                        /* Deleting/replacing all values and a nothing DN is configured? */
-                       if ( na && na->ra_numvals == i && !BER_BVISNULL(&dd->nothing) )
+                       if ( na && na->ra_numvals == a->a_numvals && !BER_BVISNULL(&dd->nothing) )
                                na->dont_empty = 1;
 
                        Debug( LDAP_DEBUG_TRACE, "refint_search_cb: %s: %s (#%d)\n",
@@ -729,11 +783,9 @@ refint_qtask( void *ctx, void *arg )
        ftop.f_or = NULL;
        op->ors_filter = &ftop;
        for(ip = id->attrs; ip; ip = ip->next) {
+               /* this filter can be either EQUALITY or EXT */
                fptr = op->o_tmpcalloc( sizeof(Filter) + sizeof(MatchingRuleAssertion),
                        1, op->o_tmpmemctx );
-               /* Use (attr:dnSubtreeMatch:=value) to catch subtree rename
-                * and subtree delete where supported */
-               fptr->f_choice = LDAP_FILTER_EXT;
                fptr->f_mra = (MatchingRuleAssertion *)(fptr+1);
                fptr->f_mr_rule = mr_dnSubtreeMatch;
                fptr->f_mr_rule_text = mr_dnSubtreeMatch->smr_bvoid;
@@ -764,8 +816,15 @@ refint_qtask( void *ctx, void *arg )
                if ( !rq )
                        break;
 
-               for (fptr = ftop.f_or; fptr; fptr = fptr->f_next )
+               for (fptr = ftop.f_or; fptr; fptr = fptr->f_next ) {
                        fptr->f_mr_value = rq->oldndn;
+                       /* Use (attr:dnSubtreeMatch:=value) to catch subtree rename
+                        * and subtree delete where supported */
+                       if (rq->do_sub)
+                               fptr->f_choice = LDAP_FILTER_EXT;
+                       else
+                               fptr->f_choice = LDAP_FILTER_EQUALITY;
+               }
 
                filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
 
@@ -875,60 +934,29 @@ refint_response(
        SlapReply *rs
 )
 {
-       slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
-       refint_data *id = on->on_bi.bi_private;
+       refint_pre *rp;
+       slap_overinst *on;
+       refint_data *id;
        BerValue pdn;
-       int ac;
        refint_q *rq;
-       BackendDB *db = NULL;
        refint_attrs *ip;
+       int ac;
 
        /* If the main op failed or is not a Delete or ModRdn, ignore it */
        if (( op->o_tag != LDAP_REQ_DELETE && op->o_tag != LDAP_REQ_MODRDN ) ||
                rs->sr_err != LDAP_SUCCESS )
                return SLAP_CB_CONTINUE;
 
-       /*
-       ** validate (and count) the list of attrs;
-       **
-       */
-
-       for(ip = id->attrs, ac = 0; ip; ip = ip->next, ac++);
-       if(!ac) {
-               Debug( LDAP_DEBUG_TRACE,
-                       "refint_response called without any attributes\n", 0, 0, 0 );
-               return SLAP_CB_CONTINUE;
-       }
-
-       /*
-       ** find the backend that matches our configured basedn;
-       ** make sure it exists and has search and modify methods;
-       **
-       */
-
-       if ( on->on_info->oi_origdb != frontendDB ) {
-               db = select_backend(&id->dn, 1);
-
-               if ( db ) {
-                       if ( !db->be_search || !db->be_modify ) {
-                               Debug( LDAP_DEBUG_TRACE,
-                                       "refint_response: backend missing search and/or modify\n",
-                                       0, 0, 0 );
-                               return SLAP_CB_CONTINUE;
-                       }
-               } else {
-                       Debug( LDAP_DEBUG_TRACE,
-                               "refint_response: no backend for our baseDN %s??\n",
-                               id->dn.bv_val, 0, 0 );
-                       return SLAP_CB_CONTINUE;
-               }
-       }
+       rp = op->o_callback->sc_private;
+       on = rp->on;
+       id = on->on_bi.bi_private;
 
        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->db = id->db;
        rq->rdata = id;
+       rq->do_sub = rp->do_sub;
 
        if ( op->o_tag == LDAP_REQ_MODRDN ) {
                if ( op->oq_modrdn.rs_newSup ) {
@@ -977,6 +1005,47 @@ refint_response(
        return SLAP_CB_CONTINUE;
 }
 
+/* Check if the target entry exists and has children.
+ * Do nothing if target doesn't exist.
+ */
+static int
+refint_preop(
+       Operation *op,
+       SlapReply *rs
+)
+{
+       slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+       refint_data *id = on->on_bi.bi_private;
+       Entry *e;
+       int rc;
+
+       /* are any attrs configured? */
+       if ( !id->attrs )
+               return SLAP_CB_CONTINUE;
+
+       rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on );
+       if ( rc == LDAP_SUCCESS ) {
+               slap_callback *sc = op->o_tmpcalloc( 1,
+                       sizeof(slap_callback)+sizeof(refint_pre), op->o_tmpmemctx );
+               refint_pre *rp = (refint_pre *)(sc+1);
+               rp->on = on;
+               rp->do_sub = 1; /* assume there are children */
+               if ( op->o_bd->be_has_subordinates ) {
+                       int has = 0;
+                       rc = op->o_bd->be_has_subordinates( op, e, &has );
+                       /* there definitely are not children */
+                       if ( rc == LDAP_SUCCESS && has == LDAP_COMPARE_FALSE )
+                               rp->do_sub = 0;
+               }
+               overlay_entry_release_ov( op, e, 0, on );
+               sc->sc_response = refint_response;
+               sc->sc_private = rp;
+               sc->sc_next = op->o_callback;
+               op->o_callback = sc;
+       }
+       return SLAP_CB_CONTINUE;
+}
+
 /*
 ** init_module is last so the symbols resolve "for free" --
 ** it expects to be called automagically during dynamic module initialization
@@ -999,7 +1068,8 @@ int refint_initialize() {
        refint.on_bi.bi_db_destroy = refint_db_destroy;
        refint.on_bi.bi_db_open = refint_open;
        refint.on_bi.bi_db_close = refint_close;
-       refint.on_response = refint_response;
+       refint.on_bi.bi_op_delete = refint_preop;
+       refint.on_bi.bi_op_modrdn = refint_preop;
 
        refint.on_bi.bi_cf_ocs = refintocs;
        rc = config_register_schema ( refintcfg, refintocs );