1/* $NetBSD: value.c,v 1.3 2021/08/14 16:14:58 christos Exp $ */ 2 3/* value.c - routines for dealing with values */ 4/* $OpenLDAP$ */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2021 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18/* 19 * Copyright (c) 1995 Regents of the University of Michigan. 20 * All rights reserved. 21 * 22 * Redistribution and use in source and binary forms are permitted 23 * provided that this notice is preserved and that due credit is given 24 * to the University of Michigan at Ann Arbor. The name of the University 25 * may not be used to endorse or promote products derived from this 26 * software without specific prior written permission. This software 27 * is provided ``as is'' without express or implied warranty. 28 */ 29 30#include <sys/cdefs.h> 31__RCSID("$NetBSD: value.c,v 1.3 2021/08/14 16:14:58 christos Exp $"); 32 33#include "portable.h" 34 35#include <stdio.h> 36 37#include <ac/ctype.h> 38#include <ac/socket.h> 39#include <ac/string.h> 40#include <ac/time.h> 41 42#include <sys/stat.h> 43 44#include "slap.h" 45 46int 47value_add( 48 BerVarray *vals, 49 BerVarray addvals ) 50{ 51 int n, nn = 0; 52 BerVarray v2; 53 54 if ( addvals != NULL ) { 55 for ( ; !BER_BVISNULL( &addvals[nn] ); nn++ ) 56 ; /* NULL */ 57 } 58 59 if ( *vals == NULL ) { 60 *vals = (BerVarray) SLAP_MALLOC( (nn + 1) 61 * sizeof(struct berval) ); 62 if( *vals == NULL ) { 63 Debug(LDAP_DEBUG_TRACE, 64 "value_add: SLAP_MALLOC failed.\n" ); 65 return LBER_ERROR_MEMORY; 66 } 67 n = 0; 68 69 } else { 70 for ( n = 0; !BER_BVISNULL( &(*vals)[n] ); n++ ) { 71 ; /* Empty */ 72 } 73 *vals = (BerVarray) SLAP_REALLOC( (char *) *vals, 74 (n + nn + 1) * sizeof(struct berval) ); 75 if( *vals == NULL ) { 76 Debug(LDAP_DEBUG_TRACE, 77 "value_add: SLAP_MALLOC failed.\n" ); 78 return LBER_ERROR_MEMORY; 79 } 80 } 81 82 v2 = &(*vals)[n]; 83 for ( n = 0 ; n < nn; v2++, addvals++ ) { 84 ber_dupbv( v2, addvals ); 85 if ( BER_BVISNULL( v2 ) ) break; 86 } 87 BER_BVZERO( v2 ); 88 89 return LDAP_SUCCESS; 90} 91 92int 93value_add_one( 94 BerVarray *vals, 95 struct berval *addval ) 96{ 97 int n; 98 BerVarray v2; 99 100 if ( *vals == NULL ) { 101 *vals = (BerVarray) SLAP_MALLOC( 2 * sizeof(struct berval) ); 102 if( *vals == NULL ) { 103 Debug(LDAP_DEBUG_TRACE, 104 "value_add_one: SLAP_MALLOC failed.\n" ); 105 return LBER_ERROR_MEMORY; 106 } 107 n = 0; 108 109 } else { 110 for ( n = 0; !BER_BVISNULL( &(*vals)[n] ); n++ ) { 111 ; /* Empty */ 112 } 113 *vals = (BerVarray) SLAP_REALLOC( (char *) *vals, 114 (n + 2) * sizeof(struct berval) ); 115 if( *vals == NULL ) { 116 Debug(LDAP_DEBUG_TRACE, 117 "value_add_one: SLAP_MALLOC failed.\n" ); 118 return LBER_ERROR_MEMORY; 119 } 120 } 121 122 v2 = &(*vals)[n]; 123 ber_dupbv(v2, addval); 124 125 v2++; 126 BER_BVZERO( v2 ); 127 128 return LDAP_SUCCESS; 129} 130 131int asserted_value_validate_normalize( 132 AttributeDescription *ad, 133 MatchingRule *mr, 134 unsigned usage, 135 struct berval *in, 136 struct berval *out, 137 const char ** text, 138 void *ctx ) 139{ 140 int rc; 141 struct berval pval; 142 pval.bv_val = NULL; 143 144 /* we expect the value to be in the assertion syntax */ 145 assert( !SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) ); 146 147 if( mr == NULL ) { 148 *text = "inappropriate matching request"; 149 return LDAP_INAPPROPRIATE_MATCHING; 150 } 151 152 if( !mr->smr_match ) { 153 *text = "requested matching rule not supported"; 154 return LDAP_INAPPROPRIATE_MATCHING; 155 } 156 157 if( mr->smr_syntax->ssyn_pretty ) { 158 rc = (mr->smr_syntax->ssyn_pretty)( mr->smr_syntax, in, &pval, ctx ); 159 in = &pval; 160 161 } else if ( mr->smr_syntax->ssyn_validate ) { 162 rc = (mr->smr_syntax->ssyn_validate)( mr->smr_syntax, in ); 163 164 } else { 165 *text = "inappropriate matching request"; 166 return LDAP_INAPPROPRIATE_MATCHING; 167 } 168 169 if( rc != LDAP_SUCCESS ) { 170 *text = "value does not conform to assertion syntax"; 171 return LDAP_INVALID_SYNTAX; 172 } 173 174 if( mr->smr_normalize ) { 175 rc = (mr->smr_normalize)( 176 usage|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, 177 ad ? ad->ad_type->sat_syntax : NULL, 178 mr, in, out, ctx ); 179 180 if( pval.bv_val ) ber_memfree_x( pval.bv_val, ctx ); 181 182 if( rc != LDAP_SUCCESS ) { 183 *text = "unable to normalize value for matching"; 184 return LDAP_INVALID_SYNTAX; 185 } 186 187 } else if ( pval.bv_val != NULL ) { 188 *out = pval; 189 190 } else { 191 ber_dupbv_x( out, in, ctx ); 192 } 193 194 return LDAP_SUCCESS; 195} 196 197int 198value_match( 199 int *match, 200 AttributeDescription *ad, 201 MatchingRule *mr, 202 unsigned flags, 203 struct berval *v1, /* stored value */ 204 void *v2, /* assertion */ 205 const char ** text ) 206{ 207 int rc; 208 209 assert( mr != NULL ); 210 211 if( !mr->smr_match ) { 212 return LDAP_INAPPROPRIATE_MATCHING; 213 } 214 215 rc = (mr->smr_match)( match, flags, 216 ad->ad_type->sat_syntax, mr, v1, v2 ); 217 218 return rc; 219} 220 221int value_find_ex( 222 AttributeDescription *ad, 223 unsigned flags, 224 BerVarray vals, 225 struct berval *val, 226 void *ctx ) 227{ 228 int i; 229 int rc; 230 struct berval nval = BER_BVNULL; 231 MatchingRule *mr = ad->ad_type->sat_equality; 232 233 if( mr == NULL || !mr->smr_match ) { 234 return LDAP_INAPPROPRIATE_MATCHING; 235 } 236 237 assert( SLAP_IS_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH( flags ) != 0 ); 238 239 if( !SLAP_IS_MR_ASSERTED_VALUE_NORMALIZED_MATCH( flags ) && 240 mr->smr_normalize ) 241 { 242 rc = (mr->smr_normalize)( 243 flags & (SLAP_MR_TYPE_MASK|SLAP_MR_SUBTYPE_MASK|SLAP_MR_VALUE_OF_SYNTAX), 244 ad->ad_type->sat_syntax, 245 mr, val, &nval, ctx ); 246 247 if( rc != LDAP_SUCCESS ) { 248 return LDAP_INVALID_SYNTAX; 249 } 250 } 251 252 for ( i = 0; vals[i].bv_val != NULL; i++ ) { 253 int match; 254 const char *text; 255 256 rc = value_match( &match, ad, mr, flags, 257 &vals[i], nval.bv_val == NULL ? val : &nval, &text ); 258 259 if( rc == LDAP_SUCCESS && match == 0 ) { 260 slap_sl_free( nval.bv_val, ctx ); 261 return rc; 262 } 263 } 264 265 slap_sl_free( nval.bv_val, ctx ); 266 return LDAP_NO_SUCH_ATTRIBUTE; 267} 268 269/* assign new indexes to an attribute's ordered values */ 270void 271ordered_value_renumber( Attribute *a ) 272{ 273 char *ptr, ibuf[64]; /* many digits */ 274 struct berval ibv, tmp, vtmp; 275 unsigned i; 276 277 ibv.bv_val = ibuf; 278 279 for (i=0; i<a->a_numvals; i++) { 280 ibv.bv_len = sprintf(ibv.bv_val, "{%u}", i); 281 vtmp = a->a_vals[i]; 282 if ( vtmp.bv_val[0] == '{' ) { 283 ptr = ber_bvchr(&vtmp, '}'); 284 assert( ptr != NULL ); 285 ++ptr; 286 vtmp.bv_len -= ptr - vtmp.bv_val; 287 vtmp.bv_val = ptr; 288 } 289 tmp.bv_len = ibv.bv_len + vtmp.bv_len; 290 tmp.bv_val = ch_malloc( tmp.bv_len + 1 ); 291 strcpy( tmp.bv_val, ibv.bv_val ); 292 AC_MEMCPY( tmp.bv_val + ibv.bv_len, vtmp.bv_val, vtmp.bv_len ); 293 tmp.bv_val[tmp.bv_len] = '\0'; 294 ch_free( a->a_vals[i].bv_val ); 295 a->a_vals[i] = tmp; 296 297 if ( a->a_nvals && a->a_nvals != a->a_vals ) { 298 vtmp = a->a_nvals[i]; 299 if ( vtmp.bv_val[0] == '{' ) { 300 ptr = ber_bvchr(&vtmp, '}'); 301 assert( ptr != NULL ); 302 ++ptr; 303 vtmp.bv_len -= ptr - vtmp.bv_val; 304 vtmp.bv_val = ptr; 305 } 306 tmp.bv_len = ibv.bv_len + vtmp.bv_len; 307 tmp.bv_val = ch_malloc( tmp.bv_len + 1 ); 308 strcpy( tmp.bv_val, ibv.bv_val ); 309 AC_MEMCPY( tmp.bv_val + ibv.bv_len, vtmp.bv_val, vtmp.bv_len ); 310 tmp.bv_val[tmp.bv_len] = '\0'; 311 ch_free( a->a_nvals[i].bv_val ); 312 a->a_nvals[i] = tmp; 313 } 314 } 315} 316 317/* Sort the values in an X-ORDERED VALUES attribute. 318 * If the values have no index, index them in their given order. 319 * If the values have indexes, sort them. 320 * If some are indexed and some are not, return Error. 321 */ 322int 323ordered_value_sort( Attribute *a, int do_renumber ) 324{ 325 int i, vals; 326 int index = 0, noindex = 0, renumber = 0, gotnvals = 0; 327 struct berval tmp; 328 329 if ( a->a_nvals && a->a_nvals != a->a_vals ) 330 gotnvals = 1; 331 332 /* count attrs, look for index */ 333 for (i=0; a->a_vals[i].bv_val; i++) { 334 if ( a->a_vals[i].bv_val[0] == '{' ) { 335 char *ptr; 336 index = 1; 337 ptr = ber_bvchr( &a->a_vals[i], '}' ); 338 if ( !ptr ) 339 return LDAP_INVALID_SYNTAX; 340 if ( noindex ) 341 return LDAP_INVALID_SYNTAX; 342 } else { 343 noindex = 1; 344 if ( index ) 345 return LDAP_INVALID_SYNTAX; 346 } 347 } 348 vals = i; 349 350 /* If values have indexes, sort the values */ 351 if ( index ) { 352 int *indexes, j, idx; 353 struct berval ntmp; 354 355#if 0 356 /* Strip index from normalized values */ 357 if ( !a->a_nvals || a->a_vals == a->a_nvals ) { 358 a->a_nvals = ch_malloc( (vals+1)*sizeof(struct berval)); 359 BER_BVZERO(a->a_nvals+vals); 360 for ( i=0; i<vals; i++ ) { 361 char *ptr = ber_bvchr(&a->a_vals[i], '}') + 1; 362 a->a_nvals[i].bv_len = a->a_vals[i].bv_len - 363 (ptr - a->a_vals[i].bv_val); 364 a->a_nvals[i].bv_val = ch_malloc( a->a_nvals[i].bv_len + 1); 365 strcpy(a->a_nvals[i].bv_val, ptr ); 366 } 367 } else { 368 for ( i=0; i<vals; i++ ) { 369 char *ptr = ber_bvchr(&a->a_nvals[i], '}') + 1; 370 a->a_nvals[i].bv_len -= ptr - a->a_nvals[i].bv_val; 371 strcpy(a->a_nvals[i].bv_val, ptr); 372 } 373 } 374#endif 375 376 indexes = ch_malloc( vals * sizeof(int) ); 377 for ( i=0; i<vals; i++) { 378 char *ptr; 379 indexes[i] = strtol(a->a_vals[i].bv_val+1, &ptr, 0); 380 if ( *ptr != '}' ) { 381 ch_free( indexes ); 382 return LDAP_INVALID_SYNTAX; 383 } 384 } 385 386 /* Insertion sort */ 387 for ( i=1; i<vals; i++ ) { 388 idx = indexes[i]; 389 tmp = a->a_vals[i]; 390 if ( gotnvals ) ntmp = a->a_nvals[i]; 391 j = i; 392 while ((j > 0) && (indexes[j-1] > idx)) { 393 indexes[j] = indexes[j-1]; 394 a->a_vals[j] = a->a_vals[j-1]; 395 if ( gotnvals ) a->a_nvals[j] = a->a_nvals[j-1]; 396 j--; 397 } 398 indexes[j] = idx; 399 a->a_vals[j] = tmp; 400 if ( gotnvals ) a->a_nvals[j] = ntmp; 401 } 402 403 /* If range is not contiguous, must renumber */ 404 if ( indexes[0] != 0 || indexes[vals-1] != vals-1 ) { 405 renumber = 1; 406 } 407 ch_free( indexes ); 408 } else { 409 renumber = 1; 410 } 411 412 if ( do_renumber && renumber ) 413 ordered_value_renumber( a ); 414 415 return 0; 416} 417 418/* 419 * wrapper for validate function 420 * uses the validate function of the syntax after removing 421 * the index, if allowed and present 422 */ 423int 424ordered_value_validate( 425 AttributeDescription *ad, 426 struct berval *in, 427 int mop ) 428{ 429 struct berval bv = *in; 430 431 assert( ad->ad_type->sat_syntax != NULL ); 432 assert( ad->ad_type->sat_syntax->ssyn_validate != NULL ); 433 434 if ( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) { 435 436 /* Skip past the assertion index */ 437 if ( bv.bv_val[0] == '{' ) { 438 char *ptr; 439 440 ptr = ber_bvchr( &bv, '}' ); 441 if ( ptr != NULL ) { 442 struct berval ns; 443 444 ns.bv_val = bv.bv_val + 1; 445 ns.bv_len = ptr - ns.bv_val; 446 447 if ( numericStringValidate( NULL, &ns ) == LDAP_SUCCESS ) { 448 ptr++; 449 bv.bv_len -= ptr - bv.bv_val; 450 bv.bv_val = ptr; 451 in = &bv; 452 /* If deleting by index, just succeed */ 453 if ( mop == LDAP_MOD_DELETE && BER_BVISEMPTY( &bv ) ) { 454 return LDAP_SUCCESS; 455 } 456 } 457 } 458 } 459 } 460 461 return ad->ad_type->sat_syntax->ssyn_validate( ad->ad_type->sat_syntax, in ); 462} 463 464/* 465 * wrapper for pretty function 466 * uses the pretty function of the syntax after removing 467 * the index, if allowed and present; in case, it's prepended 468 * to the pretty value 469 */ 470int 471ordered_value_pretty( 472 AttributeDescription *ad, 473 struct berval *val, 474 struct berval *out, 475 void *ctx ) 476{ 477 struct berval bv, 478 idx = BER_BVNULL; 479 int rc; 480 481 assert( ad->ad_type->sat_syntax != NULL ); 482 assert( ad->ad_type->sat_syntax->ssyn_pretty != NULL ); 483 assert( val != NULL ); 484 assert( out != NULL ); 485 486 bv = *val; 487 488 if ( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) { 489 490 /* Skip past the assertion index */ 491 if ( bv.bv_val[0] == '{' ) { 492 char *ptr; 493 494 ptr = ber_bvchr( &bv, '}' ); 495 if ( ptr != NULL ) { 496 struct berval ns; 497 498 ns.bv_val = bv.bv_val + 1; 499 ns.bv_len = ptr - ns.bv_val; 500 501 if ( numericStringValidate( NULL, &ns ) == LDAP_SUCCESS ) { 502 ptr++; 503 504 idx = bv; 505 idx.bv_len = ptr - bv.bv_val; 506 507 bv.bv_len -= idx.bv_len; 508 bv.bv_val = ptr; 509 510 val = &bv; 511 } 512 } 513 } 514 } 515 516 rc = ad->ad_type->sat_syntax->ssyn_pretty( ad->ad_type->sat_syntax, val, out, ctx ); 517 518 if ( rc == LDAP_SUCCESS && !BER_BVISNULL( &idx ) ) { 519 bv = *out; 520 521 out->bv_len = idx.bv_len + bv.bv_len; 522 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx ); 523 524 AC_MEMCPY( out->bv_val, idx.bv_val, idx.bv_len ); 525 AC_MEMCPY( &out->bv_val[ idx.bv_len ], bv.bv_val, bv.bv_len + 1 ); 526 527 ber_memfree_x( bv.bv_val, ctx ); 528 } 529 530 return rc; 531} 532 533/* 534 * wrapper for normalize function 535 * uses the normalize function of the attribute description equality rule 536 * after removing the index, if allowed and present; in case, it's 537 * prepended to the value 538 */ 539int 540ordered_value_normalize( 541 slap_mask_t usage, 542 AttributeDescription *ad, 543 MatchingRule *mr, 544 struct berval *val, 545 struct berval *normalized, 546 void *ctx ) 547{ 548 struct berval bv, 549 idx = BER_BVNULL; 550 int rc; 551 552 assert( ad->ad_type->sat_equality != NULL ); 553 assert( ad->ad_type->sat_equality->smr_normalize != NULL ); 554 assert( val != NULL ); 555 assert( normalized != NULL ); 556 557 bv = *val; 558 559 if ( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) { 560 561 /* Skip past the assertion index */ 562 if ( bv.bv_val[ 0 ] == '{' ) { 563 char *ptr; 564 565 ptr = ber_bvchr( &bv, '}' ); 566 if ( ptr != NULL ) { 567 struct berval ns; 568 569 ns.bv_val = bv.bv_val + 1; 570 ns.bv_len = ptr - ns.bv_val; 571 572 if ( numericStringValidate( NULL, &ns ) == LDAP_SUCCESS ) { 573 ptr++; 574 575 idx = bv; 576 idx.bv_len = ptr - bv.bv_val; 577 578 bv.bv_len -= idx.bv_len; 579 bv.bv_val = ptr; 580 581 /* validator will already prevent this for Adds */ 582 if ( BER_BVISEMPTY( &bv )) { 583 ber_dupbv_x( normalized, &idx, ctx ); 584 return LDAP_SUCCESS; 585 } 586 val = &bv; 587 } 588 } 589 } 590 } 591 592 rc = ad->ad_type->sat_equality->smr_normalize( usage, 593 ad->ad_type->sat_syntax, mr, val, normalized, ctx ); 594 595 if ( rc == LDAP_SUCCESS && !BER_BVISNULL( &idx ) ) { 596 bv = *normalized; 597 598 normalized->bv_len = idx.bv_len + bv.bv_len; 599 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx ); 600 601 AC_MEMCPY( normalized->bv_val, idx.bv_val, idx.bv_len ); 602 AC_MEMCPY( &normalized->bv_val[ idx.bv_len ], bv.bv_val, bv.bv_len + 1 ); 603 604 ber_memfree_x( bv.bv_val, ctx ); 605 } 606 607 return rc; 608} 609 610/* A wrapper for value match, handles Equality matches for attributes 611 * with ordered values. 612 */ 613int 614ordered_value_match( 615 int *match, 616 AttributeDescription *ad, 617 MatchingRule *mr, 618 unsigned flags, 619 struct berval *v1, /* stored value */ 620 struct berval *v2, /* assertion */ 621 const char ** text ) 622{ 623 struct berval bv1, bv2; 624 625 /* X-ORDERED VALUES equality matching: 626 * If (SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX) that means we are 627 * comparing two attribute values. In this case, we want to ignore 628 * the ordering index of both values, we just want to know if their 629 * main values are equal. 630 * 631 * If (SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX) then we are comparing 632 * an assertion against an attribute value. 633 * If the assertion has no index, the index of the value is ignored. 634 * If the assertion has only an index, the remainder of the value is 635 * ignored. 636 * If the assertion has index and value, both are compared. 637 */ 638 if ( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) { 639 char *ptr; 640 struct berval ns1 = BER_BVNULL, ns2 = BER_BVNULL; 641 642 bv1 = *v1; 643 bv2 = *v2; 644 645 /* Skip past the assertion index */ 646 if ( bv2.bv_val[0] == '{' ) { 647 ptr = ber_bvchr( &bv2, '}' ); 648 if ( ptr != NULL ) { 649 ns2.bv_val = bv2.bv_val + 1; 650 ns2.bv_len = ptr - ns2.bv_val; 651 652 if ( numericStringValidate( NULL, &ns2 ) == LDAP_SUCCESS ) { 653 ptr++; 654 bv2.bv_len -= ptr - bv2.bv_val; 655 bv2.bv_val = ptr; 656 v2 = &bv2; 657 } 658 } 659 } 660 661 /* Skip past the attribute index */ 662 if ( bv1.bv_val[0] == '{' ) { 663 ptr = ber_bvchr( &bv1, '}' ); 664 if ( ptr != NULL ) { 665 ns1.bv_val = bv1.bv_val + 1; 666 ns1.bv_len = ptr - ns1.bv_val; 667 668 if ( numericStringValidate( NULL, &ns1 ) == LDAP_SUCCESS ) { 669 ptr++; 670 bv1.bv_len -= ptr - bv1.bv_val; 671 bv1.bv_val = ptr; 672 v1 = &bv1; 673 } 674 } 675 } 676 677 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( flags )) { 678 if ( !BER_BVISNULL( &ns2 ) && !BER_BVISNULL( &ns1 ) ) { 679 /* compare index values first */ 680 (void)octetStringOrderingMatch( match, 0, NULL, NULL, &ns1, &ns2 ); 681 682 /* If not equal, or we're only comparing the index, 683 * return result now. 684 */ 685 if ( *match != 0 || BER_BVISEMPTY( &bv2 ) ) { 686 return LDAP_SUCCESS; 687 } 688 } 689 } 690 691 } 692 693 if ( !mr || !mr->smr_match ) { 694 *match = ber_bvcmp( v1, v2 ); 695 return LDAP_SUCCESS; 696 } 697 698 return value_match( match, ad, mr, flags, v1, v2, text ); 699} 700 701int 702ordered_value_add( 703 Entry *e, 704 AttributeDescription *ad, 705 Attribute *a, 706 BerVarray vals, 707 BerVarray nvals 708) 709{ 710 int i, j, k, anum, vnum; 711 BerVarray new, nnew = NULL; 712 713 /* count new vals */ 714 for (i=0; !BER_BVISNULL( vals+i ); i++) ; 715 vnum = i; 716 717 if ( a ) { 718 ordered_value_sort( a, 0 ); 719 } else { 720 Attribute **ap; 721 for ( ap=&e->e_attrs; *ap; ap = &(*ap)->a_next ) ; 722 a = attr_alloc( ad ); 723 *ap = a; 724 } 725 anum = a->a_numvals; 726 727 new = ch_malloc( (anum+vnum+1) * sizeof(struct berval)); 728 729 /* sanity check: if normalized modifications come in, either 730 * no values are present or normalized existing values differ 731 * from non-normalized; if no normalized modifications come in, 732 * either no values are present or normalized existing values 733 * don't differ from non-normalized */ 734 if ( nvals != NULL ) { 735 assert( nvals != vals ); 736 assert( a->a_nvals == NULL || a->a_nvals != a->a_vals ); 737 738 } else { 739 assert( a->a_nvals == NULL || a->a_nvals == a->a_vals ); 740 } 741 742 if ( ( a->a_nvals && a->a_nvals != a->a_vals ) || nvals != NULL ) { 743 nnew = ch_malloc( (anum+vnum+1) * sizeof(struct berval)); 744 /* Shouldn't happen... */ 745 if ( !nvals ) nvals = vals; 746 } 747 if ( anum ) { 748 AC_MEMCPY( new, a->a_vals, anum * sizeof(struct berval)); 749 if ( nnew && a->a_nvals ) 750 AC_MEMCPY( nnew, a->a_nvals, anum * sizeof(struct berval)); 751 } 752 753 for (i=0; i<vnum; i++) { 754 char *next; 755 756 k = -1; 757 if ( vals[i].bv_val[0] == '{' ) { 758 /* FIXME: strtol() could go past end... */ 759 k = strtol( vals[i].bv_val + 1, &next, 0 ); 760 if ( next == vals[i].bv_val + 1 || 761 next[ 0 ] != '}' || 762 (ber_len_t) (next - vals[i].bv_val) > vals[i].bv_len ) 763 { 764 ch_free( nnew ); 765 ch_free( new ); 766 return -1; 767 } 768 if ( k > anum ) k = -1; 769 } 770 /* No index, or index is greater than current number of 771 * values, just tack onto the end 772 */ 773 if ( k < 0 ) { 774 ber_dupbv( new+anum, vals+i ); 775 if ( nnew ) ber_dupbv( nnew+anum, nvals+i ); 776 777 /* Indexed, push everything else down one and insert */ 778 } else { 779 for (j=anum; j>k; j--) { 780 new[j] = new[j-1]; 781 if ( nnew ) nnew[j] = nnew[j-1]; 782 } 783 ber_dupbv( new+k, vals+i ); 784 if ( nnew ) ber_dupbv( nnew+k, nvals+i ); 785 } 786 anum++; 787 } 788 BER_BVZERO( new+anum ); 789 ch_free( a->a_vals ); 790 a->a_vals = new; 791 if ( nnew ) { 792 BER_BVZERO( nnew+anum ); 793 ch_free( a->a_nvals ); 794 a->a_nvals = nnew; 795 } else { 796 a->a_nvals = a->a_vals; 797 } 798 799 a->a_numvals = anum; 800 ordered_value_renumber( a ); 801 802 return 0; 803} 804