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