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