Back to index

openldap  2.4.31
modrdn.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* Portions Copyright 1999, Juan C. Gomez, All rights reserved.
00016  * This software is not subject to any license of Silicon Graphics 
00017  * Inc. or Purdue University.
00018  *
00019  * Redistribution and use in source and binary forms are permitted
00020  * without restriction or fee of any kind as long as this notice
00021  * is preserved.
00022  */
00023 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
00024  * All rights reserved.
00025  *
00026  * Redistribution and use in source and binary forms are permitted
00027  * provided that this notice is preserved and that due credit is given
00028  * to the University of Michigan at Ann Arbor. The name of the University
00029  * may not be used to endorse or promote products derived from this
00030  * software without specific prior written permission. This software
00031  * is provided ``as is'' without express or implied warranty.
00032  */
00033 
00034 #include "portable.h"
00035 
00036 #include <stdio.h>
00037 
00038 #include <ac/socket.h>
00039 #include <ac/string.h>
00040 
00041 #include "slap.h"
00042 
00043 int
00044 do_modrdn(
00045     Operation *op,
00046     SlapReply *rs
00047 )
00048 {
00049        struct berval dn = BER_BVNULL;
00050        struct berval newrdn = BER_BVNULL;
00051        struct berval newSuperior = BER_BVNULL;
00052        ber_int_t     deloldrdn;
00053 
00054        struct berval pnewSuperior = BER_BVNULL;
00055 
00056        struct berval nnewSuperior = BER_BVNULL;
00057 
00058        ber_len_t     length;
00059 
00060        Debug( LDAP_DEBUG_TRACE, "%s do_modrdn\n",
00061                      op->o_log_prefix, 0, 0 );
00062        /*
00063         * Parse the modrdn request.  It looks like this:
00064         *
00065         *     ModifyRDNRequest := SEQUENCE {
00066         *            entry  DistinguishedName,
00067         *            newrdn RelativeDistinguishedName
00068         *            deleteoldrdn  BOOLEAN,
00069         *            newSuperior   [0] LDAPDN OPTIONAL (v3 Only!)
00070         *     }
00071         */
00072 
00073        if ( ber_scanf( op->o_ber, "{mmb", &dn, &newrdn, &deloldrdn )
00074            == LBER_ERROR )
00075        {
00076               Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf failed\n",
00077                      op->o_log_prefix, 0, 0 );
00078               send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
00079               return SLAPD_DISCONNECT;
00080        }
00081 
00082        /* Check for newSuperior parameter, if present scan it */
00083 
00084        if ( ber_peek_tag( op->o_ber, &length ) == LDAP_TAG_NEWSUPERIOR ) {
00085               if ( op->o_protocol < LDAP_VERSION3 ) {
00086                      /* Connection record indicates v2 but field 
00087                       * newSuperior is present: report error.
00088                       */
00089                      Debug( LDAP_DEBUG_ANY,
00090                             "%s do_modrdn: newSuperior requires LDAPv3\n",
00091                             op->o_log_prefix, 0, 0 );
00092 
00093                      send_ldap_discon( op, rs,
00094                             LDAP_PROTOCOL_ERROR, "newSuperior requires LDAPv3" );
00095                      rs->sr_err = SLAPD_DISCONNECT;
00096                      goto cleanup;
00097               }
00098 
00099               if ( ber_scanf( op->o_ber, "m", &newSuperior ) 
00100                    == LBER_ERROR ) {
00101 
00102                      Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf(\"m\") failed\n",
00103                             op->o_log_prefix, 0, 0 );
00104 
00105                      send_ldap_discon( op, rs,
00106                             LDAP_PROTOCOL_ERROR, "decoding error" );
00107                      rs->sr_err = SLAPD_DISCONNECT;
00108                      goto cleanup;
00109               }
00110               op->orr_newSup = &pnewSuperior;
00111               op->orr_nnewSup = &nnewSuperior;
00112        }
00113 
00114        Debug( LDAP_DEBUG_ARGS,
00115            "do_modrdn: dn (%s) newrdn (%s) newsuperior (%s)\n",
00116               dn.bv_val, newrdn.bv_val,
00117               newSuperior.bv_len ? newSuperior.bv_val : "" );
00118 
00119        if ( ber_scanf( op->o_ber, /*{*/ "}") == LBER_ERROR ) {
00120               Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf failed\n",
00121                      op->o_log_prefix, 0, 0 );
00122               send_ldap_discon( op, rs,
00123                      LDAP_PROTOCOL_ERROR, "decoding error" );
00124               rs->sr_err = SLAPD_DISCONNECT;
00125               goto cleanup;
00126        }
00127 
00128        if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
00129               Debug( LDAP_DEBUG_ANY, "%s do_modrdn: get_ctrls failed\n",
00130                      op->o_log_prefix, 0, 0 );
00131               /* get_ctrls has sent results.     Now clean up. */
00132               goto cleanup;
00133        } 
00134 
00135        rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
00136        if( rs->sr_err != LDAP_SUCCESS ) {
00137               Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid dn (%s)\n",
00138                      op->o_log_prefix, dn.bv_val, 0 );
00139               send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
00140               goto cleanup;
00141        }
00142 
00143        /* FIXME: should have/use rdnPretty / rdnNormalize routines */
00144 
00145        rs->sr_err = dnPrettyNormal( NULL, &newrdn, &op->orr_newrdn, &op->orr_nnewrdn, op->o_tmpmemctx );
00146        if( rs->sr_err != LDAP_SUCCESS ) {
00147               Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid newrdn (%s)\n",
00148                      op->o_log_prefix, newrdn.bv_val, 0 );
00149               send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid new RDN" );
00150               goto cleanup;
00151        }
00152 
00153        if( rdn_validate( &op->orr_newrdn ) != LDAP_SUCCESS ) {
00154               Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid rdn (%s)\n",
00155                      op->o_log_prefix, op->orr_newrdn.bv_val, 0 );
00156               send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid new RDN" );
00157               goto cleanup;
00158        }
00159 
00160        if( op->orr_newSup ) {
00161               rs->sr_err = dnPrettyNormal( NULL, &newSuperior, &pnewSuperior,
00162                      &nnewSuperior, op->o_tmpmemctx );
00163               if( rs->sr_err != LDAP_SUCCESS ) {
00164                      Debug( LDAP_DEBUG_ANY,
00165                             "%s do_modrdn: invalid newSuperior (%s)\n",
00166                             op->o_log_prefix, newSuperior.bv_val, 0 );
00167                      send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid newSuperior" );
00168                      goto cleanup;
00169               }
00170        }
00171 
00172        Statslog( LDAP_DEBUG_STATS, "%s MODRDN dn=\"%s\"\n",
00173            op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 );
00174 
00175        op->orr_deleteoldrdn = deloldrdn;
00176        op->orr_modlist = NULL;
00177 
00178        /* prepare modlist of modifications from old/new RDN */
00179        rs->sr_err = slap_modrdn2mods( op, rs );
00180        if ( rs->sr_err != LDAP_SUCCESS ) {
00181               send_ldap_result( op, rs );
00182               goto cleanup;
00183        }
00184 
00185        op->o_bd = frontendDB;
00186        rs->sr_err = frontendDB->be_modrdn( op, rs );
00187 
00188 #ifdef LDAP_X_TXN
00189        if( rs->sr_err == LDAP_X_TXN_SPECIFY_OKAY ) {
00190               /* skip cleanup */
00191        }
00192 #endif
00193 
00194 cleanup:
00195        op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
00196        op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
00197 
00198        op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );       
00199        op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );      
00200 
00201        if ( op->orr_modlist != NULL )
00202               slap_mods_free( op->orr_modlist, 1 );
00203 
00204        if ( !BER_BVISNULL( &pnewSuperior ) ) {
00205               op->o_tmpfree( pnewSuperior.bv_val, op->o_tmpmemctx );
00206        }
00207        if ( !BER_BVISNULL( &nnewSuperior ) ) {
00208               op->o_tmpfree( nnewSuperior.bv_val, op->o_tmpmemctx );
00209        }
00210 
00211        return rs->sr_err;
00212 }
00213 
00214 int
00215 fe_op_modrdn( Operation *op, SlapReply *rs )
00216 {
00217        struct berval dest_ndn = BER_BVNULL, dest_pndn, pdn = BER_BVNULL;
00218        BackendDB     *op_be, *bd = op->o_bd;
00219        ber_slen_t    diff;
00220        
00221        if( op->o_req_ndn.bv_len == 0 ) {
00222               Debug( LDAP_DEBUG_ANY, "%s do_modrdn: root dse!\n",
00223                      op->o_log_prefix, 0, 0 );
00224               send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
00225                      "cannot rename the root DSE" );
00226               goto cleanup;
00227 
00228        } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) {
00229               Debug( LDAP_DEBUG_ANY, "%s do_modrdn: subschema subentry: %s (%ld)\n",
00230                      op->o_log_prefix, frontendDB->be_schemandn.bv_val, (long)frontendDB->be_schemandn.bv_len );
00231 
00232               send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
00233                      "cannot rename subschema subentry" );
00234               goto cleanup;
00235        }
00236 
00237        if( op->orr_nnewSup ) {
00238               dest_pndn = *op->orr_nnewSup;
00239        } else {
00240               dnParent( &op->o_req_ndn, &dest_pndn );
00241        }
00242        build_new_dn( &dest_ndn, &dest_pndn, &op->orr_nnewrdn, op->o_tmpmemctx );
00243 
00244        diff = (ber_slen_t) dest_ndn.bv_len - (ber_slen_t) op->o_req_ndn.bv_len;
00245        if ( diff > 0 ? dnIsSuffix( &dest_ndn, &op->o_req_ndn )
00246               : diff < 0 && dnIsSuffix( &op->o_req_ndn, &dest_ndn ) )
00247        {
00248               send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
00249                      diff > 0 ? "cannot place an entry below itself"
00250                      : "cannot place an entry above itself" );
00251               goto cleanup;
00252        }
00253 
00254        /*
00255         * We could be serving multiple database backends.  Select the
00256         * appropriate one, or send a referral to our "referral server"
00257         * if we don't hold it.
00258         */
00259        op->o_bd = select_backend( &op->o_req_ndn, 1 );
00260        if ( op->o_bd == NULL ) {
00261               op->o_bd = bd;
00262               rs->sr_ref = referral_rewrite( default_referral,
00263                      NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
00264               if (!rs->sr_ref) rs->sr_ref = default_referral;
00265 
00266               if ( rs->sr_ref != NULL ) {
00267                      rs->sr_err = LDAP_REFERRAL;
00268                      send_ldap_result( op, rs );
00269 
00270                      if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref );
00271               } else {
00272                      send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
00273                             "no global superior knowledge" );
00274               }
00275               goto cleanup;
00276        }
00277 
00278        /* If we've got a glued backend, check the real backend */
00279        op_be = op->o_bd;
00280        if ( SLAP_GLUE_INSTANCE( op->o_bd )) {
00281               op->o_bd = select_backend( &op->o_req_ndn, 0 );
00282        }
00283 
00284        /* check restrictions */
00285        if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
00286               send_ldap_result( op, rs );
00287               goto cleanup;
00288        }
00289 
00290        /* check for referrals */
00291        if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
00292               goto cleanup;
00293        }
00294 
00295        /* check that destination DN is in the same backend as source DN */
00296        if ( select_backend( &dest_ndn, 0 ) != op->o_bd ) {
00297                      send_ldap_error( op, rs, LDAP_AFFECTS_MULTIPLE_DSAS,
00298                             "cannot rename between DSAs" );
00299                      goto cleanup;
00300        }
00301 
00302        /*
00303         * do the modrdn if 1 && (2 || 3)
00304         * 1) there is a modrdn function implemented in this backend;
00305         * 2) this backend is master for what it holds;
00306         * 3) it's a replica and the dn supplied is the update_ndn.
00307         */
00308        if ( op->o_bd->be_modrdn ) {
00309               /* do the update here */
00310               int repl_user = be_isupdate( op );
00311               if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user )
00312               {
00313                      op->o_bd = op_be;
00314                      op->o_bd->be_modrdn( op, rs );
00315 
00316                      if ( op->o_bd->be_delete ) {
00317                             struct berval org_req_dn = BER_BVNULL;
00318                             struct berval org_req_ndn = BER_BVNULL;
00319                             struct berval org_dn = BER_BVNULL;
00320                             struct berval org_ndn = BER_BVNULL;
00321                             int           org_managedsait;
00322 
00323                             org_req_dn = op->o_req_dn;
00324                             org_req_ndn = op->o_req_ndn;
00325                             org_dn = op->o_dn;
00326                             org_ndn = op->o_ndn;
00327                             org_managedsait = get_manageDSAit( op );
00328                             op->o_dn = op->o_bd->be_rootdn;
00329                             op->o_ndn = op->o_bd->be_rootndn;
00330                             op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
00331 
00332                             while ( rs->sr_err == LDAP_SUCCESS &&
00333                                           op->o_delete_glue_parent ) {
00334                                    op->o_delete_glue_parent = 0;
00335                                    if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) {
00336                                           slap_callback cb = { NULL };
00337                                           cb.sc_response = slap_null_cb;
00338                                           dnParent( &op->o_req_ndn, &pdn );
00339                                           op->o_req_dn = pdn;
00340                                           op->o_req_ndn = pdn;
00341                                           op->o_callback = &cb;
00342                                           op->o_bd->be_delete( op, rs );
00343                                    } else {
00344                                           break;
00345                                    }
00346                             }
00347                             op->o_managedsait = org_managedsait;
00348                             op->o_dn = org_dn;
00349                             op->o_ndn = org_ndn;
00350                             op->o_req_dn = org_req_dn;
00351                             op->o_req_ndn = org_req_ndn;
00352                             op->o_delete_glue_parent = 0;
00353                      }
00354 
00355               } else {
00356                      BerVarray defref = op->o_bd->be_update_refs
00357                             ? op->o_bd->be_update_refs : default_referral;
00358 
00359                      if ( defref != NULL ) {
00360                             rs->sr_ref = referral_rewrite( defref,
00361                                    NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
00362                             if (!rs->sr_ref) rs->sr_ref = defref;
00363 
00364                             rs->sr_err = LDAP_REFERRAL;
00365                             send_ldap_result( op, rs );
00366 
00367                             if (rs->sr_ref != defref) ber_bvarray_free( rs->sr_ref );
00368                      } else {
00369                             send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
00370                                    "shadow context; no update referral" );
00371                      }
00372               }
00373        } else {
00374               send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
00375                      "operation not supported within namingContext" );
00376        }
00377 
00378 cleanup:;
00379        if ( dest_ndn.bv_val != NULL )
00380               ber_memfree_x( dest_ndn.bv_val, op->o_tmpmemctx );
00381        op->o_bd = bd;
00382        return rs->sr_err;
00383 }
00384 
00385 int
00386 slap_modrdn2mods(
00387        Operation     *op,
00388        SlapReply     *rs )
00389 {
00390        int           a_cnt, d_cnt;
00391        LDAPRDN              old_rdn = NULL;
00392        LDAPRDN              new_rdn = NULL;
00393 
00394        assert( !BER_BVISEMPTY( &op->oq_modrdn.rs_newrdn ) );
00395 
00396        /* if requestDN is empty, silently reset deleteOldRDN */
00397        if ( BER_BVISEMPTY( &op->o_req_dn ) ) op->orr_deleteoldrdn = 0;
00398 
00399        if ( ldap_bv2rdn_x( &op->oq_modrdn.rs_newrdn, &new_rdn,
00400               (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) {
00401               Debug( LDAP_DEBUG_TRACE,
00402                      "%s slap_modrdn2mods: can't figure out "
00403                      "type(s)/value(s) of newrdn\n",
00404                      op->o_log_prefix, 0, 0 );
00405               rs->sr_err = LDAP_INVALID_DN_SYNTAX;
00406               rs->sr_text = "unknown type(s)/value(s) used in RDN";
00407               goto done;
00408        }
00409 
00410        if ( op->oq_modrdn.rs_deleteoldrdn ) {
00411               if ( ldap_bv2rdn_x( &op->o_req_dn, &old_rdn,
00412                      (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) {
00413                      Debug( LDAP_DEBUG_TRACE,
00414                             "%s slap_modrdn2mods: can't figure out "
00415                             "type(s)/value(s) of oldrdn\n",
00416                             op->o_log_prefix, 0, 0 );
00417                      rs->sr_err = LDAP_OTHER;
00418                      rs->sr_text = "cannot parse RDN from old DN";
00419                      goto done;
00420               }
00421        }
00422        rs->sr_text = NULL;
00423 
00424        /* Add new attribute values to the entry */
00425        for ( a_cnt = 0; new_rdn[a_cnt]; a_cnt++ ) {
00426               AttributeDescription *desc = NULL;
00427               Modifications               *mod_tmp;
00428 
00429               rs->sr_err = slap_bv2ad( &new_rdn[a_cnt]->la_attr, &desc, &rs->sr_text );
00430 
00431               if ( rs->sr_err != LDAP_SUCCESS ) {
00432                      Debug( LDAP_DEBUG_TRACE,
00433                             "%s slap_modrdn2mods: %s: %s (new)\n",
00434                             op->o_log_prefix,
00435                             rs->sr_text, 
00436                             new_rdn[ a_cnt ]->la_attr.bv_val );
00437                      goto done;           
00438               }
00439 
00440               /* Apply modification */
00441               mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) );
00442               mod_tmp->sml_desc = desc;
00443               BER_BVZERO( &mod_tmp->sml_type );
00444               mod_tmp->sml_numvals = 1;
00445               mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
00446               ber_dupbv( &mod_tmp->sml_values[0], &new_rdn[a_cnt]->la_value );
00447               mod_tmp->sml_values[1].bv_val = NULL;
00448               if( desc->ad_type->sat_equality->smr_normalize) {
00449                      mod_tmp->sml_nvalues = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
00450                      rs->sr_err = desc->ad_type->sat_equality->smr_normalize(
00451                             SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
00452                             desc->ad_type->sat_syntax,
00453                             desc->ad_type->sat_equality,
00454                             &mod_tmp->sml_values[0],
00455                             &mod_tmp->sml_nvalues[0], NULL );
00456                      if (rs->sr_err != LDAP_SUCCESS) {
00457                             ch_free(mod_tmp->sml_nvalues);
00458                             ch_free(mod_tmp->sml_values[0].bv_val);
00459                             ch_free(mod_tmp->sml_values);
00460                             ch_free(mod_tmp);
00461                             goto done;
00462                      }
00463                      mod_tmp->sml_nvalues[1].bv_val = NULL;
00464               } else {
00465                      mod_tmp->sml_nvalues = NULL;
00466               }
00467               mod_tmp->sml_op = SLAP_MOD_SOFTADD;
00468               mod_tmp->sml_flags = 0;
00469               mod_tmp->sml_next = op->orr_modlist;
00470               op->orr_modlist = mod_tmp;
00471        }
00472 
00473        /* Remove old rdn value if required */
00474        if ( op->orr_deleteoldrdn ) {
00475               for ( d_cnt = 0; old_rdn[d_cnt]; d_cnt++ ) {
00476                      AttributeDescription *desc = NULL;
00477                      Modifications               *mod_tmp;
00478 
00479                      rs->sr_err = slap_bv2ad( &old_rdn[d_cnt]->la_attr, &desc, &rs->sr_text );
00480                      if ( rs->sr_err != LDAP_SUCCESS ) {
00481                             Debug( LDAP_DEBUG_TRACE,
00482                                    "%s slap_modrdn2mods: %s: %s (old)\n",
00483                                    op->o_log_prefix,
00484                                    rs->sr_text, 
00485                                    old_rdn[d_cnt]->la_attr.bv_val );
00486                             goto done;           
00487                      }
00488 
00489                      /* Apply modification */
00490                      mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) );
00491                      mod_tmp->sml_desc = desc;
00492                      BER_BVZERO( &mod_tmp->sml_type );
00493                      mod_tmp->sml_numvals = 1;
00494                      mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
00495                      ber_dupbv( &mod_tmp->sml_values[0], &old_rdn[d_cnt]->la_value );
00496                      mod_tmp->sml_values[1].bv_val = NULL;
00497                      if( desc->ad_type->sat_equality->smr_normalize) {
00498                             mod_tmp->sml_nvalues = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
00499                             (void) (*desc->ad_type->sat_equality->smr_normalize)(
00500                                    SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
00501                                    desc->ad_type->sat_syntax,
00502                                    desc->ad_type->sat_equality,
00503                                    &mod_tmp->sml_values[0],
00504                                    &mod_tmp->sml_nvalues[0], NULL );
00505                             mod_tmp->sml_nvalues[1].bv_val = NULL;
00506                      } else {
00507                             mod_tmp->sml_nvalues = NULL;
00508                      }
00509                      mod_tmp->sml_op = LDAP_MOD_DELETE;
00510                      mod_tmp->sml_flags = 0;
00511                      mod_tmp->sml_next = op->orr_modlist;
00512                      op->orr_modlist = mod_tmp;
00513               }
00514        }
00515        
00516 done:
00517 
00518        /* LDAP v2 supporting correct attribute handling. */
00519        if ( rs->sr_err != LDAP_SUCCESS && op->orr_modlist != NULL ) {
00520               Modifications *tmp;
00521 
00522               for ( ; op->orr_modlist != NULL; op->orr_modlist = tmp ) {
00523                      tmp = op->orr_modlist->sml_next;
00524                      ch_free( op->orr_modlist );
00525               }
00526        }
00527 
00528        if ( new_rdn != NULL ) {
00529               ldap_rdnfree_x( new_rdn, op->o_tmpmemctx );
00530        }
00531        if ( old_rdn != NULL ) {
00532               ldap_rdnfree_x( old_rdn, op->o_tmpmemctx );
00533        }
00534 
00535        return rs->sr_err;
00536 }
00537