1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1998-2011 The OpenLDAP Foundation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in the file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15/* Portions Copyright (c) 1995 Regents of the University of Michigan. 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms are permitted 19 * provided that this notice is preserved and that due credit is given 20 * to the University of Michigan at Ann Arbor. The name of the University 21 * may not be used to endorse or promote products derived from this 22 * software without specific prior written permission. This software 23 * is provided ``as is'' without express or implied warranty. 24 */ 25 26#include "portable.h" 27 28#include <stdio.h> 29 30#include <ac/socket.h> 31#include <ac/string.h> 32#include <ac/time.h> 33 34#include "slap.h" 35#include "lutil.h" 36 37 38int 39do_modify( 40 Operation *op, 41 SlapReply *rs ) 42{ 43 struct berval dn = BER_BVNULL; 44 char textbuf[ SLAP_TEXT_BUFLEN ]; 45 size_t textlen = sizeof( textbuf ); 46#ifdef LDAP_DEBUG 47 Modifications *tmp; 48#endif 49 50 Debug( LDAP_DEBUG_TRACE, "%s do_modify\n", 51 op->o_log_prefix, 0, 0 ); 52 /* 53 * Parse the modify request. It looks like this: 54 * 55 * ModifyRequest := [APPLICATION 6] SEQUENCE { 56 * name DistinguishedName, 57 * mods SEQUENCE OF SEQUENCE { 58 * operation ENUMERATED { 59 * add (0), 60 * delete (1), 61 * replace (2) 62 * }, 63 * modification SEQUENCE { 64 * type AttributeType, 65 * values SET OF AttributeValue 66 * } 67 * } 68 * } 69 */ 70 71 if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) { 72 Debug( LDAP_DEBUG_ANY, "%s do_modify: ber_scanf failed\n", 73 op->o_log_prefix, 0, 0 ); 74 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); 75 return SLAPD_DISCONNECT; 76 } 77 78 Debug( LDAP_DEBUG_ARGS, "%s do_modify: dn (%s)\n", 79 op->o_log_prefix, dn.bv_val, 0 ); 80 81 rs->sr_err = slap_parse_modlist( op, rs, op->o_ber, &op->oq_modify ); 82 if ( rs->sr_err != LDAP_SUCCESS ) { 83 Debug( LDAP_DEBUG_ANY, "%s do_modify: slap_parse_modlist failed err=%d msg=%s\n", 84 op->o_log_prefix, rs->sr_err, rs->sr_text ); 85 send_ldap_result( op, rs ); 86 goto cleanup; 87 } 88 89 if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { 90 Debug( LDAP_DEBUG_ANY, "%s do_modify: get_ctrls failed\n", 91 op->o_log_prefix, 0, 0 ); 92 /* get_ctrls has sent results. Now clean up. */ 93 goto cleanup; 94 } 95 96 rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, 97 op->o_tmpmemctx ); 98 if( rs->sr_err != LDAP_SUCCESS ) { 99 Debug( LDAP_DEBUG_ANY, "%s do_modify: invalid dn (%s)\n", 100 op->o_log_prefix, dn.bv_val, 0 ); 101 send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); 102 goto cleanup; 103 } 104 105 op->orm_no_opattrs = 0; 106 107#ifdef LDAP_DEBUG 108 Debug( LDAP_DEBUG_ARGS, "%s modifications:\n", 109 op->o_log_prefix, 0, 0 ); 110 111 for ( tmp = op->orm_modlist; tmp != NULL; tmp = tmp->sml_next ) { 112 Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n", 113 tmp->sml_op == LDAP_MOD_ADD ? "add" : 114 (tmp->sml_op == LDAP_MOD_INCREMENT ? "increment" : 115 (tmp->sml_op == LDAP_MOD_DELETE ? "delete" : 116 "replace")), tmp->sml_type.bv_val, 0 ); 117 118 if ( tmp->sml_values == NULL ) { 119 Debug( LDAP_DEBUG_ARGS, "%s\n", 120 "\t\tno values", NULL, NULL ); 121 } else if ( BER_BVISNULL( &tmp->sml_values[ 0 ] ) ) { 122 Debug( LDAP_DEBUG_ARGS, "%s\n", 123 "\t\tzero values", NULL, NULL ); 124 } else if ( BER_BVISNULL( &tmp->sml_values[ 1 ] ) ) { 125 Debug( LDAP_DEBUG_ARGS, "%s, length %ld\n", 126 "\t\tone value", (long) tmp->sml_values[0].bv_len, NULL ); 127 } else { 128 Debug( LDAP_DEBUG_ARGS, "%s\n", 129 "\t\tmultiple values", NULL, NULL ); 130 } 131 } 132 133 if ( StatslogTest( LDAP_DEBUG_STATS ) ) { 134 char abuf[BUFSIZ/2], *ptr = abuf; 135 int len = 0; 136 137 Statslog( LDAP_DEBUG_STATS, "%s MOD dn=\"%s\"\n", 138 op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 ); 139 140 for ( tmp = op->orm_modlist; tmp != NULL; tmp = tmp->sml_next ) { 141 if (len + 1 + tmp->sml_type.bv_len > sizeof(abuf)) { 142 Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n", 143 op->o_log_prefix, abuf, 0, 0, 0 ); 144 145 len = 0; 146 ptr = abuf; 147 148 if( 1 + tmp->sml_type.bv_len > sizeof(abuf)) { 149 Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n", 150 op->o_log_prefix, tmp->sml_type.bv_val, 0, 0, 0 ); 151 continue; 152 } 153 } 154 if (len) { 155 *ptr++ = ' '; 156 len++; 157 } 158 ptr = lutil_strcopy(ptr, tmp->sml_type.bv_val); 159 len += tmp->sml_type.bv_len; 160 } 161 if (len) { 162 Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n", 163 op->o_log_prefix, abuf, 0, 0, 0 ); 164 } 165 } 166#endif /* LDAP_DEBUG */ 167 168 rs->sr_err = slap_mods_check( op, op->orm_modlist, 169 &rs->sr_text, textbuf, textlen, NULL ); 170 171 if ( rs->sr_err != LDAP_SUCCESS ) { 172 send_ldap_result( op, rs ); 173 goto cleanup; 174 } 175 176 op->o_bd = frontendDB; 177 rs->sr_err = frontendDB->be_modify( op, rs ); 178 179#ifdef LDAP_X_TXN 180 if( rs->sr_err == LDAP_X_TXN_SPECIFY_OKAY ) { 181 /* skip cleanup */ 182 return rs->sr_err; 183 } 184#endif 185 186cleanup: 187 op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx ); 188 op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx ); 189 if ( op->orm_modlist != NULL ) slap_mods_free( op->orm_modlist, 1 ); 190 191 return rs->sr_err; 192} 193 194int 195fe_op_modify( Operation *op, SlapReply *rs ) 196{ 197 BackendDB *op_be, *bd = op->o_bd; 198 char textbuf[ SLAP_TEXT_BUFLEN ]; 199 size_t textlen = sizeof( textbuf ); 200 201 if ( BER_BVISEMPTY( &op->o_req_ndn ) ) { 202 Debug( LDAP_DEBUG_ANY, "%s do_modify: root dse!\n", 203 op->o_log_prefix, 0, 0 ); 204 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 205 "modify upon the root DSE not supported" ); 206 goto cleanup; 207 208 } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { 209 Debug( LDAP_DEBUG_ANY, "%s do_modify: subschema subentry!\n", 210 op->o_log_prefix, 0, 0 ); 211 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 212 "modification of subschema subentry not supported" ); 213 goto cleanup; 214 } 215 216 /* 217 * We could be serving multiple database backends. Select the 218 * appropriate one, or send a referral to our "referral server" 219 * if we don't hold it. 220 */ 221 op->o_bd = select_backend( &op->o_req_ndn, 1 ); 222 if ( op->o_bd == NULL ) { 223 op->o_bd = bd; 224 rs->sr_ref = referral_rewrite( default_referral, 225 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 226 if ( !rs->sr_ref ) { 227 rs->sr_ref = default_referral; 228 } 229 230 if ( rs->sr_ref != NULL ) { 231 rs->sr_err = LDAP_REFERRAL; 232 send_ldap_result( op, rs ); 233 234 if ( rs->sr_ref != default_referral ) { 235 ber_bvarray_free( rs->sr_ref ); 236 } 237 238 } else { 239 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 240 "no global superior knowledge" ); 241 } 242 goto cleanup; 243 } 244 245 /* If we've got a glued backend, check the real backend */ 246 op_be = op->o_bd; 247 if ( SLAP_GLUE_INSTANCE( op->o_bd )) { 248 op->o_bd = select_backend( &op->o_req_ndn, 0 ); 249 } 250 251 /* check restrictions */ 252 if ( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { 253 send_ldap_result( op, rs ); 254 goto cleanup; 255 } 256 257 /* check for referrals */ 258 if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) { 259 goto cleanup; 260 } 261 262 rs->sr_err = slap_mods_obsolete_check( op, op->orm_modlist, 263 &rs->sr_text, textbuf, textlen ); 264 if ( rs->sr_err != LDAP_SUCCESS ) { 265 send_ldap_result( op, rs ); 266 goto cleanup; 267 } 268 269 /* check for modify/increment support */ 270 if ( op->orm_increment && !SLAP_INCREMENT( op->o_bd ) ) { 271 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 272 "modify/increment not supported in context" ); 273 goto cleanup; 274 } 275 276 /* 277 * do the modify if 1 && (2 || 3) 278 * 1) there is a modify function implemented in this backend; 279 * 2) this backend is master for what it holds; 280 * 3) it's a replica and the dn supplied is the update_ndn. 281 */ 282 if ( op->o_bd->be_modify ) { 283 /* do the update here */ 284 int repl_user = be_isupdate( op ); 285 286 /* 287 * Multimaster slapd does not have to check for replicator dn 288 * because it accepts each modify request 289 */ 290 if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) { 291 int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn ); 292 293 op->o_bd = op_be; 294 295 if ( !update ) { 296 rs->sr_err = slap_mods_no_user_mod_check( op, op->orm_modlist, 297 &rs->sr_text, textbuf, textlen ); 298 if ( rs->sr_err != LDAP_SUCCESS ) { 299 send_ldap_result( op, rs ); 300 goto cleanup; 301 } 302 } 303 op->o_bd->be_modify( op, rs ); 304 305 } else { /* send a referral */ 306 BerVarray defref = op->o_bd->be_update_refs 307 ? op->o_bd->be_update_refs : default_referral; 308 if ( defref != NULL ) { 309 rs->sr_ref = referral_rewrite( defref, 310 NULL, &op->o_req_dn, 311 LDAP_SCOPE_DEFAULT ); 312 if ( rs->sr_ref == NULL ) { 313 /* FIXME: must duplicate, because 314 * overlays may muck with it */ 315 rs->sr_ref = defref; 316 } 317 rs->sr_err = LDAP_REFERRAL; 318 send_ldap_result( op, rs ); 319 if ( rs->sr_ref != defref ) { 320 ber_bvarray_free( rs->sr_ref ); 321 } 322 323 } else { 324 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 325 "shadow context; no update referral" ); 326 } 327 } 328 329 } else { 330 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 331 "operation not supported within namingContext" ); 332 } 333 334cleanup:; 335 op->o_bd = bd; 336 return rs->sr_err; 337} 338 339/* 340 * Obsolete constraint checking. 341 */ 342int 343slap_mods_obsolete_check( 344 Operation *op, 345 Modifications *ml, 346 const char **text, 347 char *textbuf, 348 size_t textlen ) 349{ 350 if( get_relax( op ) ) return LDAP_SUCCESS; 351 352 for ( ; ml != NULL; ml = ml->sml_next ) { 353 if ( is_at_obsolete( ml->sml_desc->ad_type ) && 354 (( ml->sml_op != LDAP_MOD_REPLACE && 355 ml->sml_op != LDAP_MOD_DELETE ) || 356 ml->sml_values != NULL )) 357 { 358 /* 359 * attribute is obsolete, 360 * only allow replace/delete with no values 361 */ 362 snprintf( textbuf, textlen, 363 "%s: attribute is obsolete", 364 ml->sml_type.bv_val ); 365 *text = textbuf; 366 return LDAP_CONSTRAINT_VIOLATION; 367 } 368 } 369 370 return LDAP_SUCCESS; 371} 372 373/* 374 * No-user-modification constraint checking. 375 */ 376int 377slap_mods_no_user_mod_check( 378 Operation *op, 379 Modifications *ml, 380 const char **text, 381 char *textbuf, 382 size_t textlen ) 383{ 384 for ( ; ml != NULL; ml = ml->sml_next ) { 385 if ( !is_at_no_user_mod( ml->sml_desc->ad_type ) ) { 386 continue; 387 } 388 389 if ( ml->sml_flags & SLAP_MOD_INTERNAL ) { 390 continue; 391 } 392 393 if ( get_relax( op ) ) { 394 if ( ml->sml_desc->ad_type->sat_flags & SLAP_AT_MANAGEABLE ) { 395 ml->sml_flags |= SLAP_MOD_MANAGING; 396 continue; 397 } 398 399 /* attribute not manageable */ 400 snprintf( textbuf, textlen, 401 "%s: no-user-modification attribute not manageable", 402 ml->sml_type.bv_val ); 403 404 } else { 405 /* user modification disallowed */ 406 snprintf( textbuf, textlen, 407 "%s: no user modification allowed", 408 ml->sml_type.bv_val ); 409 } 410 411 *text = textbuf; 412 return LDAP_CONSTRAINT_VIOLATION; 413 } 414 415 return LDAP_SUCCESS; 416} 417 418int 419slap_mods_no_repl_user_mod_check( 420 Operation *op, 421 Modifications *ml, 422 const char **text, 423 char *textbuf, 424 size_t textlen ) 425{ 426 Modifications *mods; 427 Modifications *modp; 428 429 for ( mods = ml; mods != NULL; mods = mods->sml_next ) { 430 assert( mods->sml_op == LDAP_MOD_ADD ); 431 432 /* check doesn't already appear */ 433 for ( modp = ml; modp != NULL; modp = modp->sml_next ) { 434 if ( mods->sml_desc == modp->sml_desc && mods != modp ) { 435 snprintf( textbuf, textlen, 436 "attribute '%s' provided more than once", 437 mods->sml_desc->ad_cname.bv_val ); 438 *text = textbuf; 439 return LDAP_TYPE_OR_VALUE_EXISTS; 440 } 441 } 442 } 443 444 return LDAP_SUCCESS; 445} 446 447/* 448 * Do basic attribute type checking and syntax validation. 449 */ 450int slap_mods_check( 451 Operation *op, 452 Modifications *ml, 453 const char **text, 454 char *textbuf, 455 size_t textlen, 456 void *ctx ) 457{ 458 int rc; 459 460 for( ; ml != NULL; ml = ml->sml_next ) { 461 AttributeDescription *ad = NULL; 462 463 /* convert to attribute description */ 464 if ( ml->sml_desc == NULL ) { 465 rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text ); 466 if( rc != LDAP_SUCCESS ) { 467 if ( get_no_schema_check( op )) { 468 rc = slap_bv2undef_ad( &ml->sml_type, &ml->sml_desc, 469 text, 0 ); 470 } 471 } 472 if( rc != LDAP_SUCCESS ) { 473 snprintf( textbuf, textlen, "%s: %s", 474 ml->sml_type.bv_val, *text ); 475 *text = textbuf; 476 return rc; 477 } 478 } 479 480 ad = ml->sml_desc; 481 482 if( slap_syntax_is_binary( ad->ad_type->sat_syntax ) 483 && !slap_ad_is_binary( ad )) 484 { 485 /* attribute requires binary transfer */ 486 snprintf( textbuf, textlen, 487 "%s: requires ;binary transfer", 488 ml->sml_type.bv_val ); 489 *text = textbuf; 490 return LDAP_UNDEFINED_TYPE; 491 } 492 493 if( !slap_syntax_is_binary( ad->ad_type->sat_syntax ) 494 && slap_ad_is_binary( ad )) 495 { 496 /* attribute does not require binary transfer */ 497 snprintf( textbuf, textlen, 498 "%s: disallows ;binary transfer", 499 ml->sml_type.bv_val ); 500 *text = textbuf; 501 return LDAP_UNDEFINED_TYPE; 502 } 503 504 if( slap_ad_is_tag_range( ad )) { 505 /* attribute requires binary transfer */ 506 snprintf( textbuf, textlen, 507 "%s: inappropriate use of tag range option", 508 ml->sml_type.bv_val ); 509 *text = textbuf; 510 return LDAP_UNDEFINED_TYPE; 511 } 512 513#if 0 514 if ( is_at_obsolete( ad->ad_type ) && 515 (( ml->sml_op != LDAP_MOD_REPLACE && 516 ml->sml_op != LDAP_MOD_DELETE ) || 517 ml->sml_values != NULL )) 518 { 519 /* 520 * attribute is obsolete, 521 * only allow replace/delete with no values 522 */ 523 snprintf( textbuf, textlen, 524 "%s: attribute is obsolete", 525 ml->sml_type.bv_val ); 526 *text = textbuf; 527 return LDAP_CONSTRAINT_VIOLATION; 528 } 529#endif 530 531 if ( ml->sml_op == LDAP_MOD_INCREMENT && 532#ifdef SLAPD_REAL_SYNTAX 533 !is_at_syntax( ad->ad_type, SLAPD_REAL_SYNTAX ) && 534#endif 535 !is_at_syntax( ad->ad_type, SLAPD_INTEGER_SYNTAX ) ) 536 { 537 /* 538 * attribute values must be INTEGER or REAL 539 */ 540 snprintf( textbuf, textlen, 541 "%s: attribute syntax inappropriate for increment", 542 ml->sml_type.bv_val ); 543 *text = textbuf; 544 return LDAP_CONSTRAINT_VIOLATION; 545 } 546 547 /* 548 * check values 549 */ 550 if( ml->sml_values != NULL ) { 551 ber_len_t nvals; 552 slap_syntax_validate_func *validate = 553 ad->ad_type->sat_syntax->ssyn_validate; 554 slap_syntax_transform_func *pretty = 555 ad->ad_type->sat_syntax->ssyn_pretty; 556 557 if( !pretty && !validate ) { 558 *text = "no validator for syntax"; 559 snprintf( textbuf, textlen, 560 "%s: no validator for syntax %s", 561 ml->sml_type.bv_val, 562 ad->ad_type->sat_syntax->ssyn_oid ); 563 *text = textbuf; 564 return LDAP_INVALID_SYNTAX; 565 } 566 567 /* 568 * check that each value is valid per syntax 569 * and pretty if appropriate 570 */ 571 for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) { 572 struct berval pval; 573 574 if ( pretty ) { 575 rc = ordered_value_pretty( ad, 576 &ml->sml_values[nvals], &pval, ctx ); 577 } else { 578 rc = ordered_value_validate( ad, 579 &ml->sml_values[nvals], ml->sml_op ); 580 } 581 582 if( rc != 0 ) { 583 snprintf( textbuf, textlen, 584 "%s: value #%ld invalid per syntax", 585 ml->sml_type.bv_val, (long) nvals ); 586 *text = textbuf; 587 return LDAP_INVALID_SYNTAX; 588 } 589 590 if( pretty ) { 591 ber_memfree_x( ml->sml_values[nvals].bv_val, ctx ); 592 ml->sml_values[nvals] = pval; 593 } 594 } 595 ml->sml_values[nvals].bv_len = 0; 596 ml->sml_numvals = nvals; 597 598 /* 599 * a rough single value check... an additional check is needed 600 * to catch add of single value to existing single valued attribute 601 */ 602 if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE) 603 && nvals > 1 && is_at_single_value( ad->ad_type )) 604 { 605 snprintf( textbuf, textlen, 606 "%s: multiple values provided", 607 ml->sml_type.bv_val ); 608 *text = textbuf; 609 return LDAP_CONSTRAINT_VIOLATION; 610 } 611 612 /* if the type has a normalizer, generate the 613 * normalized values. otherwise leave them NULL. 614 * 615 * this is different from the rule for attributes 616 * in an entry - in an attribute list, the normalized 617 * value is set equal to the non-normalized value 618 * when there is no normalizer. 619 */ 620 if( nvals && ad->ad_type->sat_equality && 621 ad->ad_type->sat_equality->smr_normalize ) 622 { 623 ml->sml_nvalues = ber_memalloc_x( 624 (nvals+1)*sizeof(struct berval), ctx ); 625 626 for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) { 627 rc = ordered_value_normalize( 628 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 629 ad, 630 ad->ad_type->sat_equality, 631 &ml->sml_values[nvals], &ml->sml_nvalues[nvals], ctx ); 632 if ( rc ) { 633 Debug( LDAP_DEBUG_ANY, 634 "<= str2entry NULL (ssyn_normalize %d)\n", 635 rc, 0, 0 ); 636 snprintf( textbuf, textlen, 637 "%s: value #%ld normalization failed", 638 ml->sml_type.bv_val, (long) nvals ); 639 *text = textbuf; 640 BER_BVZERO( &ml->sml_nvalues[nvals] ); 641 return rc; 642 } 643 } 644 645 BER_BVZERO( &ml->sml_nvalues[nvals] ); 646 } 647 648 /* check for duplicates, but ignore Deletes. 649 */ 650 if( nvals > 1 && ml->sml_op != LDAP_MOD_DELETE ) { 651 int i; 652 rc = slap_sort_vals( ml, text, &i, ctx ); 653 if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) { 654 /* value exists already */ 655 snprintf( textbuf, textlen, 656 "%s: value #%d provided more than once", 657 ml->sml_desc->ad_cname.bv_val, i ); 658 *text = textbuf; 659 } 660 if ( rc ) 661 return rc; 662 } 663 } else { 664 ml->sml_numvals = 0; 665 } 666 } 667 668 return LDAP_SUCCESS; 669} 670 671/* Sort a set of values. An (Attribute *) may be used interchangeably here 672 * instead of a (Modifications *) structure. 673 * 674 * Uses Quicksort + Insertion sort for small arrays 675 */ 676 677int 678slap_sort_vals( 679 Modifications *ml, 680 const char **text, 681 int *dup, 682 void *ctx ) 683{ 684 AttributeDescription *ad; 685 MatchingRule *mr; 686 int istack[sizeof(int)*16]; 687 int i, j, k, l, ir, jstack, match, *ix, itmp, nvals, rc = LDAP_SUCCESS; 688 int is_norm; 689 struct berval a, *cv; 690 691#define SMALL 8 692#define SWAP(a,b,tmp) tmp=(a);(a)=(b);(b)=tmp 693#define COMP(a,b) match=0; rc = ordered_value_match( &match, \ 694 ad, mr, SLAP_MR_EQUALITY \ 695 | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX \ 696 | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH \ 697 | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, \ 698 &(a), &(b), text ); 699 700#define IX(x) ix[x] 701#define EXCH(x,y) SWAP(ix[x],ix[y],itmp) 702#define SETA(x) itmp = ix[x]; a = cv[itmp] 703#define GETA(x) ix[x] = itmp; 704#define SET(x,y) ix[x] = ix[y] 705 706 ad = ml->sml_desc; 707 nvals = ml->sml_numvals; 708 if ( nvals <= 1 ) 709 goto ret; 710 711 /* For Modifications, sml_nvalues is NULL if normalization wasn't needed. 712 * For Attributes, sml_nvalues == sml_values when normalization isn't needed. 713 */ 714 if ( ml->sml_nvalues && ml->sml_nvalues != ml->sml_values ) { 715 cv = ml->sml_nvalues; 716 is_norm = 1; 717 } else { 718 cv = ml->sml_values; 719 is_norm = 0; 720 } 721 722 if ( ad == slap_schema.si_ad_objectClass ) 723 mr = NULL; /* shortcut matching */ 724 else 725 mr = ad->ad_type->sat_equality; 726 727 /* record indices to preserve input ordering */ 728 ix = slap_sl_malloc( nvals * sizeof(int), ctx ); 729 for (i=0; i<nvals; i++) ix[i] = i; 730 731 ir = nvals-1; 732 l = 0; 733 jstack = 0; 734 735 for(;;) { 736 if (ir - l < SMALL) { /* Insertion sort */ 737 match=1; 738 for (j=l+1;j<=ir;j++) { 739 SETA(j); 740 for (i=j-1;i>=0;i--) { 741 COMP(cv[IX(i)], a); 742 if ( match <= 0 ) 743 break; 744 SET(i+1,i); 745 } 746 GETA(i+1); 747 if ( match == 0 ) goto done; 748 } 749 if ( jstack == 0 ) break; 750 if ( match == 0 ) break; 751 ir = istack[jstack--]; 752 l = istack[jstack--]; 753 } else { 754 k = (l + ir) >> 1; /* Choose median of left, center, right */ 755 EXCH(k, l+1); 756 COMP( cv[IX(l)], cv[IX(ir)] ); 757 if ( match > 0 ) { 758 EXCH(l, ir); 759 } else if ( match == 0 ) { 760 i = ir; 761 break; 762 } 763 COMP( cv[IX(l+1)], cv[IX(ir)] ); 764 if ( match > 0 ) { 765 EXCH(l+1, ir); 766 } else if ( match == 0 ) { 767 i = ir; 768 break; 769 } 770 COMP( cv[IX(l)], cv[IX(l+1)] ); 771 if ( match > 0 ) { 772 EXCH(l, l+1); 773 } else if ( match == 0 ) { 774 i = l; 775 break; 776 } 777 i = l+1; 778 j = ir; 779 a = cv[IX(i)]; 780 for(;;) { 781 do { 782 i++; 783 COMP( cv[IX(i)], a ); 784 } while( match < 0 ); 785 while( match > 0 ) { 786 j--; 787 COMP( cv[IX(j)], a ); 788 } 789 if (j < i) { 790 match = 1; 791 break; 792 } 793 if ( match == 0 ) { 794 i = l+1; 795 break; 796 } 797 EXCH(i,j); 798 } 799 if ( match == 0 ) 800 break; 801 EXCH(l+1,j); 802 jstack += 2; 803 if (ir-i+1 >= j) { 804 istack[jstack] = ir; 805 istack[jstack-1] = i; 806 ir = j; 807 } else { 808 istack[jstack] = j; 809 istack[jstack-1] = l; 810 l = i; 811 } 812 } 813 } 814 done: 815 if ( match == 0 && i >= 0 ) 816 *dup = ix[i]; 817 818 /* For sorted attributes, put the values in index order */ 819 if ( rc == LDAP_SUCCESS && match && 820 ( ad->ad_type->sat_flags & SLAP_AT_SORTED_VAL )) { 821 BerVarray tmpv = slap_sl_malloc( sizeof( struct berval ) * nvals, ctx ); 822 for ( i = 0; i<nvals; i++ ) 823 tmpv[i] = cv[ix[i]]; 824 for ( i = 0; i<nvals; i++ ) 825 cv[i] = tmpv[i]; 826 /* Check if the non-normalized array needs to move too */ 827 if ( is_norm ) { 828 cv = ml->sml_values; 829 for ( i = 0; i<nvals; i++ ) 830 tmpv[i] = cv[ix[i]]; 831 for ( i = 0; i<nvals; i++ ) 832 cv[i] = tmpv[i]; 833 } 834 slap_sl_free( tmpv, ctx ); 835 } 836 837 slap_sl_free( ix, ctx ); 838 839 if ( rc == LDAP_SUCCESS && match == 0 ) { 840 /* value exists already */ 841 assert( i >= 0 ); 842 assert( i < nvals ); 843 rc = LDAP_TYPE_OR_VALUE_EXISTS; 844 } 845 ret: 846 return rc; 847} 848 849/* Enter with bv->bv_len = sizeof buffer, returns with 850 * actual length of string 851 */ 852void slap_timestamp( time_t *tm, struct berval *bv ) 853{ 854 struct tm ltm; 855 856 ldap_pvt_gmtime( tm, <m ); 857 858 bv->bv_len = lutil_gentime( bv->bv_val, bv->bv_len, <m ); 859} 860 861/* Called for all modify and modrdn ops. If the current op was replicated 862 * from elsewhere, all of the attrs should already be present. 863 */ 864void slap_mods_opattrs( 865 Operation *op, 866 Modifications **modsp, 867 int manage_ctxcsn ) 868{ 869 struct berval name, timestamp, csn = BER_BVNULL; 870 struct berval nname; 871 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 872 char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ]; 873 Modifications *mod, **modtail, *modlast; 874 int gotcsn = 0, gotmname = 0, gotmtime = 0; 875 876 if ( SLAP_LASTMOD( op->o_bd ) && !op->orm_no_opattrs ) { 877 char *ptr; 878 timestamp.bv_val = timebuf; 879 for ( modtail = modsp; *modtail; modtail = &(*modtail)->sml_next ) { 880 if ( (*modtail)->sml_op != LDAP_MOD_ADD && 881 (*modtail)->sml_op != SLAP_MOD_SOFTADD && 882 (*modtail)->sml_op != SLAP_MOD_ADD_IF_NOT_PRESENT && 883 (*modtail)->sml_op != LDAP_MOD_REPLACE ) 884 { 885 continue; 886 } 887 888 if ( (*modtail)->sml_desc == slap_schema.si_ad_entryCSN ) 889 { 890 csn = (*modtail)->sml_values[0]; 891 gotcsn = 1; 892 893 } else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifiersName ) 894 { 895 gotmname = 1; 896 897 } else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifyTimestamp ) 898 { 899 gotmtime = 1; 900 } 901 } 902 903 if ( BER_BVISEMPTY( &op->o_csn )) { 904 if ( !gotcsn ) { 905 csn.bv_val = csnbuf; 906 csn.bv_len = sizeof( csnbuf ); 907 slap_get_csn( op, &csn, manage_ctxcsn ); 908 909 } else { 910 if ( manage_ctxcsn ) { 911 slap_queue_csn( op, &csn ); 912 } 913 } 914 915 } else { 916 csn = op->o_csn; 917 } 918 919 ptr = ber_bvchr( &csn, '#' ); 920 if ( ptr ) { 921 timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ"); 922 AC_MEMCPY( timebuf, csn.bv_val, timestamp.bv_len ); 923 timebuf[timestamp.bv_len-1] = 'Z'; 924 timebuf[timestamp.bv_len] = '\0'; 925 926 } else { 927 time_t now = slap_get_time(); 928 929 timestamp.bv_len = sizeof(timebuf); 930 931 slap_timestamp( &now, ×tamp ); 932 } 933 934 if ( BER_BVISEMPTY( &op->o_dn ) ) { 935 BER_BVSTR( &name, SLAPD_ANONYMOUS ); 936 nname = name; 937 938 } else { 939 name = op->o_dn; 940 nname = op->o_ndn; 941 } 942 943 if ( !gotcsn ) { 944 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 945 mod->sml_op = LDAP_MOD_REPLACE; 946 mod->sml_flags = SLAP_MOD_INTERNAL; 947 mod->sml_next = NULL; 948 BER_BVZERO( &mod->sml_type ); 949 mod->sml_desc = slap_schema.si_ad_entryCSN; 950 mod->sml_numvals = 1; 951 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 952 ber_dupbv( &mod->sml_values[0], &csn ); 953 BER_BVZERO( &mod->sml_values[1] ); 954 assert( !BER_BVISNULL( &mod->sml_values[0] ) ); 955 mod->sml_nvalues = NULL; 956 *modtail = mod; 957 modlast = mod; 958 modtail = &mod->sml_next; 959 } 960 961 if ( !gotmname ) { 962 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 963 mod->sml_op = LDAP_MOD_REPLACE; 964 mod->sml_flags = SLAP_MOD_INTERNAL; 965 mod->sml_next = NULL; 966 BER_BVZERO( &mod->sml_type ); 967 mod->sml_desc = slap_schema.si_ad_modifiersName; 968 mod->sml_numvals = 1; 969 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 970 ber_dupbv( &mod->sml_values[0], &name ); 971 BER_BVZERO( &mod->sml_values[1] ); 972 assert( !BER_BVISNULL( &mod->sml_values[0] ) ); 973 mod->sml_nvalues = 974 (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 975 ber_dupbv( &mod->sml_nvalues[0], &nname ); 976 BER_BVZERO( &mod->sml_nvalues[1] ); 977 assert( !BER_BVISNULL( &mod->sml_nvalues[0] ) ); 978 *modtail = mod; 979 modtail = &mod->sml_next; 980 } 981 982 if ( !gotmtime ) { 983 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 984 mod->sml_op = LDAP_MOD_REPLACE; 985 mod->sml_flags = SLAP_MOD_INTERNAL; 986 mod->sml_next = NULL; 987 BER_BVZERO( &mod->sml_type ); 988 mod->sml_desc = slap_schema.si_ad_modifyTimestamp; 989 mod->sml_numvals = 1; 990 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 991 ber_dupbv( &mod->sml_values[0], ×tamp ); 992 BER_BVZERO( &mod->sml_values[1] ); 993 assert( !BER_BVISNULL( &mod->sml_values[0] ) ); 994 mod->sml_nvalues = NULL; 995 *modtail = mod; 996 modtail = &mod->sml_next; 997 } 998 } 999} 1000 1001int 1002slap_parse_modlist( 1003 Operation *op, 1004 SlapReply *rs, 1005 BerElement *ber, 1006 req_modify_s *ms ) 1007{ 1008 ber_tag_t tag; 1009 ber_len_t len; 1010 char *last; 1011 Modifications **modtail = &ms->rs_mods.rs_modlist; 1012 1013 ms->rs_mods.rs_modlist = NULL; 1014 ms->rs_increment = 0; 1015 1016 rs->sr_err = LDAP_SUCCESS; 1017 1018 /* collect modifications & save for later */ 1019 for ( tag = ber_first_element( ber, &len, &last ); 1020 tag != LBER_DEFAULT; 1021 tag = ber_next_element( ber, &len, last ) ) 1022 { 1023 ber_int_t mop; 1024 Modifications tmp, *mod; 1025 1026 tmp.sml_nvalues = NULL; 1027 1028 if ( ber_scanf( ber, "{e{m[W]}}", &mop, 1029 &tmp.sml_type, &tmp.sml_values ) == LBER_ERROR ) 1030 { 1031 rs->sr_text = "decoding modlist error"; 1032 rs->sr_err = LDAP_PROTOCOL_ERROR; 1033 goto done; 1034 } 1035 1036 mod = (Modifications *) ch_malloc( sizeof(Modifications) ); 1037 mod->sml_op = mop; 1038 mod->sml_flags = 0; 1039 mod->sml_type = tmp.sml_type; 1040 mod->sml_values = tmp.sml_values; 1041 mod->sml_nvalues = NULL; 1042 mod->sml_desc = NULL; 1043 mod->sml_next = NULL; 1044 *modtail = mod; 1045 1046 switch( mop ) { 1047 case LDAP_MOD_ADD: 1048 if ( mod->sml_values == NULL ) { 1049 rs->sr_text = "modify/add operation requires values"; 1050 rs->sr_err = LDAP_PROTOCOL_ERROR; 1051 goto done; 1052 } 1053 1054 /* fall through */ 1055 1056 case LDAP_MOD_DELETE: 1057 case LDAP_MOD_REPLACE: 1058 break; 1059 1060 case LDAP_MOD_INCREMENT: 1061 if( op->o_protocol >= LDAP_VERSION3 ) { 1062 ms->rs_increment++; 1063 if ( mod->sml_values == NULL ) { 1064 rs->sr_text = "modify/increment operation requires value"; 1065 rs->sr_err = LDAP_PROTOCOL_ERROR; 1066 goto done; 1067 } 1068 1069 if ( !BER_BVISNULL( &mod->sml_values[ 1 ] ) ) { 1070 rs->sr_text = "modify/increment operation requires single value"; 1071 rs->sr_err = LDAP_PROTOCOL_ERROR; 1072 goto done; 1073 } 1074 1075 break; 1076 } 1077 /* fall thru */ 1078 1079 default: 1080 rs->sr_text = "unrecognized modify operation"; 1081 rs->sr_err = LDAP_PROTOCOL_ERROR; 1082 goto done; 1083 } 1084 1085 modtail = &mod->sml_next; 1086 } 1087 *modtail = NULL; 1088 1089done: 1090 if ( rs->sr_err != LDAP_SUCCESS ) { 1091 slap_mods_free( ms->rs_mods.rs_modlist, 1 ); 1092 ms->rs_mods.rs_modlist = NULL; 1093 ms->rs_increment = 0; 1094 } 1095 1096 return rs->sr_err; 1097} 1098 1099