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