Back to index

openldap  2.4.31
modrdn.c
Go to the documentation of this file.
00001 /* modrdn.c - mdb backend modrdn routine */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2000-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 #include <ac/string.h>
00021 
00022 #include "back-mdb.h"
00023 
00024 int
00025 mdb_modrdn( Operation       *op, SlapReply *rs )
00026 {
00027        struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
00028        AttributeDescription *children = slap_schema.si_ad_children;
00029        AttributeDescription *entry = slap_schema.si_ad_entry;
00030        struct berval p_dn, p_ndn;
00031        struct berval new_dn = {0, NULL}, new_ndn = {0, NULL};
00032        Entry         *e = NULL;
00033        Entry         *p = NULL;
00034        /* LDAP v2 supporting correct attribute handling. */
00035        char textbuf[SLAP_TEXT_BUFLEN];
00036        size_t textlen = sizeof textbuf;
00037        MDB_txn              *txn = NULL;
00038        MDB_cursor    *mc;
00039        struct mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
00040        Entry dummy = {0};
00041 
00042        Entry         *np = NULL;                 /* newSuperior Entry */
00043        struct berval *np_dn = NULL;                     /* newSuperior dn */
00044        struct berval *np_ndn = NULL;                    /* newSuperior ndn */
00045        struct berval *new_parent_dn = NULL;      /* np_dn, p_dn, or NULL */
00046 
00047        int           manageDSAit = get_manageDSAit( op );
00048 
00049        ID nid;
00050        LDAPControl **preread_ctrl = NULL;
00051        LDAPControl **postread_ctrl = NULL;
00052        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
00053        int num_ctrls = 0;
00054 
00055        int parent_is_glue = 0;
00056        int parent_is_leaf = 0;
00057 
00058 #ifdef LDAP_X_TXN
00059        int settle = 0;
00060 #endif
00061 
00062        Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(mdb_modrdn) "(%s,%s,%s)\n",
00063               op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
00064               op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );
00065 
00066 #ifdef LDAP_X_TXN
00067        if( op->o_txnSpec ) {
00068               /* acquire connection lock */
00069               ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00070               if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
00071                      rs->sr_text = "invalid transaction identifier";
00072                      rs->sr_err = LDAP_X_TXN_ID_INVALID;
00073                      goto txnReturn;
00074               } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
00075                      settle=1;
00076                      goto txnReturn;
00077               }
00078 
00079               if( op->o_conn->c_txn_backend == NULL ) {
00080                      op->o_conn->c_txn_backend = op->o_bd;
00081 
00082               } else if( op->o_conn->c_txn_backend != op->o_bd ) {
00083                      rs->sr_text = "transaction cannot span multiple database contexts";
00084                      rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
00085                      goto txnReturn;
00086               }
00087 
00088               /* insert operation into transaction */
00089 
00090               rs->sr_text = "transaction specified";
00091               rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
00092 
00093 txnReturn:
00094               /* release connection lock */
00095               ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00096 
00097               if( !settle ) {
00098                      send_ldap_result( op, rs );
00099                      return rs->sr_err;
00100               }
00101        }
00102 #endif
00103 
00104        ctrls[num_ctrls] = NULL;
00105 
00106        slap_mods_opattrs( op, &op->orr_modlist, 1 );
00107 
00108        /* begin transaction */
00109        rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
00110        rs->sr_text = NULL;
00111        if( rs->sr_err != 0 ) {
00112               Debug( LDAP_DEBUG_TRACE,
00113                      LDAP_XSTRING(mdb_modrdn) ": txn_begin failed: "
00114                      "%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
00115               rs->sr_err = LDAP_OTHER;
00116               rs->sr_text = "internal error";
00117               goto return_results;
00118        }
00119 
00120        txn = moi->moi_txn;
00121 
00122        if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
00123 #ifdef MDB_MULTIPLE_SUFFIXES
00124               /* Allow renaming one suffix entry to another */
00125               p_ndn = slap_empty_bv;
00126 #else
00127               /* There can only be one suffix entry */
00128               rs->sr_err = LDAP_NAMING_VIOLATION;
00129               rs->sr_text = "cannot rename suffix entry";
00130               goto return_results;
00131 #endif
00132        } else {
00133               dnParent( &op->o_req_ndn, &p_ndn );
00134        }
00135        np_ndn = &p_ndn;
00136        /* Make sure parent entry exist and we can write its
00137         * children.
00138         */
00139        rs->sr_err = mdb_cursor_open( txn, mdb->mi_dn2id, &mc );
00140        if ( rs->sr_err != 0 ) {
00141               Debug(LDAP_DEBUG_TRACE,
00142                      "<=- " LDAP_XSTRING(mdb_modrdn)
00143                      ": cursor_open failed: %s (%d)\n",
00144                      mdb_strerror(rs->sr_err), rs->sr_err, 0 );
00145               rs->sr_err = LDAP_OTHER;
00146               rs->sr_text = "DN cursor_open failed";
00147               goto return_results;
00148        }
00149        rs->sr_err = mdb_dn2entry( op, txn, mc, &p_ndn, &p, 0 );
00150        switch( rs->sr_err ) {
00151        case MDB_NOTFOUND:
00152               Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn)
00153                      ": parent does not exist\n", 0, 0, 0);
00154               rs->sr_ref = referral_rewrite( default_referral, NULL,
00155                                    &op->o_req_dn, LDAP_SCOPE_DEFAULT );
00156               rs->sr_err = LDAP_REFERRAL;
00157 
00158               send_ldap_result( op, rs );
00159 
00160               ber_bvarray_free( rs->sr_ref );
00161               goto done;
00162        case 0:
00163               break;
00164        case LDAP_BUSY:
00165               rs->sr_text = "ldap server busy";
00166               goto return_results;
00167        default:
00168               rs->sr_err = LDAP_OTHER;
00169               rs->sr_text = "internal error";
00170               goto return_results;
00171        }
00172 
00173        /* check parent for "children" acl */
00174        rs->sr_err = access_allowed( op, p,
00175               children, NULL,
00176               op->oq_modrdn.rs_newSup == NULL ?
00177                      ACL_WRITE : ACL_WDEL,
00178               NULL );
00179 
00180        if ( ! rs->sr_err ) {
00181               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00182               Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
00183                      0, 0 );
00184               rs->sr_text = "no write access to parent's children";
00185               goto return_results;
00186        }
00187 
00188        Debug( LDAP_DEBUG_TRACE,
00189               LDAP_XSTRING(mdb_modrdn) ": wr to children "
00190               "of entry %s OK\n", p_ndn.bv_val, 0, 0 );
00191 
00192        if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
00193               p_dn = slap_empty_bv;
00194        } else {
00195               dnParent( &op->o_req_dn, &p_dn );
00196        }
00197 
00198        Debug( LDAP_DEBUG_TRACE,
00199               LDAP_XSTRING(mdb_modrdn) ": parent dn=%s\n",
00200               p_dn.bv_val, 0, 0 );
00201 
00202        /* get entry */
00203        rs->sr_err = mdb_dn2entry( op, txn, mc, &op->o_req_ndn, &e, 0 );
00204        switch( rs->sr_err ) {
00205        case MDB_NOTFOUND:
00206               e = p;
00207               p = NULL;
00208        case 0:
00209               break;
00210        case LDAP_BUSY:
00211               rs->sr_text = "ldap server busy";
00212               goto return_results;
00213        default:
00214               rs->sr_err = LDAP_OTHER;
00215               rs->sr_text = "internal error";
00216               goto return_results;
00217        }
00218 
00219        /* FIXME: dn2entry() should return non-glue entry */
00220        if (( rs->sr_err == MDB_NOTFOUND ) ||
00221               ( !manageDSAit && e && is_entry_glue( e )))
00222        {
00223               if( e != NULL ) {
00224                      rs->sr_matched = ch_strdup( e->e_dn );
00225                      if ( is_entry_referral( e )) {
00226                             BerVarray ref = get_entry_referrals( op, e );
00227                             rs->sr_ref = referral_rewrite( ref, &e->e_name,
00228                                    &op->o_req_dn, LDAP_SCOPE_DEFAULT );
00229                             ber_bvarray_free( ref );
00230                      } else {
00231                             rs->sr_ref = NULL;
00232                      }
00233                      mdb_entry_return( op, e );
00234                      e = NULL;
00235 
00236               } else {
00237                      rs->sr_ref = referral_rewrite( default_referral, NULL,
00238                                    &op->o_req_dn, LDAP_SCOPE_DEFAULT );
00239               }
00240 
00241               rs->sr_err = LDAP_REFERRAL;
00242               send_ldap_result( op, rs );
00243 
00244               ber_bvarray_free( rs->sr_ref );
00245               free( (char *)rs->sr_matched );
00246               rs->sr_ref = NULL;
00247               rs->sr_matched = NULL;
00248 
00249               goto done;
00250        }
00251 
00252        if ( get_assert( op ) &&
00253               ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
00254        {
00255               rs->sr_err = LDAP_ASSERTION_FAILED;
00256               goto return_results;
00257        }
00258 
00259        /* check write on old entry */
00260        rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL );
00261        if ( ! rs->sr_err ) {
00262               Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
00263                      0, 0 );
00264               rs->sr_text = "no write access to old entry";
00265               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00266               goto return_results;
00267        }
00268 
00269        if (!manageDSAit && is_entry_referral( e ) ) {
00270               /* entry is a referral, don't allow rename */
00271               rs->sr_ref = get_entry_referrals( op, e );
00272 
00273               Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn)
00274                      ": entry %s is referral\n", e->e_dn, 0, 0 );
00275 
00276               rs->sr_err = LDAP_REFERRAL,
00277               rs->sr_matched = e->e_name.bv_val;
00278               send_ldap_result( op, rs );
00279 
00280               ber_bvarray_free( rs->sr_ref );
00281               rs->sr_ref = NULL;
00282               rs->sr_matched = NULL;
00283               goto done;
00284        }
00285 
00286        new_parent_dn = &p_dn;      /* New Parent unless newSuperior given */
00287 
00288        if ( op->oq_modrdn.rs_newSup != NULL ) {
00289               Debug( LDAP_DEBUG_TRACE,
00290                      LDAP_XSTRING(mdb_modrdn)
00291                      ": new parent \"%s\" requested...\n",
00292                      op->oq_modrdn.rs_newSup->bv_val, 0, 0 );
00293 
00294               /*  newSuperior == oldParent? */
00295               if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) {
00296                      Debug( LDAP_DEBUG_TRACE, "mdb_back_modrdn: "
00297                             "new parent \"%s\" same as the old parent \"%s\"\n",
00298                             op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 );
00299                      op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */
00300               }
00301        }
00302 
00303        /* There's a MDB_MULTIPLE_SUFFIXES case here that this code doesn't
00304         * support. E.g., two suffixes dc=foo,dc=com and dc=bar,dc=net.
00305         * We do not allow modDN
00306         *   dc=foo,dc=com
00307         *    newrdn dc=bar
00308         *    newsup dc=net
00309         * and we probably should. But since MULTIPLE_SUFFIXES is deprecated
00310         * I'm ignoring this problem for now.
00311         */
00312        if ( op->oq_modrdn.rs_newSup != NULL ) {
00313               if ( op->oq_modrdn.rs_newSup->bv_len ) {
00314                      np_dn = op->oq_modrdn.rs_newSup;
00315                      np_ndn = op->oq_modrdn.rs_nnewSup;
00316 
00317                      /* newSuperior == oldParent? - checked above */
00318                      /* newSuperior == entry being moved?, if so ==> ERROR */
00319                      if ( dnIsSuffix( np_ndn, &e->e_nname )) {
00320                             rs->sr_err = LDAP_NO_SUCH_OBJECT;
00321                             rs->sr_text = "new superior not found";
00322                             goto return_results;
00323                      }
00324                      /* Get Entry with dn=newSuperior. Does newSuperior exist? */
00325                      rs->sr_err = mdb_dn2entry( op, txn, NULL, np_ndn, &np, 0 );
00326 
00327                      switch( rs->sr_err ) {
00328                      case 0:
00329                             break;
00330                      case MDB_NOTFOUND:
00331                             Debug( LDAP_DEBUG_TRACE,
00332                                    LDAP_XSTRING(mdb_modrdn)
00333                                    ": newSup(ndn=%s) not here!\n",
00334                                    np_ndn->bv_val, 0, 0);
00335                             rs->sr_text = "new superior not found";
00336                             rs->sr_err = LDAP_NO_SUCH_OBJECT;
00337                             goto return_results;
00338                      case LDAP_BUSY:
00339                             rs->sr_text = "ldap server busy";
00340                             goto return_results;
00341                      default:
00342                             rs->sr_err = LDAP_OTHER;
00343                             rs->sr_text = "internal error";
00344                             goto return_results;
00345                      }
00346 
00347                      /* check newSuperior for "children" acl */
00348                      rs->sr_err = access_allowed( op, np, children,
00349                             NULL, ACL_WADD, NULL );
00350 
00351                      if( ! rs->sr_err ) {
00352                             Debug( LDAP_DEBUG_TRACE,
00353                                    LDAP_XSTRING(mdb_modrdn)
00354                                    ": no wr to newSup children\n",
00355                                    0, 0, 0 );
00356                             rs->sr_text = "no write access to new superior's children";
00357                             rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00358                             goto return_results;
00359                      }
00360 
00361                      Debug( LDAP_DEBUG_TRACE,
00362                             LDAP_XSTRING(mdb_modrdn)
00363                             ": wr to new parent OK np=%p, id=%ld\n",
00364                             (void *) np, (long) np->e_id, 0 );
00365 
00366                      if ( is_entry_alias( np ) ) {
00367                             /* parent is an alias, don't allow add */
00368                             Debug( LDAP_DEBUG_TRACE,
00369                                    LDAP_XSTRING(mdb_modrdn)
00370                                    ": entry is alias\n",
00371                                    0, 0, 0 );
00372                             rs->sr_text = "new superior is an alias";
00373                             rs->sr_err = LDAP_ALIAS_PROBLEM;
00374                             goto return_results;
00375                      }
00376 
00377                      if ( is_entry_referral( np ) ) {
00378                             /* parent is a referral, don't allow add */
00379                             Debug( LDAP_DEBUG_TRACE,
00380                                    LDAP_XSTRING(mdb_modrdn)
00381                                    ": entry is referral\n",
00382                                    0, 0, 0 );
00383                             rs->sr_text = "new superior is a referral";
00384                             rs->sr_err = LDAP_OTHER;
00385                             goto return_results;
00386                      }
00387                      new_parent_dn = &np->e_name;
00388 
00389               } else {
00390                      np_dn = NULL;
00391 
00392                      /* no parent, modrdn entry directly under root */
00393                      if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
00394                             || be_isupdate( op ) ) {
00395                             np = (Entry *)&slap_entry_root;
00396 
00397                             /* check parent for "children" acl */
00398                             rs->sr_err = access_allowed( op, np,
00399                                    children, NULL, ACL_WADD, NULL );
00400 
00401                             np = NULL;
00402 
00403                             if ( ! rs->sr_err ) {
00404                                    rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00405                                    Debug( LDAP_DEBUG_TRACE,
00406                                           "no access to new superior\n",
00407                                           0, 0, 0 );
00408                                    rs->sr_text =
00409                                           "no write access to new superior's children";
00410                                    goto return_results;
00411                             }
00412                      }
00413               }
00414 
00415               Debug( LDAP_DEBUG_TRACE,
00416                      LDAP_XSTRING(mdb_modrdn)
00417                      ": wr to new parent's children OK\n",
00418                      0, 0, 0 );
00419 
00420               new_parent_dn = np_dn;
00421        }
00422 
00423        /* Build target dn and make sure target entry doesn't exist already. */
00424        if (!new_dn.bv_val) {
00425               build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn, op->o_tmpmemctx );
00426        }
00427 
00428        if (!new_ndn.bv_val) {
00429               dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, op->o_tmpmemctx );
00430        }
00431 
00432        Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn) ": new ndn=%s\n",
00433               new_ndn.bv_val, 0, 0 );
00434 
00435        /* Shortcut the search */
00436        rs->sr_err = mdb_dn2id ( op, txn, NULL, &new_ndn, &nid, NULL, NULL );
00437        switch( rs->sr_err ) {
00438        case MDB_NOTFOUND:
00439               break;
00440        case 0:
00441               /* Allow rename to same DN */
00442               if ( nid == e->e_id )
00443                      break;
00444               rs->sr_err = LDAP_ALREADY_EXISTS;
00445               goto return_results;
00446        default:
00447               rs->sr_err = LDAP_OTHER;
00448               rs->sr_text = "internal error";
00449               goto return_results;
00450        }
00451 
00452        assert( op->orr_modlist != NULL );
00453 
00454        if( op->o_preread ) {
00455               if( preread_ctrl == NULL ) {
00456                      preread_ctrl = &ctrls[num_ctrls++];
00457                      ctrls[num_ctrls] = NULL;
00458               }
00459               if( slap_read_controls( op, rs, e,
00460                      &slap_pre_read_bv, preread_ctrl ) )
00461               {
00462                      Debug( LDAP_DEBUG_TRACE,
00463                             "<=- " LDAP_XSTRING(mdb_modrdn)
00464                             ": pre-read failed!\n", 0, 0, 0 );
00465                      if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
00466                             /* FIXME: is it correct to abort
00467                              * operation if control fails? */
00468                             goto return_results;
00469                      }
00470               }
00471        }
00472 
00473        /* delete old DN */
00474        rs->sr_err = mdb_dn2id_delete( op, mc, e->e_id );
00475        if ( rs->sr_err != 0 ) {
00476               Debug(LDAP_DEBUG_TRACE,
00477                      "<=- " LDAP_XSTRING(mdb_modrdn)
00478                      ": dn2id del failed: %s (%d)\n",
00479                      mdb_strerror(rs->sr_err), rs->sr_err, 0 );
00480               rs->sr_err = LDAP_OTHER;
00481               rs->sr_text = "DN index delete fail";
00482               goto return_results;
00483        }
00484 
00485        /* copy the entry, then override some fields */
00486        dummy = *e;
00487        dummy.e_name = new_dn;
00488        dummy.e_nname = new_ndn;
00489        dummy.e_attrs = NULL;
00490 
00491        /* add new DN */
00492        rs->sr_err = mdb_dn2id_add( op, mc, mc, np ? np->e_id : p->e_id, &dummy );
00493        if ( rs->sr_err != 0 ) {
00494               Debug(LDAP_DEBUG_TRACE,
00495                      "<=- " LDAP_XSTRING(mdb_modrdn)
00496                      ": dn2id add failed: %s (%d)\n",
00497                      mdb_strerror(rs->sr_err), rs->sr_err, 0 );
00498               rs->sr_err = LDAP_OTHER;
00499               rs->sr_text = "DN index add failed";
00500               goto return_results;
00501        }
00502 
00503        dummy.e_attrs = e->e_attrs;
00504 
00505        /* modify entry */
00506        rs->sr_err = mdb_modify_internal( op, txn, op->orr_modlist, &dummy,
00507               &rs->sr_text, textbuf, textlen );
00508        if( rs->sr_err != LDAP_SUCCESS ) {
00509               Debug(LDAP_DEBUG_TRACE,
00510                      "<=- " LDAP_XSTRING(mdb_modrdn)
00511                      ": modify failed: %s (%d)\n",
00512                      mdb_strerror(rs->sr_err), rs->sr_err, 0 );
00513               if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
00514               goto return_results;
00515        }
00516 
00517        /* id2entry index */
00518        rs->sr_err = mdb_id2entry_update( op, txn, NULL, &dummy );
00519        if ( rs->sr_err != 0 ) {
00520               Debug(LDAP_DEBUG_TRACE,
00521                      "<=- " LDAP_XSTRING(mdb_modrdn)
00522                      ": id2entry failed: %s (%d)\n",
00523                      mdb_strerror(rs->sr_err), rs->sr_err, 0 );
00524               rs->sr_err = LDAP_OTHER;
00525               rs->sr_text = "entry update failed";
00526               goto return_results;
00527        }
00528 
00529        if ( p_ndn.bv_len != 0 ) {
00530               parent_is_glue = is_entry_glue(p);
00531               rs->sr_err = mdb_dn2id_children( op, txn, p );
00532               if ( rs->sr_err != MDB_NOTFOUND ) {
00533                      switch( rs->sr_err ) {
00534                      case 0:
00535                             break;
00536                      default:
00537                             Debug(LDAP_DEBUG_ARGS,
00538                                    "<=- " LDAP_XSTRING(mdb_modrdn)
00539                                    ": has_children failed: %s (%d)\n",
00540                                    mdb_strerror(rs->sr_err), rs->sr_err, 0 );
00541                             rs->sr_err = LDAP_OTHER;
00542                             rs->sr_text = "internal error";
00543                             goto return_results;
00544                      }
00545               } else {
00546                      parent_is_leaf = 1;
00547               }
00548               mdb_entry_return( op, p );
00549               p = NULL;
00550        }
00551 
00552        if( op->o_postread ) {
00553               if( postread_ctrl == NULL ) {
00554                      postread_ctrl = &ctrls[num_ctrls++];
00555                      ctrls[num_ctrls] = NULL;
00556               }
00557               if( slap_read_controls( op, rs, &dummy,
00558                      &slap_post_read_bv, postread_ctrl ) )
00559               {
00560                      Debug( LDAP_DEBUG_TRACE,
00561                             "<=- " LDAP_XSTRING(mdb_modrdn)
00562                             ": post-read failed!\n", 0, 0, 0 );
00563                      if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
00564                             /* FIXME: is it correct to abort
00565                              * operation if control fails? */
00566                             goto return_results;
00567                      }
00568               }
00569        }
00570 
00571        if( moi == &opinfo ) {
00572               LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
00573               opinfo.moi_oe.oe_key = NULL;
00574               if( op->o_noop ) {
00575                      mdb_txn_abort( txn );
00576                      rs->sr_err = LDAP_X_NO_OPERATION;
00577                      txn = NULL;
00578                      /* Only free attrs if they were dup'd.  */
00579                      if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
00580                      goto return_results;
00581 
00582               } else {
00583                      if(( rs->sr_err=mdb_txn_commit( txn )) != 0 ) {
00584                             rs->sr_text = "txn_commit failed";
00585                      } else {
00586                             rs->sr_err = LDAP_SUCCESS;
00587                      }
00588                      txn = NULL;
00589               }
00590        }
00591 
00592        if( rs->sr_err != LDAP_SUCCESS ) {
00593               Debug( LDAP_DEBUG_TRACE,
00594                      LDAP_XSTRING(mdb_modrdn) ": %s : %s (%d)\n",
00595                      rs->sr_text, mdb_strerror(rs->sr_err), rs->sr_err );
00596               rs->sr_err = LDAP_OTHER;
00597 
00598               goto return_results;
00599        }
00600 
00601        Debug(LDAP_DEBUG_TRACE,
00602               LDAP_XSTRING(mdb_modrdn)
00603               ": rdn modified%s id=%08lx dn=\"%s\"\n",
00604               op->o_noop ? " (no-op)" : "",
00605               dummy.e_id, op->o_req_dn.bv_val );
00606        rs->sr_text = NULL;
00607        if( num_ctrls ) rs->sr_ctrls = ctrls;
00608 
00609 return_results:
00610        if ( dummy.e_attrs ) {
00611               attrs_free( dummy.e_attrs );
00612        }
00613        send_ldap_result( op, rs );
00614 
00615 #if 0
00616        if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) {
00617               TXN_CHECKPOINT( mdb->bi_dbenv,
00618                      mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
00619        }
00620 #endif
00621 
00622        if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
00623               op->o_delete_glue_parent = 1;
00624        }
00625 
00626 done:
00627        slap_graduate_commit_csn( op );
00628 
00629        if( new_ndn.bv_val != NULL ) op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
00630        if( new_dn.bv_val != NULL ) op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
00631 
00632        /* LDAP v3 Support */
00633        if( np != NULL ) {
00634               /* free new parent */
00635               mdb_entry_return( op, np );
00636        }
00637 
00638        if( p != NULL ) {
00639               /* free parent */
00640               mdb_entry_return( op, p );
00641        }
00642 
00643        /* free entry */
00644        if( e != NULL ) {
00645               mdb_entry_return( op, e );
00646        }
00647 
00648        if( moi == &opinfo ) {
00649               if( txn != NULL ) {
00650                      mdb_txn_abort( txn );
00651               }
00652               if ( opinfo.moi_oe.oe_key ) {
00653                      LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
00654               }
00655        }
00656 
00657        if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
00658               slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
00659               slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
00660        }
00661        if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
00662               slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
00663               slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
00664        }
00665        return rs->sr_err;
00666 }