1 /* $NetBSD: modrdn.c,v 1.1.1.1 2014/05/28 09:58:50 tron Exp $ */ 2 3 /* modrdn.c - mdb backend modrdn routine */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2000-2014 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 19 #include "portable.h" 20 21 #include <stdio.h> 22 #include <ac/string.h> 23 24 #include "back-mdb.h" 25 26 int 27 mdb_modrdn( Operation *op, SlapReply *rs ) 28 { 29 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 30 AttributeDescription *children = slap_schema.si_ad_children; 31 AttributeDescription *entry = slap_schema.si_ad_entry; 32 struct berval p_dn, p_ndn; 33 struct berval new_dn = {0, NULL}, new_ndn = {0, NULL}; 34 Entry *e = NULL; 35 Entry *p = NULL; 36 /* LDAP v2 supporting correct attribute handling. */ 37 char textbuf[SLAP_TEXT_BUFLEN]; 38 size_t textlen = sizeof textbuf; 39 MDB_txn *txn = NULL; 40 MDB_cursor *mc; 41 struct mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo; 42 Entry dummy = {0}; 43 44 Entry *np = NULL; /* newSuperior Entry */ 45 struct berval *np_dn = NULL; /* newSuperior dn */ 46 struct berval *np_ndn = NULL; /* newSuperior ndn */ 47 struct berval *new_parent_dn = NULL; /* np_dn, p_dn, or NULL */ 48 49 int manageDSAit = get_manageDSAit( op ); 50 51 ID nid, nsubs; 52 LDAPControl **preread_ctrl = NULL; 53 LDAPControl **postread_ctrl = NULL; 54 LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; 55 int num_ctrls = 0; 56 57 int parent_is_glue = 0; 58 int parent_is_leaf = 0; 59 60 #ifdef LDAP_X_TXN 61 int settle = 0; 62 #endif 63 64 Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(mdb_modrdn) "(%s,%s,%s)\n", 65 op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val, 66 op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" ); 67 68 #ifdef LDAP_X_TXN 69 if( op->o_txnSpec ) { 70 /* acquire connection lock */ 71 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 72 if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) { 73 rs->sr_text = "invalid transaction identifier"; 74 rs->sr_err = LDAP_X_TXN_ID_INVALID; 75 goto txnReturn; 76 } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) { 77 settle=1; 78 goto txnReturn; 79 } 80 81 if( op->o_conn->c_txn_backend == NULL ) { 82 op->o_conn->c_txn_backend = op->o_bd; 83 84 } else if( op->o_conn->c_txn_backend != op->o_bd ) { 85 rs->sr_text = "transaction cannot span multiple database contexts"; 86 rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS; 87 goto txnReturn; 88 } 89 90 /* insert operation into transaction */ 91 92 rs->sr_text = "transaction specified"; 93 rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY; 94 95 txnReturn: 96 /* release connection lock */ 97 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 98 99 if( !settle ) { 100 send_ldap_result( op, rs ); 101 return rs->sr_err; 102 } 103 } 104 #endif 105 106 ctrls[num_ctrls] = NULL; 107 108 /* begin transaction */ 109 rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi ); 110 rs->sr_text = NULL; 111 if( rs->sr_err != 0 ) { 112 Debug( LDAP_DEBUG_TRACE, 113 LDAP_XSTRING(mdb_modrdn) ": txn_begin failed: " 114 "%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 ); 115 rs->sr_err = LDAP_OTHER; 116 rs->sr_text = "internal error"; 117 goto return_results; 118 } 119 txn = moi->moi_txn; 120 121 slap_mods_opattrs( op, &op->orr_modlist, 1 ); 122 123 if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) { 124 #ifdef MDB_MULTIPLE_SUFFIXES 125 /* Allow renaming one suffix entry to another */ 126 p_ndn = slap_empty_bv; 127 #else 128 /* There can only be one suffix entry */ 129 rs->sr_err = LDAP_NAMING_VIOLATION; 130 rs->sr_text = "cannot rename suffix entry"; 131 goto return_results; 132 #endif 133 } else { 134 dnParent( &op->o_req_ndn, &p_ndn ); 135 } 136 np_ndn = &p_ndn; 137 /* Make sure parent entry exist and we can write its 138 * children. 139 */ 140 rs->sr_err = mdb_cursor_open( txn, mdb->mi_dn2id, &mc ); 141 if ( rs->sr_err != 0 ) { 142 Debug(LDAP_DEBUG_TRACE, 143 "<=- " LDAP_XSTRING(mdb_modrdn) 144 ": cursor_open failed: %s (%d)\n", 145 mdb_strerror(rs->sr_err), rs->sr_err, 0 ); 146 rs->sr_err = LDAP_OTHER; 147 rs->sr_text = "DN cursor_open failed"; 148 goto return_results; 149 } 150 rs->sr_err = mdb_dn2entry( op, txn, mc, &p_ndn, &p, NULL, 0 ); 151 switch( rs->sr_err ) { 152 case MDB_NOTFOUND: 153 Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn) 154 ": parent does not exist\n", 0, 0, 0); 155 rs->sr_ref = referral_rewrite( default_referral, NULL, 156 &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 157 rs->sr_err = LDAP_REFERRAL; 158 159 send_ldap_result( op, rs ); 160 161 ber_bvarray_free( rs->sr_ref ); 162 goto done; 163 case 0: 164 break; 165 case LDAP_BUSY: 166 rs->sr_text = "ldap server busy"; 167 goto return_results; 168 default: 169 rs->sr_err = LDAP_OTHER; 170 rs->sr_text = "internal error"; 171 goto return_results; 172 } 173 174 /* check parent for "children" acl */ 175 rs->sr_err = access_allowed( op, p, 176 children, NULL, 177 op->oq_modrdn.rs_newSup == NULL ? 178 ACL_WRITE : ACL_WDEL, 179 NULL ); 180 181 if ( ! rs->sr_err ) { 182 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 183 Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 184 0, 0 ); 185 rs->sr_text = "no write access to parent's children"; 186 goto return_results; 187 } 188 189 Debug( LDAP_DEBUG_TRACE, 190 LDAP_XSTRING(mdb_modrdn) ": wr to children " 191 "of entry %s OK\n", p_ndn.bv_val, 0, 0 ); 192 193 if ( p_ndn.bv_val == slap_empty_bv.bv_val ) { 194 p_dn = slap_empty_bv; 195 } else { 196 dnParent( &op->o_req_dn, &p_dn ); 197 } 198 199 Debug( LDAP_DEBUG_TRACE, 200 LDAP_XSTRING(mdb_modrdn) ": parent dn=%s\n", 201 p_dn.bv_val, 0, 0 ); 202 203 /* get entry */ 204 rs->sr_err = mdb_dn2entry( op, txn, mc, &op->o_req_ndn, &e, &nsubs, 0 ); 205 switch( rs->sr_err ) { 206 case MDB_NOTFOUND: 207 e = p; 208 p = NULL; 209 case 0: 210 break; 211 case LDAP_BUSY: 212 rs->sr_text = "ldap server busy"; 213 goto return_results; 214 default: 215 rs->sr_err = LDAP_OTHER; 216 rs->sr_text = "internal error"; 217 goto return_results; 218 } 219 220 /* FIXME: dn2entry() should return non-glue entry */ 221 if (( rs->sr_err == MDB_NOTFOUND ) || 222 ( !manageDSAit && e && is_entry_glue( e ))) 223 { 224 if( e != NULL ) { 225 rs->sr_matched = ch_strdup( e->e_dn ); 226 if ( is_entry_referral( e )) { 227 BerVarray ref = get_entry_referrals( op, e ); 228 rs->sr_ref = referral_rewrite( ref, &e->e_name, 229 &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 230 ber_bvarray_free( ref ); 231 } else { 232 rs->sr_ref = NULL; 233 } 234 mdb_entry_return( op, e ); 235 e = NULL; 236 237 } else { 238 rs->sr_ref = referral_rewrite( default_referral, NULL, 239 &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 240 } 241 242 rs->sr_err = LDAP_REFERRAL; 243 send_ldap_result( op, rs ); 244 245 ber_bvarray_free( rs->sr_ref ); 246 free( (char *)rs->sr_matched ); 247 rs->sr_ref = NULL; 248 rs->sr_matched = NULL; 249 250 goto done; 251 } 252 253 if ( get_assert( op ) && 254 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE )) 255 { 256 rs->sr_err = LDAP_ASSERTION_FAILED; 257 goto return_results; 258 } 259 260 /* check write on old entry */ 261 rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL ); 262 if ( ! rs->sr_err ) { 263 Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0, 264 0, 0 ); 265 rs->sr_text = "no write access to old entry"; 266 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 267 goto return_results; 268 } 269 270 if (!manageDSAit && is_entry_referral( e ) ) { 271 /* entry is a referral, don't allow rename */ 272 rs->sr_ref = get_entry_referrals( op, e ); 273 274 Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn) 275 ": entry %s is referral\n", e->e_dn, 0, 0 ); 276 277 rs->sr_err = LDAP_REFERRAL, 278 rs->sr_matched = e->e_name.bv_val; 279 send_ldap_result( op, rs ); 280 281 ber_bvarray_free( rs->sr_ref ); 282 rs->sr_ref = NULL; 283 rs->sr_matched = NULL; 284 goto done; 285 } 286 287 new_parent_dn = &p_dn; /* New Parent unless newSuperior given */ 288 289 if ( op->oq_modrdn.rs_newSup != NULL ) { 290 Debug( LDAP_DEBUG_TRACE, 291 LDAP_XSTRING(mdb_modrdn) 292 ": new parent \"%s\" requested...\n", 293 op->oq_modrdn.rs_newSup->bv_val, 0, 0 ); 294 295 /* newSuperior == oldParent? */ 296 if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) { 297 Debug( LDAP_DEBUG_TRACE, "mdb_back_modrdn: " 298 "new parent \"%s\" same as the old parent \"%s\"\n", 299 op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 ); 300 op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */ 301 } 302 } 303 304 /* There's a MDB_MULTIPLE_SUFFIXES case here that this code doesn't 305 * support. E.g., two suffixes dc=foo,dc=com and dc=bar,dc=net. 306 * We do not allow modDN 307 * dc=foo,dc=com 308 * newrdn dc=bar 309 * newsup dc=net 310 * and we probably should. But since MULTIPLE_SUFFIXES is deprecated 311 * I'm ignoring this problem for now. 312 */ 313 if ( op->oq_modrdn.rs_newSup != NULL ) { 314 if ( op->oq_modrdn.rs_newSup->bv_len ) { 315 np_dn = op->oq_modrdn.rs_newSup; 316 np_ndn = op->oq_modrdn.rs_nnewSup; 317 318 /* newSuperior == oldParent? - checked above */ 319 /* newSuperior == entry being moved?, if so ==> ERROR */ 320 if ( dnIsSuffix( np_ndn, &e->e_nname )) { 321 rs->sr_err = LDAP_NO_SUCH_OBJECT; 322 rs->sr_text = "new superior not found"; 323 goto return_results; 324 } 325 /* Get Entry with dn=newSuperior. Does newSuperior exist? */ 326 rs->sr_err = mdb_dn2entry( op, txn, NULL, np_ndn, &np, NULL, 0 ); 327 328 switch( rs->sr_err ) { 329 case 0: 330 break; 331 case MDB_NOTFOUND: 332 Debug( LDAP_DEBUG_TRACE, 333 LDAP_XSTRING(mdb_modrdn) 334 ": newSup(ndn=%s) not here!\n", 335 np_ndn->bv_val, 0, 0); 336 rs->sr_text = "new superior not found"; 337 rs->sr_err = LDAP_NO_SUCH_OBJECT; 338 goto return_results; 339 case LDAP_BUSY: 340 rs->sr_text = "ldap server busy"; 341 goto return_results; 342 default: 343 rs->sr_err = LDAP_OTHER; 344 rs->sr_text = "internal error"; 345 goto return_results; 346 } 347 348 /* check newSuperior for "children" acl */ 349 rs->sr_err = access_allowed( op, np, children, 350 NULL, ACL_WADD, NULL ); 351 352 if( ! rs->sr_err ) { 353 Debug( LDAP_DEBUG_TRACE, 354 LDAP_XSTRING(mdb_modrdn) 355 ": no wr to newSup children\n", 356 0, 0, 0 ); 357 rs->sr_text = "no write access to new superior's children"; 358 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 359 goto return_results; 360 } 361 362 Debug( LDAP_DEBUG_TRACE, 363 LDAP_XSTRING(mdb_modrdn) 364 ": wr to new parent OK np=%p, id=%ld\n", 365 (void *) np, (long) np->e_id, 0 ); 366 367 if ( is_entry_alias( np ) ) { 368 /* parent is an alias, don't allow add */ 369 Debug( LDAP_DEBUG_TRACE, 370 LDAP_XSTRING(mdb_modrdn) 371 ": entry is alias\n", 372 0, 0, 0 ); 373 rs->sr_text = "new superior is an alias"; 374 rs->sr_err = LDAP_ALIAS_PROBLEM; 375 goto return_results; 376 } 377 378 if ( is_entry_referral( np ) ) { 379 /* parent is a referral, don't allow add */ 380 Debug( LDAP_DEBUG_TRACE, 381 LDAP_XSTRING(mdb_modrdn) 382 ": entry is referral\n", 383 0, 0, 0 ); 384 rs->sr_text = "new superior is a referral"; 385 rs->sr_err = LDAP_OTHER; 386 goto return_results; 387 } 388 new_parent_dn = &np->e_name; 389 390 } else { 391 np_dn = NULL; 392 393 /* no parent, modrdn entry directly under root */ 394 if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv ) 395 || be_isupdate( op ) ) { 396 np = (Entry *)&slap_entry_root; 397 398 /* check parent for "children" acl */ 399 rs->sr_err = access_allowed( op, np, 400 children, NULL, ACL_WADD, NULL ); 401 402 np = NULL; 403 404 if ( ! rs->sr_err ) { 405 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 406 Debug( LDAP_DEBUG_TRACE, 407 "no access to new superior\n", 408 0, 0, 0 ); 409 rs->sr_text = 410 "no write access to new superior's children"; 411 goto return_results; 412 } 413 } 414 } 415 416 Debug( LDAP_DEBUG_TRACE, 417 LDAP_XSTRING(mdb_modrdn) 418 ": wr to new parent's children OK\n", 419 0, 0, 0 ); 420 421 new_parent_dn = np_dn; 422 } 423 424 /* Build target dn and make sure target entry doesn't exist already. */ 425 if (!new_dn.bv_val) { 426 build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn, op->o_tmpmemctx ); 427 } 428 429 if (!new_ndn.bv_val) { 430 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, op->o_tmpmemctx ); 431 } 432 433 Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn) ": new ndn=%s\n", 434 new_ndn.bv_val, 0, 0 ); 435 436 /* Shortcut the search */ 437 rs->sr_err = mdb_dn2id ( op, txn, NULL, &new_ndn, &nid, NULL, NULL, NULL ); 438 switch( rs->sr_err ) { 439 case MDB_NOTFOUND: 440 break; 441 case 0: 442 /* Allow rename to same DN */ 443 if ( nid == e->e_id ) 444 break; 445 rs->sr_err = LDAP_ALREADY_EXISTS; 446 goto return_results; 447 default: 448 rs->sr_err = LDAP_OTHER; 449 rs->sr_text = "internal error"; 450 goto return_results; 451 } 452 453 assert( op->orr_modlist != NULL ); 454 455 if( op->o_preread ) { 456 if( preread_ctrl == NULL ) { 457 preread_ctrl = &ctrls[num_ctrls++]; 458 ctrls[num_ctrls] = NULL; 459 } 460 if( slap_read_controls( op, rs, e, 461 &slap_pre_read_bv, preread_ctrl ) ) 462 { 463 Debug( LDAP_DEBUG_TRACE, 464 "<=- " LDAP_XSTRING(mdb_modrdn) 465 ": pre-read failed!\n", 0, 0, 0 ); 466 if ( op->o_preread & SLAP_CONTROL_CRITICAL ) { 467 /* FIXME: is it correct to abort 468 * operation if control fails? */ 469 goto return_results; 470 } 471 } 472 } 473 474 /* delete old DN 475 * If moving to a new parent, must delete current subtree count, 476 * otherwise leave it unchanged since we'll be adding it right back. 477 */ 478 rs->sr_err = mdb_dn2id_delete( op, mc, e->e_id, np ? nsubs : 0 ); 479 if ( rs->sr_err != 0 ) { 480 Debug(LDAP_DEBUG_TRACE, 481 "<=- " LDAP_XSTRING(mdb_modrdn) 482 ": dn2id del failed: %s (%d)\n", 483 mdb_strerror(rs->sr_err), rs->sr_err, 0 ); 484 rs->sr_err = LDAP_OTHER; 485 rs->sr_text = "DN index delete fail"; 486 goto return_results; 487 } 488 489 /* copy the entry, then override some fields */ 490 dummy = *e; 491 dummy.e_name = new_dn; 492 dummy.e_nname = new_ndn; 493 dummy.e_attrs = NULL; 494 495 /* add new DN */ 496 rs->sr_err = mdb_dn2id_add( op, mc, mc, np ? np->e_id : p->e_id, 497 nsubs, np != NULL, &dummy ); 498 if ( rs->sr_err != 0 ) { 499 Debug(LDAP_DEBUG_TRACE, 500 "<=- " LDAP_XSTRING(mdb_modrdn) 501 ": dn2id add failed: %s (%d)\n", 502 mdb_strerror(rs->sr_err), rs->sr_err, 0 ); 503 rs->sr_err = LDAP_OTHER; 504 rs->sr_text = "DN index add failed"; 505 goto return_results; 506 } 507 508 dummy.e_attrs = e->e_attrs; 509 510 /* modify entry */ 511 rs->sr_err = mdb_modify_internal( op, txn, op->orr_modlist, &dummy, 512 &rs->sr_text, textbuf, textlen ); 513 if( rs->sr_err != LDAP_SUCCESS ) { 514 Debug(LDAP_DEBUG_TRACE, 515 "<=- " LDAP_XSTRING(mdb_modrdn) 516 ": modify failed: %s (%d)\n", 517 mdb_strerror(rs->sr_err), rs->sr_err, 0 ); 518 if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; 519 goto return_results; 520 } 521 522 /* id2entry index */ 523 rs->sr_err = mdb_id2entry_update( op, txn, NULL, &dummy ); 524 if ( rs->sr_err != 0 ) { 525 Debug(LDAP_DEBUG_TRACE, 526 "<=- " LDAP_XSTRING(mdb_modrdn) 527 ": id2entry failed: %s (%d)\n", 528 mdb_strerror(rs->sr_err), rs->sr_err, 0 ); 529 rs->sr_err = LDAP_OTHER; 530 rs->sr_text = "entry update failed"; 531 goto return_results; 532 } 533 534 if ( p_ndn.bv_len != 0 ) { 535 if ((parent_is_glue = is_entry_glue(p))) { 536 rs->sr_err = mdb_dn2id_children( op, txn, p ); 537 if ( rs->sr_err != MDB_NOTFOUND ) { 538 switch( rs->sr_err ) { 539 case 0: 540 break; 541 default: 542 Debug(LDAP_DEBUG_ARGS, 543 "<=- " LDAP_XSTRING(mdb_modrdn) 544 ": has_children failed: %s (%d)\n", 545 mdb_strerror(rs->sr_err), rs->sr_err, 0 ); 546 rs->sr_err = LDAP_OTHER; 547 rs->sr_text = "internal error"; 548 goto return_results; 549 } 550 } else { 551 parent_is_leaf = 1; 552 } 553 } 554 mdb_entry_return( op, p ); 555 p = NULL; 556 } 557 558 if( op->o_postread ) { 559 if( postread_ctrl == NULL ) { 560 postread_ctrl = &ctrls[num_ctrls++]; 561 ctrls[num_ctrls] = NULL; 562 } 563 if( slap_read_controls( op, rs, &dummy, 564 &slap_post_read_bv, postread_ctrl ) ) 565 { 566 Debug( LDAP_DEBUG_TRACE, 567 "<=- " LDAP_XSTRING(mdb_modrdn) 568 ": post-read failed!\n", 0, 0, 0 ); 569 if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { 570 /* FIXME: is it correct to abort 571 * operation if control fails? */ 572 goto return_results; 573 } 574 } 575 } 576 577 if( moi == &opinfo ) { 578 LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next ); 579 opinfo.moi_oe.oe_key = NULL; 580 if( op->o_noop ) { 581 mdb_txn_abort( txn ); 582 rs->sr_err = LDAP_X_NO_OPERATION; 583 txn = NULL; 584 /* Only free attrs if they were dup'd. */ 585 if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; 586 goto return_results; 587 588 } else { 589 if(( rs->sr_err=mdb_txn_commit( txn )) != 0 ) { 590 rs->sr_text = "txn_commit failed"; 591 } else { 592 rs->sr_err = LDAP_SUCCESS; 593 } 594 txn = NULL; 595 } 596 } 597 598 if( rs->sr_err != LDAP_SUCCESS ) { 599 Debug( LDAP_DEBUG_ANY, 600 LDAP_XSTRING(mdb_modrdn) ": %s : %s (%d)\n", 601 rs->sr_text, mdb_strerror(rs->sr_err), rs->sr_err ); 602 rs->sr_err = LDAP_OTHER; 603 604 goto return_results; 605 } 606 607 Debug(LDAP_DEBUG_TRACE, 608 LDAP_XSTRING(mdb_modrdn) 609 ": rdn modified%s id=%08lx dn=\"%s\"\n", 610 op->o_noop ? " (no-op)" : "", 611 dummy.e_id, op->o_req_dn.bv_val ); 612 rs->sr_text = NULL; 613 if( num_ctrls ) rs->sr_ctrls = ctrls; 614 615 return_results: 616 if ( dummy.e_attrs ) { 617 attrs_free( dummy.e_attrs ); 618 } 619 send_ldap_result( op, rs ); 620 621 #if 0 622 if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) { 623 TXN_CHECKPOINT( mdb->bi_dbenv, 624 mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 ); 625 } 626 #endif 627 628 if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) { 629 op->o_delete_glue_parent = 1; 630 } 631 632 done: 633 slap_graduate_commit_csn( op ); 634 635 if( new_ndn.bv_val != NULL ) op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx ); 636 if( new_dn.bv_val != NULL ) op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx ); 637 638 /* LDAP v3 Support */ 639 if( np != NULL ) { 640 /* free new parent */ 641 mdb_entry_return( op, np ); 642 } 643 644 if( p != NULL ) { 645 /* free parent */ 646 mdb_entry_return( op, p ); 647 } 648 649 /* free entry */ 650 if( e != NULL ) { 651 mdb_entry_return( op, e ); 652 } 653 654 if( moi == &opinfo ) { 655 if( txn != NULL ) { 656 mdb_txn_abort( txn ); 657 } 658 if ( opinfo.moi_oe.oe_key ) { 659 LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next ); 660 } 661 } else { 662 moi->moi_ref--; 663 } 664 665 if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) { 666 slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); 667 slap_sl_free( *preread_ctrl, op->o_tmpmemctx ); 668 } 669 if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) { 670 slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); 671 slap_sl_free( *postread_ctrl, op->o_tmpmemctx ); 672 } 673 return rs->sr_err; 674 } 675