1/* $NetBSD: modify.c,v 1.1.1.3 2010/12/12 15:22:33 adam Exp $ */ 2 3/* OpenLDAP: pkg/ldap/servers/slapd/modify.c,v 1.276.2.15 2010/04/19 16:53:02 quanah Exp */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2010 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 40int 41do_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 goto cleanup; 88 } 89 90 if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { 91 Debug( LDAP_DEBUG_ANY, "%s do_modify: get_ctrls failed\n", 92 op->o_log_prefix, 0, 0 ); 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; 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 709 /* For Modifications, sml_nvalues is NULL if normalization wasn't needed. 710 * For Attributes, sml_nvalues == sml_values when normalization isn't needed. 711 */ 712 if ( ml->sml_nvalues && ml->sml_nvalues != ml->sml_values ) { 713 cv = ml->sml_nvalues; 714 is_norm = 1; 715 } else { 716 cv = ml->sml_values; 717 is_norm = 0; 718 } 719 720 if ( ad == slap_schema.si_ad_objectClass ) 721 mr = NULL; /* shortcut matching */ 722 else 723 mr = ad->ad_type->sat_equality; 724 725 /* record indices to preserve input ordering */ 726 ix = slap_sl_malloc( nvals * sizeof(int), ctx ); 727 for (i=0; i<nvals; i++) ix[i] = i; 728 729 ir = nvals-1; 730 l = 0; 731 jstack = 0; 732 733 for(;;) { 734 if (ir - l < SMALL) { /* Insertion sort */ 735 match=1; 736 for (j=l+1;j<=ir;j++) { 737 SETA(j); 738 for (i=j-1;i>=0;i--) { 739 COMP(cv[IX(i)], a); 740 if ( match <= 0 ) 741 break; 742 SET(i+1,i); 743 } 744 GETA(i+1); 745 if ( match == 0 ) goto done; 746 } 747 if ( jstack == 0 ) break; 748 if ( match == 0 ) break; 749 ir = istack[jstack--]; 750 l = istack[jstack--]; 751 } else { 752 k = (l + ir) >> 1; /* Choose median of left, center, right */ 753 EXCH(k, l+1); 754 COMP( cv[IX(l)], cv[IX(ir)] ); 755 if ( match > 0 ) { 756 EXCH(l, ir); 757 } else if ( match == 0 ) { 758 i = ir; 759 break; 760 } 761 COMP( cv[IX(l+1)], cv[IX(ir)] ); 762 if ( match > 0 ) { 763 EXCH(l+1, ir); 764 } else if ( match == 0 ) { 765 i = ir; 766 break; 767 } 768 COMP( cv[IX(l)], cv[IX(l+1)] ); 769 if ( match > 0 ) { 770 EXCH(l, l+1); 771 } else if ( match == 0 ) { 772 i = l; 773 break; 774 } 775 i = l+1; 776 j = ir; 777 a = cv[IX(i)]; 778 for(;;) { 779 do { 780 i++; 781 COMP( cv[IX(i)], a ); 782 } while( match < 0 ); 783 while( match > 0 ) { 784 j--; 785 COMP( cv[IX(j)], a ); 786 } 787 if (j < i) { 788 match = 1; 789 break; 790 } 791 if ( match == 0 ) { 792 i = l+1; 793 break; 794 } 795 EXCH(i,j); 796 } 797 if ( match == 0 ) 798 break; 799 EXCH(l+1,j); 800 jstack += 2; 801 if (ir-i+1 >= j) { 802 istack[jstack] = ir; 803 istack[jstack-1] = i; 804 ir = j; 805 } else { 806 istack[jstack] = j; 807 istack[jstack-1] = l; 808 l = i; 809 } 810 } 811 } 812 done: 813 if ( match == 0 && i >= 0 ) 814 *dup = ix[i]; 815 816 /* For sorted attributes, put the values in index order */ 817 if ( rc == LDAP_SUCCESS && match && 818 ( ad->ad_type->sat_flags & SLAP_AT_SORTED_VAL )) { 819 BerVarray tmpv = slap_sl_malloc( sizeof( struct berval ) * nvals, ctx ); 820 for ( i = 0; i<nvals; i++ ) 821 tmpv[i] = cv[ix[i]]; 822 for ( i = 0; i<nvals; i++ ) 823 cv[i] = tmpv[i]; 824 /* Check if the non-normalized array needs to move too */ 825 if ( is_norm ) { 826 cv = ml->sml_values; 827 for ( i = 0; i<nvals; i++ ) 828 tmpv[i] = cv[ix[i]]; 829 for ( i = 0; i<nvals; i++ ) 830 cv[i] = tmpv[i]; 831 } 832 slap_sl_free( tmpv, ctx ); 833 } 834 835 slap_sl_free( ix, ctx ); 836 837 if ( rc != LDAP_SUCCESS ) { 838 return rc; 839 } else if ( match == 0 ) { 840 /* value exists already */ 841 assert( i >= 0 ); 842 assert( i < nvals ); 843 return LDAP_TYPE_OR_VALUE_EXISTS; 844 } 845 return LDAP_SUCCESS; 846} 847 848/* Enter with bv->bv_len = sizeof buffer, returns with 849 * actual length of string 850 */ 851void slap_timestamp( time_t *tm, struct berval *bv ) 852{ 853 struct tm ltm; 854 855 ldap_pvt_gmtime( tm, <m ); 856 857 bv->bv_len = lutil_gentime( bv->bv_val, bv->bv_len, <m ); 858} 859 860/* Called for all modify and modrdn ops. If the current op was replicated 861 * from elsewhere, all of the attrs should already be present. 862 */ 863void slap_mods_opattrs( 864 Operation *op, 865 Modifications **modsp, 866 int manage_ctxcsn ) 867{ 868 struct berval name, timestamp, csn = BER_BVNULL; 869 struct berval nname; 870 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 871 char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ]; 872 Modifications *mod, **modtail, *modlast; 873 int gotcsn = 0, gotmname = 0, gotmtime = 0; 874 875 if ( SLAP_LASTMOD( op->o_bd ) && !op->orm_no_opattrs ) { 876 char *ptr; 877 timestamp.bv_val = timebuf; 878 for ( modtail = modsp; *modtail; modtail = &(*modtail)->sml_next ) { 879 if ( (*modtail)->sml_op != LDAP_MOD_ADD && 880 (*modtail)->sml_op != SLAP_MOD_SOFTADD && 881 (*modtail)->sml_op != LDAP_MOD_REPLACE ) 882 { 883 continue; 884 } 885 886 if ( (*modtail)->sml_desc == slap_schema.si_ad_entryCSN ) 887 { 888 csn = (*modtail)->sml_values[0]; 889 gotcsn = 1; 890 891 } else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifiersName ) 892 { 893 gotmname = 1; 894 895 } else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifyTimestamp ) 896 { 897 gotmtime = 1; 898 } 899 } 900 901 if ( BER_BVISEMPTY( &op->o_csn )) { 902 if ( !gotcsn ) { 903 csn.bv_val = csnbuf; 904 csn.bv_len = sizeof( csnbuf ); 905 slap_get_csn( op, &csn, manage_ctxcsn ); 906 907 } else { 908 if ( manage_ctxcsn ) { 909 slap_queue_csn( op, &csn ); 910 } 911 } 912 913 } else { 914 csn = op->o_csn; 915 } 916 917 ptr = ber_bvchr( &csn, '#' ); 918 if ( ptr ) { 919 timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ"); 920 AC_MEMCPY( timebuf, csn.bv_val, timestamp.bv_len ); 921 timebuf[timestamp.bv_len-1] = 'Z'; 922 timebuf[timestamp.bv_len] = '\0'; 923 924 } else { 925 time_t now = slap_get_time(); 926 927 timestamp.bv_len = sizeof(timebuf); 928 929 slap_timestamp( &now, ×tamp ); 930 } 931 932 if ( BER_BVISEMPTY( &op->o_dn ) ) { 933 BER_BVSTR( &name, SLAPD_ANONYMOUS ); 934 nname = name; 935 936 } else { 937 name = op->o_dn; 938 nname = op->o_ndn; 939 } 940 941 if ( !gotcsn ) { 942 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 943 mod->sml_op = LDAP_MOD_REPLACE; 944 mod->sml_flags = SLAP_MOD_INTERNAL; 945 mod->sml_next = NULL; 946 BER_BVZERO( &mod->sml_type ); 947 mod->sml_desc = slap_schema.si_ad_entryCSN; 948 mod->sml_numvals = 1; 949 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 950 ber_dupbv( &mod->sml_values[0], &csn ); 951 BER_BVZERO( &mod->sml_values[1] ); 952 assert( !BER_BVISNULL( &mod->sml_values[0] ) ); 953 mod->sml_nvalues = NULL; 954 *modtail = mod; 955 modlast = mod; 956 modtail = &mod->sml_next; 957 } 958 959 if ( !gotmname ) { 960 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 961 mod->sml_op = LDAP_MOD_REPLACE; 962 mod->sml_flags = SLAP_MOD_INTERNAL; 963 mod->sml_next = NULL; 964 BER_BVZERO( &mod->sml_type ); 965 mod->sml_desc = slap_schema.si_ad_modifiersName; 966 mod->sml_numvals = 1; 967 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 968 ber_dupbv( &mod->sml_values[0], &name ); 969 BER_BVZERO( &mod->sml_values[1] ); 970 assert( !BER_BVISNULL( &mod->sml_values[0] ) ); 971 mod->sml_nvalues = 972 (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 973 ber_dupbv( &mod->sml_nvalues[0], &nname ); 974 BER_BVZERO( &mod->sml_nvalues[1] ); 975 assert( !BER_BVISNULL( &mod->sml_nvalues[0] ) ); 976 *modtail = mod; 977 modtail = &mod->sml_next; 978 } 979 980 if ( !gotmtime ) { 981 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 982 mod->sml_op = LDAP_MOD_REPLACE; 983 mod->sml_flags = SLAP_MOD_INTERNAL; 984 mod->sml_next = NULL; 985 BER_BVZERO( &mod->sml_type ); 986 mod->sml_desc = slap_schema.si_ad_modifyTimestamp; 987 mod->sml_numvals = 1; 988 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 989 ber_dupbv( &mod->sml_values[0], ×tamp ); 990 BER_BVZERO( &mod->sml_values[1] ); 991 assert( !BER_BVISNULL( &mod->sml_values[0] ) ); 992 mod->sml_nvalues = NULL; 993 *modtail = mod; 994 modtail = &mod->sml_next; 995 } 996 } 997} 998 999int 1000slap_parse_modlist( 1001 Operation *op, 1002 SlapReply *rs, 1003 BerElement *ber, 1004 req_modify_s *ms ) 1005{ 1006 ber_tag_t tag; 1007 ber_len_t len; 1008 char *last; 1009 Modifications **modtail = &ms->rs_mods.rs_modlist; 1010 1011 ms->rs_mods.rs_modlist = NULL; 1012 ms->rs_increment = 0; 1013 1014 rs->sr_err = LDAP_SUCCESS; 1015 1016 /* collect modifications & save for later */ 1017 for ( tag = ber_first_element( ber, &len, &last ); 1018 tag != LBER_DEFAULT; 1019 tag = ber_next_element( ber, &len, last ) ) 1020 { 1021 ber_int_t mop; 1022 Modifications tmp, *mod; 1023 1024 tmp.sml_nvalues = NULL; 1025 1026 if ( ber_scanf( ber, "{e{m[W]}}", &mop, 1027 &tmp.sml_type, &tmp.sml_values ) == LBER_ERROR ) 1028 { 1029 rs->sr_text = "decoding modlist error"; 1030 rs->sr_err = LDAP_PROTOCOL_ERROR; 1031 goto done; 1032 } 1033 1034 mod = (Modifications *) ch_malloc( sizeof(Modifications) ); 1035 mod->sml_op = mop; 1036 mod->sml_flags = 0; 1037 mod->sml_type = tmp.sml_type; 1038 mod->sml_values = tmp.sml_values; 1039 mod->sml_nvalues = NULL; 1040 mod->sml_desc = NULL; 1041 mod->sml_next = NULL; 1042 *modtail = mod; 1043 1044 switch( mop ) { 1045 case LDAP_MOD_ADD: 1046 if ( mod->sml_values == NULL ) { 1047 rs->sr_text = "modify/add operation requires values"; 1048 rs->sr_err = LDAP_PROTOCOL_ERROR; 1049 goto done; 1050 } 1051 1052 /* fall through */ 1053 1054 case LDAP_MOD_DELETE: 1055 case LDAP_MOD_REPLACE: 1056 break; 1057 1058 case LDAP_MOD_INCREMENT: 1059 if( op->o_protocol >= LDAP_VERSION3 ) { 1060 ms->rs_increment++; 1061 if ( mod->sml_values == NULL ) { 1062 rs->sr_text = "modify/increment operation requires value"; 1063 rs->sr_err = LDAP_PROTOCOL_ERROR; 1064 goto done; 1065 } 1066 1067 if ( !BER_BVISNULL( &mod->sml_values[ 1 ] ) ) { 1068 rs->sr_text = "modify/increment operation requires single value"; 1069 rs->sr_err = LDAP_PROTOCOL_ERROR; 1070 goto done; 1071 } 1072 1073 break; 1074 } 1075 /* fall thru */ 1076 1077 default: 1078 rs->sr_text = "unrecognized modify operation"; 1079 rs->sr_err = LDAP_PROTOCOL_ERROR; 1080 goto done; 1081 } 1082 1083 modtail = &mod->sml_next; 1084 } 1085 *modtail = NULL; 1086 1087done: 1088 if ( rs->sr_err != LDAP_SUCCESS ) { 1089 slap_mods_free( ms->rs_mods.rs_modlist, 1 ); 1090 ms->rs_mods.rs_modlist = NULL; 1091 ms->rs_increment = 0; 1092 } 1093 1094 return rs->sr_err; 1095} 1096 1097