1 /* $NetBSD: modify.c,v 1.1.1.3 2018/02/06 01:53:17 christos Exp $ */ 2 3 /* modify.c - mdb backend modify routine */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2000-2017 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: modify.c,v 1.1.1.3 2018/02/06 01:53:17 christos Exp $"); 21 22 #include "portable.h" 23 24 #include <stdio.h> 25 #include <ac/string.h> 26 #include <ac/time.h> 27 28 #include "back-mdb.h" 29 30 static struct berval scbva[] = { 31 BER_BVC("glue"), 32 BER_BVNULL 33 }; 34 35 static void 36 mdb_modify_idxflags( 37 Operation *op, 38 AttributeDescription *desc, 39 int got_delete, 40 Attribute *newattrs, 41 Attribute *oldattrs ) 42 { 43 struct berval ix_at; 44 AttrInfo *ai; 45 46 /* check if modified attribute was indexed 47 * but not in case of NOOP... */ 48 ai = mdb_index_mask( op->o_bd, desc, &ix_at ); 49 if ( ai ) { 50 if ( got_delete ) { 51 Attribute *ap; 52 struct berval ix2; 53 54 ap = attr_find( oldattrs, desc ); 55 if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL; 56 57 /* Find all other attrs that index to same slot */ 58 for ( ap = newattrs; ap; ap = ap->a_next ) { 59 ai = mdb_index_mask( op->o_bd, ap->a_desc, &ix2 ); 60 if ( ai && ix2.bv_val == ix_at.bv_val ) 61 ap->a_flags |= SLAP_ATTR_IXADD; 62 } 63 64 } else { 65 Attribute *ap; 66 67 ap = attr_find( newattrs, desc ); 68 if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD; 69 } 70 } 71 } 72 73 int mdb_modify_internal( 74 Operation *op, 75 MDB_txn *tid, 76 Modifications *modlist, 77 Entry *e, 78 const char **text, 79 char *textbuf, 80 size_t textlen ) 81 { 82 int rc, err; 83 Modification *mod; 84 Modifications *ml; 85 Attribute *save_attrs; 86 Attribute *ap; 87 int glue_attr_delete = 0; 88 int got_delete; 89 90 Debug( LDAP_DEBUG_TRACE, "mdb_modify_internal: 0x%08lx: %s\n", 91 e->e_id, e->e_dn, 0); 92 93 if ( !acl_check_modlist( op, e, modlist )) { 94 return LDAP_INSUFFICIENT_ACCESS; 95 } 96 97 /* save_attrs will be disposed of by caller */ 98 save_attrs = e->e_attrs; 99 e->e_attrs = attrs_dup( e->e_attrs ); 100 101 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { 102 int match; 103 mod = &ml->sml_mod; 104 switch( mod->sm_op ) { 105 case LDAP_MOD_ADD: 106 case LDAP_MOD_REPLACE: 107 if ( mod->sm_desc == slap_schema.si_ad_structuralObjectClass ) { 108 value_match( &match, slap_schema.si_ad_structuralObjectClass, 109 slap_schema.si_ad_structuralObjectClass-> 110 ad_type->sat_equality, 111 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 112 &mod->sm_values[0], &scbva[0], text ); 113 if ( !match ) glue_attr_delete = 1; 114 } 115 } 116 if ( glue_attr_delete ) 117 break; 118 } 119 120 if ( glue_attr_delete ) { 121 Attribute **app = &e->e_attrs; 122 while ( *app != NULL ) { 123 if ( !is_at_operational( (*app)->a_desc->ad_type )) { 124 Attribute *save = *app; 125 *app = (*app)->a_next; 126 attr_free( save ); 127 continue; 128 } 129 app = &(*app)->a_next; 130 } 131 } 132 133 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { 134 mod = &ml->sml_mod; 135 got_delete = 0; 136 137 switch ( mod->sm_op ) { 138 case LDAP_MOD_ADD: 139 Debug(LDAP_DEBUG_ARGS, 140 "mdb_modify_internal: add %s\n", 141 mod->sm_desc->ad_cname.bv_val, 0, 0); 142 err = modify_add_values( e, mod, get_permissiveModify(op), 143 text, textbuf, textlen ); 144 if( err != LDAP_SUCCESS ) { 145 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 146 err, *text, 0); 147 } 148 break; 149 150 case LDAP_MOD_DELETE: 151 if ( glue_attr_delete ) { 152 err = LDAP_SUCCESS; 153 break; 154 } 155 156 Debug(LDAP_DEBUG_ARGS, 157 "mdb_modify_internal: delete %s\n", 158 mod->sm_desc->ad_cname.bv_val, 0, 0); 159 err = modify_delete_values( e, mod, get_permissiveModify(op), 160 text, textbuf, textlen ); 161 if( err != LDAP_SUCCESS ) { 162 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 163 err, *text, 0); 164 } else { 165 got_delete = 1; 166 } 167 break; 168 169 case LDAP_MOD_REPLACE: 170 Debug(LDAP_DEBUG_ARGS, 171 "mdb_modify_internal: replace %s\n", 172 mod->sm_desc->ad_cname.bv_val, 0, 0); 173 err = modify_replace_values( e, mod, get_permissiveModify(op), 174 text, textbuf, textlen ); 175 if( err != LDAP_SUCCESS ) { 176 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 177 err, *text, 0); 178 } else { 179 got_delete = 1; 180 } 181 break; 182 183 case LDAP_MOD_INCREMENT: 184 Debug(LDAP_DEBUG_ARGS, 185 "mdb_modify_internal: increment %s\n", 186 mod->sm_desc->ad_cname.bv_val, 0, 0); 187 err = modify_increment_values( e, mod, get_permissiveModify(op), 188 text, textbuf, textlen ); 189 if( err != LDAP_SUCCESS ) { 190 Debug(LDAP_DEBUG_ARGS, 191 "mdb_modify_internal: %d %s\n", 192 err, *text, 0); 193 } else { 194 got_delete = 1; 195 } 196 break; 197 198 case SLAP_MOD_SOFTADD: 199 Debug(LDAP_DEBUG_ARGS, 200 "mdb_modify_internal: softadd %s\n", 201 mod->sm_desc->ad_cname.bv_val, 0, 0); 202 /* Avoid problems in index_add_mods() 203 * We need to add index if necessary. 204 */ 205 mod->sm_op = LDAP_MOD_ADD; 206 207 err = modify_add_values( e, mod, get_permissiveModify(op), 208 text, textbuf, textlen ); 209 210 mod->sm_op = SLAP_MOD_SOFTADD; 211 212 if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) { 213 err = LDAP_SUCCESS; 214 } 215 216 if( err != LDAP_SUCCESS ) { 217 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 218 err, *text, 0); 219 } 220 break; 221 222 case SLAP_MOD_SOFTDEL: 223 Debug(LDAP_DEBUG_ARGS, 224 "mdb_modify_internal: softdel %s\n", 225 mod->sm_desc->ad_cname.bv_val, 0, 0); 226 /* Avoid problems in index_delete_mods() 227 * We need to add index if necessary. 228 */ 229 mod->sm_op = LDAP_MOD_DELETE; 230 231 err = modify_delete_values( e, mod, get_permissiveModify(op), 232 text, textbuf, textlen ); 233 234 mod->sm_op = SLAP_MOD_SOFTDEL; 235 236 if ( err == LDAP_SUCCESS ) { 237 got_delete = 1; 238 } else if ( err == LDAP_NO_SUCH_ATTRIBUTE ) { 239 err = LDAP_SUCCESS; 240 } 241 242 if( err != LDAP_SUCCESS ) { 243 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 244 err, *text, 0); 245 } 246 break; 247 248 case SLAP_MOD_ADD_IF_NOT_PRESENT: 249 if ( attr_find( e->e_attrs, mod->sm_desc ) != NULL ) { 250 /* skip */ 251 err = LDAP_SUCCESS; 252 break; 253 } 254 255 Debug(LDAP_DEBUG_ARGS, 256 "mdb_modify_internal: add_if_not_present %s\n", 257 mod->sm_desc->ad_cname.bv_val, 0, 0); 258 /* Avoid problems in index_add_mods() 259 * We need to add index if necessary. 260 */ 261 mod->sm_op = LDAP_MOD_ADD; 262 263 err = modify_add_values( e, mod, get_permissiveModify(op), 264 text, textbuf, textlen ); 265 266 mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT; 267 268 if( err != LDAP_SUCCESS ) { 269 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 270 err, *text, 0); 271 } 272 break; 273 274 default: 275 Debug(LDAP_DEBUG_ANY, "mdb_modify_internal: invalid op %d\n", 276 mod->sm_op, 0, 0); 277 *text = "Invalid modify operation"; 278 err = LDAP_OTHER; 279 Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", 280 err, *text, 0); 281 } 282 283 if ( err != LDAP_SUCCESS ) { 284 attrs_free( e->e_attrs ); 285 e->e_attrs = save_attrs; 286 /* unlock entry, delete from cache */ 287 return err; 288 } 289 290 /* If objectClass was modified, reset the flags */ 291 if ( mod->sm_desc == slap_schema.si_ad_objectClass ) { 292 e->e_ocflags = 0; 293 } 294 295 if ( glue_attr_delete ) e->e_ocflags = 0; 296 297 298 /* check if modified attribute was indexed 299 * but not in case of NOOP... */ 300 if ( !op->o_noop ) { 301 mdb_modify_idxflags( op, mod->sm_desc, got_delete, e->e_attrs, save_attrs ); 302 } 303 } 304 305 /* check that the entry still obeys the schema */ 306 ap = NULL; 307 rc = entry_schema_check( op, e, save_attrs, get_relax(op), 0, &ap, 308 text, textbuf, textlen ); 309 if ( rc != LDAP_SUCCESS || op->o_noop ) { 310 attrs_free( e->e_attrs ); 311 /* clear the indexing flags */ 312 for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) { 313 ap->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL); 314 } 315 e->e_attrs = save_attrs; 316 317 if ( rc != LDAP_SUCCESS ) { 318 Debug( LDAP_DEBUG_ANY, 319 "entry failed schema check: %s\n", 320 *text, 0, 0 ); 321 } 322 323 /* if NOOP then silently revert to saved attrs */ 324 return rc; 325 } 326 327 /* structuralObjectClass modified! */ 328 if ( ap ) { 329 assert( ap->a_desc == slap_schema.si_ad_structuralObjectClass ); 330 if ( !op->o_noop ) { 331 mdb_modify_idxflags( op, slap_schema.si_ad_structuralObjectClass, 332 1, e->e_attrs, save_attrs ); 333 } 334 } 335 336 /* update the indices of the modified attributes */ 337 338 /* start with deleting the old index entries */ 339 for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) { 340 if ( ap->a_flags & SLAP_ATTR_IXDEL ) { 341 struct berval *vals; 342 Attribute *a2; 343 ap->a_flags &= ~SLAP_ATTR_IXDEL; 344 a2 = attr_find( e->e_attrs, ap->a_desc ); 345 if ( a2 ) { 346 /* need to detect which values were deleted */ 347 int i, j; 348 /* let add know there were deletes */ 349 if ( a2->a_flags & SLAP_ATTR_IXADD ) 350 a2->a_flags |= SLAP_ATTR_IXDEL; 351 vals = op->o_tmpalloc( (ap->a_numvals + 1) * 352 sizeof(struct berval), op->o_tmpmemctx ); 353 j = 0; 354 for ( i=0; i < ap->a_numvals; i++ ) { 355 rc = attr_valfind( a2, SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 356 &ap->a_nvals[i], NULL, op->o_tmpmemctx ); 357 /* Save deleted values */ 358 if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) 359 vals[j++] = ap->a_nvals[i]; 360 } 361 BER_BVZERO(vals+j); 362 } else { 363 /* attribute was completely deleted */ 364 vals = ap->a_nvals; 365 } 366 rc = 0; 367 if ( !BER_BVISNULL( vals )) { 368 rc = mdb_index_values( op, tid, ap->a_desc, 369 vals, e->e_id, SLAP_INDEX_DELETE_OP ); 370 if ( rc != LDAP_SUCCESS ) { 371 Debug( LDAP_DEBUG_ANY, 372 "%s: attribute \"%s\" index delete failure\n", 373 op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 ); 374 attrs_free( e->e_attrs ); 375 e->e_attrs = save_attrs; 376 } 377 } 378 if ( vals != ap->a_nvals ) 379 op->o_tmpfree( vals, op->o_tmpmemctx ); 380 if ( rc ) return rc; 381 } 382 } 383 384 /* add the new index entries */ 385 for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) { 386 if (ap->a_flags & SLAP_ATTR_IXADD) { 387 ap->a_flags &= ~SLAP_ATTR_IXADD; 388 if ( ap->a_flags & SLAP_ATTR_IXDEL ) { 389 /* if any values were deleted, we must readd index 390 * for all remaining values. 391 */ 392 ap->a_flags &= ~SLAP_ATTR_IXDEL; 393 rc = mdb_index_values( op, tid, ap->a_desc, 394 ap->a_nvals, 395 e->e_id, SLAP_INDEX_ADD_OP ); 396 } else { 397 int found = 0; 398 /* if this was only an add, we only need to index 399 * the added values. 400 */ 401 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { 402 struct berval *vals; 403 if ( ml->sml_desc != ap->a_desc || !ml->sml_numvals ) 404 continue; 405 found = 1; 406 switch( ml->sml_op ) { 407 case LDAP_MOD_ADD: 408 case LDAP_MOD_REPLACE: 409 case LDAP_MOD_INCREMENT: 410 case SLAP_MOD_SOFTADD: 411 case SLAP_MOD_ADD_IF_NOT_PRESENT: 412 if ( ml->sml_op == LDAP_MOD_INCREMENT ) 413 vals = ap->a_nvals; 414 else if ( ml->sml_nvalues ) 415 vals = ml->sml_nvalues; 416 else 417 vals = ml->sml_values; 418 rc = mdb_index_values( op, tid, ap->a_desc, 419 vals, e->e_id, SLAP_INDEX_ADD_OP ); 420 break; 421 } 422 if ( rc ) 423 break; 424 } 425 /* This attr was affected by a modify of a subtype, so 426 * there was no direct match in the modlist. Just readd 427 * all of its values. 428 */ 429 if ( !found ) { 430 rc = mdb_index_values( op, tid, ap->a_desc, 431 ap->a_nvals, 432 e->e_id, SLAP_INDEX_ADD_OP ); 433 } 434 } 435 if ( rc != LDAP_SUCCESS ) { 436 Debug( LDAP_DEBUG_ANY, 437 "%s: attribute \"%s\" index add failure\n", 438 op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 ); 439 attrs_free( e->e_attrs ); 440 e->e_attrs = save_attrs; 441 return rc; 442 } 443 } 444 } 445 446 return rc; 447 } 448 449 450 int 451 mdb_modify( Operation *op, SlapReply *rs ) 452 { 453 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; 454 Entry *e = NULL; 455 int manageDSAit = get_manageDSAit( op ); 456 char textbuf[SLAP_TEXT_BUFLEN]; 457 size_t textlen = sizeof textbuf; 458 MDB_txn *txn = NULL; 459 mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo; 460 Entry dummy = {0}; 461 462 LDAPControl **preread_ctrl = NULL; 463 LDAPControl **postread_ctrl = NULL; 464 LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; 465 int num_ctrls = 0; 466 int numads = mdb->mi_numads; 467 468 #ifdef LDAP_X_TXN 469 int settle = 0; 470 #endif 471 472 Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(mdb_modify) ": %s\n", 473 op->o_req_dn.bv_val, 0, 0 ); 474 475 #ifdef LDAP_X_TXN 476 if( op->o_txnSpec ) { 477 /* acquire connection lock */ 478 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 479 if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) { 480 rs->sr_text = "invalid transaction identifier"; 481 rs->sr_err = LDAP_X_TXN_ID_INVALID; 482 goto txnReturn; 483 } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) { 484 settle=1; 485 goto txnReturn; 486 } 487 488 if( op->o_conn->c_txn_backend == NULL ) { 489 op->o_conn->c_txn_backend = op->o_bd; 490 491 } else if( op->o_conn->c_txn_backend != op->o_bd ) { 492 rs->sr_text = "transaction cannot span multiple database contexts"; 493 rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS; 494 goto txnReturn; 495 } 496 497 /* insert operation into transaction */ 498 499 rs->sr_text = "transaction specified"; 500 rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY; 501 502 txnReturn: 503 /* release connection lock */ 504 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 505 506 if( !settle ) { 507 send_ldap_result( op, rs ); 508 return rs->sr_err; 509 } 510 } 511 #endif 512 513 ctrls[num_ctrls] = NULL; 514 515 /* begin transaction */ 516 rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi ); 517 rs->sr_text = NULL; 518 if( rs->sr_err != 0 ) { 519 Debug( LDAP_DEBUG_TRACE, 520 LDAP_XSTRING(mdb_modify) ": txn_begin failed: " 521 "%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 ); 522 rs->sr_err = LDAP_OTHER; 523 rs->sr_text = "internal error"; 524 goto return_results; 525 } 526 txn = moi->moi_txn; 527 528 /* Don't touch the opattrs, if this is a contextCSN update 529 * initiated from updatedn */ 530 if ( !be_isupdate(op) || !op->orm_modlist || op->orm_modlist->sml_next || 531 op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) { 532 533 slap_mods_opattrs( op, &op->orm_modlist, 1 ); 534 } 535 536 /* get entry or ancestor */ 537 rs->sr_err = mdb_dn2entry( op, txn, NULL, &op->o_req_ndn, &e, NULL, 1 ); 538 539 if ( rs->sr_err != 0 ) { 540 Debug( LDAP_DEBUG_TRACE, 541 LDAP_XSTRING(mdb_modify) ": dn2entry failed (%d)\n", 542 rs->sr_err, 0, 0 ); 543 switch( rs->sr_err ) { 544 case MDB_NOTFOUND: 545 break; 546 case LDAP_BUSY: 547 rs->sr_text = "ldap server busy"; 548 goto return_results; 549 default: 550 rs->sr_err = LDAP_OTHER; 551 rs->sr_text = "internal error"; 552 goto return_results; 553 } 554 } 555 556 /* acquire and lock entry */ 557 /* FIXME: dn2entry() should return non-glue entry */ 558 if (( rs->sr_err == MDB_NOTFOUND ) || 559 ( !manageDSAit && e && is_entry_glue( e ))) 560 { 561 if ( e != NULL ) { 562 rs->sr_matched = ch_strdup( e->e_dn ); 563 if ( is_entry_referral( e )) { 564 BerVarray ref = get_entry_referrals( op, e ); 565 rs->sr_ref = referral_rewrite( ref, &e->e_name, 566 &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 567 ber_bvarray_free( ref ); 568 } else { 569 rs->sr_ref = NULL; 570 } 571 mdb_entry_return( op, e ); 572 e = NULL; 573 574 } else { 575 rs->sr_ref = referral_rewrite( default_referral, NULL, 576 &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 577 } 578 579 rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; 580 rs->sr_err = LDAP_REFERRAL; 581 send_ldap_result( op, rs ); 582 goto done; 583 } 584 585 if ( !manageDSAit && is_entry_referral( e ) ) { 586 /* entry is a referral, don't allow modify */ 587 rs->sr_ref = get_entry_referrals( op, e ); 588 589 Debug( LDAP_DEBUG_TRACE, 590 LDAP_XSTRING(mdb_modify) ": entry is referral\n", 591 0, 0, 0 ); 592 593 rs->sr_err = LDAP_REFERRAL; 594 rs->sr_matched = e->e_name.bv_val; 595 rs->sr_flags = REP_REF_MUSTBEFREED; 596 send_ldap_result( op, rs ); 597 rs->sr_matched = NULL; 598 goto done; 599 } 600 601 if ( get_assert( op ) && 602 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE )) 603 { 604 rs->sr_err = LDAP_ASSERTION_FAILED; 605 goto return_results; 606 } 607 608 if( op->o_preread ) { 609 if( preread_ctrl == NULL ) { 610 preread_ctrl = &ctrls[num_ctrls++]; 611 ctrls[num_ctrls] = NULL; 612 } 613 if ( slap_read_controls( op, rs, e, 614 &slap_pre_read_bv, preread_ctrl ) ) 615 { 616 Debug( LDAP_DEBUG_TRACE, 617 "<=- " LDAP_XSTRING(mdb_modify) ": pre-read " 618 "failed!\n", 0, 0, 0 ); 619 if ( op->o_preread & SLAP_CONTROL_CRITICAL ) { 620 /* FIXME: is it correct to abort 621 * operation if control fails? */ 622 goto return_results; 623 } 624 } 625 } 626 627 /* Modify the entry */ 628 dummy = *e; 629 rs->sr_err = mdb_modify_internal( op, txn, op->orm_modlist, 630 &dummy, &rs->sr_text, textbuf, textlen ); 631 632 if( rs->sr_err != LDAP_SUCCESS ) { 633 Debug( LDAP_DEBUG_TRACE, 634 LDAP_XSTRING(mdb_modify) ": modify failed (%d)\n", 635 rs->sr_err, 0, 0 ); 636 /* Only free attrs if they were dup'd. */ 637 if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; 638 goto return_results; 639 } 640 641 /* change the entry itself */ 642 rs->sr_err = mdb_id2entry_update( op, txn, NULL, &dummy ); 643 if ( rs->sr_err != 0 ) { 644 Debug( LDAP_DEBUG_TRACE, 645 LDAP_XSTRING(mdb_modify) ": id2entry update failed " "(%d)\n", 646 rs->sr_err, 0, 0 ); 647 rs->sr_text = "entry update failed"; 648 goto return_results; 649 } 650 651 if( op->o_postread ) { 652 if( postread_ctrl == NULL ) { 653 postread_ctrl = &ctrls[num_ctrls++]; 654 ctrls[num_ctrls] = NULL; 655 } 656 if( slap_read_controls( op, rs, &dummy, 657 &slap_post_read_bv, postread_ctrl ) ) 658 { 659 Debug( LDAP_DEBUG_TRACE, 660 "<=- " LDAP_XSTRING(mdb_modify) 661 ": post-read failed!\n", 0, 0, 0 ); 662 if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { 663 /* FIXME: is it correct to abort 664 * operation if control fails? */ 665 goto return_results; 666 } 667 } 668 } 669 670 /* Only free attrs if they were dup'd. */ 671 if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; 672 if( moi == &opinfo ) { 673 LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next ); 674 opinfo.moi_oe.oe_key = NULL; 675 if( op->o_noop ) { 676 mdb->mi_numads = numads; 677 mdb_txn_abort( txn ); 678 rs->sr_err = LDAP_X_NO_OPERATION; 679 txn = NULL; 680 goto return_results; 681 } else { 682 rs->sr_err = mdb_txn_commit( txn ); 683 if ( rs->sr_err ) 684 mdb->mi_numads = numads; 685 txn = NULL; 686 } 687 } 688 689 if( rs->sr_err != 0 ) { 690 Debug( LDAP_DEBUG_ANY, 691 LDAP_XSTRING(mdb_modify) ": txn_%s failed: %s (%d)\n", 692 op->o_noop ? "abort (no-op)" : "commit", 693 mdb_strerror(rs->sr_err), rs->sr_err ); 694 rs->sr_err = LDAP_OTHER; 695 rs->sr_text = "commit failed"; 696 697 goto return_results; 698 } 699 700 Debug( LDAP_DEBUG_TRACE, 701 LDAP_XSTRING(mdb_modify) ": updated%s id=%08lx dn=\"%s\"\n", 702 op->o_noop ? " (no-op)" : "", 703 dummy.e_id, op->o_req_dn.bv_val ); 704 705 rs->sr_err = LDAP_SUCCESS; 706 rs->sr_text = NULL; 707 if( num_ctrls ) rs->sr_ctrls = ctrls; 708 709 return_results: 710 if( dummy.e_attrs ) { 711 attrs_free( dummy.e_attrs ); 712 } 713 send_ldap_result( op, rs ); 714 715 #if 0 716 if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) { 717 TXN_CHECKPOINT( mdb->bi_dbenv, 718 mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 ); 719 } 720 #endif 721 722 done: 723 slap_graduate_commit_csn( op ); 724 725 if( moi == &opinfo ) { 726 if( txn != NULL ) { 727 mdb->mi_numads = numads; 728 mdb_txn_abort( txn ); 729 } 730 if ( opinfo.moi_oe.oe_key ) { 731 LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next ); 732 } 733 } else { 734 moi->moi_ref--; 735 } 736 737 if( e != NULL ) { 738 mdb_entry_return( op, e ); 739 } 740 741 if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) { 742 slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); 743 slap_sl_free( *preread_ctrl, op->o_tmpmemctx ); 744 } 745 if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) { 746 slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); 747 slap_sl_free( *postread_ctrl, op->o_tmpmemctx ); 748 } 749 750 rs->sr_text = NULL; 751 752 return rs->sr_err; 753 } 754