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