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