]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/modrdn.c
Merge remote-tracking branch 'origin/mdb.master' into OPENLDAP_REL_ENG_2_4
[openldap] / servers / slapd / modrdn.c
index 3aae6ac4448c7733197577d195e6069ab2d196e9..ed52fc02b00d2d980a9136eb9dd3af0216764cf1 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2007 The OpenLDAP Foundation.
+ * Copyright 1998-2014 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -214,9 +214,9 @@ cleanup:
 int
 fe_op_modrdn( Operation *op, SlapReply *rs )
 {
-       Backend         *newSuperior_be = NULL;
-       struct berval   pdn = BER_BVNULL;
+       struct berval   dest_ndn = BER_BVNULL, dest_pndn, pdn = BER_BVNULL;
        BackendDB       *op_be, *bd = op->o_bd;
+       ber_slen_t      diff;
        
        if( op->o_req_ndn.bv_len == 0 ) {
                Debug( LDAP_DEBUG_ANY, "%s do_modrdn: root dse!\n",
@@ -234,6 +234,23 @@ fe_op_modrdn( Operation *op, SlapReply *rs )
                goto cleanup;
        }
 
+       if( op->orr_nnewSup ) {
+               dest_pndn = *op->orr_nnewSup;
+       } else {
+               dnParent( &op->o_req_ndn, &dest_pndn );
+       }
+       build_new_dn( &dest_ndn, &dest_pndn, &op->orr_nnewrdn, op->o_tmpmemctx );
+
+       diff = (ber_slen_t) dest_ndn.bv_len - (ber_slen_t) op->o_req_ndn.bv_len;
+       if ( diff > 0 ? dnIsSuffix( &dest_ndn, &op->o_req_ndn )
+               : diff < 0 && dnIsSuffix( &op->o_req_ndn, &dest_ndn ) )
+       {
+               send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
+                       diff > 0 ? "cannot place an entry below itself"
+                       : "cannot place an entry above itself" );
+               goto cleanup;
+       }
+
        /*
         * We could be serving multiple database backends.  Select the
         * appropriate one, or send a referral to our "referral server"
@@ -275,19 +292,11 @@ fe_op_modrdn( Operation *op, SlapReply *rs )
                goto cleanup;
        }
 
-       /* Make sure that the entry being changed and the newSuperior are in 
-        * the same backend, otherwise we return an error.
-        */
-       if( op->orr_newSup ) {
-               newSuperior_be = select_backend( op->orr_nnewSup, 0 );
-
-               if ( newSuperior_be != op->o_bd ) {
-                       /* newSuperior is in different backend */
+       /* check that destination DN is in the same backend as source DN */
+       if ( select_backend( &dest_ndn, 0 ) != op->o_bd ) {
                        send_ldap_error( op, rs, LDAP_AFFECTS_MULTIPLE_DSAS,
                                "cannot rename between DSAs" );
-
                        goto cleanup;
-               }
        }
 
        /*
@@ -367,6 +376,8 @@ fe_op_modrdn( Operation *op, SlapReply *rs )
        }
 
 cleanup:;
+       if ( dest_ndn.bv_val != NULL )
+               ber_memfree_x( dest_ndn.bv_val, op->o_tmpmemctx );
        op->o_bd = bd;
        return rs->sr_err;
 }
@@ -381,7 +392,9 @@ slap_modrdn2mods(
        LDAPRDN         new_rdn = NULL;
 
        assert( !BER_BVISEMPTY( &op->oq_modrdn.rs_newrdn ) );
-       assert( !op->orr_deleteoldrdn || !BER_BVISEMPTY( &op->o_req_dn ) );
+
+       /* if requestDN is empty, silently reset deleteOldRDN */
+       if ( BER_BVISEMPTY( &op->o_req_dn ) ) op->orr_deleteoldrdn = 0;
 
        if ( ldap_bv2rdn_x( &op->oq_modrdn.rs_newrdn, &new_rdn,
                (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) {
@@ -390,7 +403,7 @@ slap_modrdn2mods(
                        "type(s)/value(s) of newrdn\n",
                        op->o_log_prefix, 0, 0 );
                rs->sr_err = LDAP_INVALID_DN_SYNTAX;
-               rs->sr_text = "unknown type(s) used in RDN";
+               rs->sr_text = "unknown type(s)/value(s) used in RDN";
                goto done;
        }
 
@@ -419,26 +432,45 @@ slap_modrdn2mods(
                        Debug( LDAP_DEBUG_TRACE,
                                "%s slap_modrdn2mods: %s: %s (new)\n",
                                op->o_log_prefix,
-                               rs->sr_text, 
+                               rs->sr_text,
                                new_rdn[ a_cnt ]->la_attr.bv_val );
                        goto done;              
                }
 
+               if ( !desc->ad_type->sat_equality ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "%s slap_modrdn2mods: %s: %s (new)\n",
+                               op->o_log_prefix,
+                               rs->sr_text,
+                               new_rdn[ a_cnt ]->la_attr.bv_val );
+                       rs->sr_text = "naming attribute has no equality matching rule";
+                       rs->sr_err = LDAP_NAMING_VIOLATION;
+                       goto done;
+               }
+
                /* Apply modification */
                mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) );
                mod_tmp->sml_desc = desc;
                BER_BVZERO( &mod_tmp->sml_type );
+               mod_tmp->sml_numvals = 1;
                mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
                ber_dupbv( &mod_tmp->sml_values[0], &new_rdn[a_cnt]->la_value );
                mod_tmp->sml_values[1].bv_val = NULL;
                if( desc->ad_type->sat_equality->smr_normalize) {
                        mod_tmp->sml_nvalues = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
-                       (void) (*desc->ad_type->sat_equality->smr_normalize)(
+                       rs->sr_err = desc->ad_type->sat_equality->smr_normalize(
                                SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
                                desc->ad_type->sat_syntax,
                                desc->ad_type->sat_equality,
                                &mod_tmp->sml_values[0],
                                &mod_tmp->sml_nvalues[0], NULL );
+                       if (rs->sr_err != LDAP_SUCCESS) {
+                               ch_free(mod_tmp->sml_nvalues);
+                               ch_free(mod_tmp->sml_values[0].bv_val);
+                               ch_free(mod_tmp->sml_values);
+                               ch_free(mod_tmp);
+                               goto done;
+                       }
                        mod_tmp->sml_nvalues[1].bv_val = NULL;
                } else {
                        mod_tmp->sml_nvalues = NULL;
@@ -469,6 +501,7 @@ slap_modrdn2mods(
                        mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) );
                        mod_tmp->sml_desc = desc;
                        BER_BVZERO( &mod_tmp->sml_type );
+                       mod_tmp->sml_numvals = 1;
                        mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
                        ber_dupbv( &mod_tmp->sml_values[0], &old_rdn[d_cnt]->la_value );
                        mod_tmp->sml_values[1].bv_val = NULL;