1 /* $NetBSD: attr.c,v 1.1.1.5 2014/05/28 09:58:45 tron Exp $ */ 2 3 /* attr.c - routines for dealing with attributes */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2014 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 /* Portions Copyright (c) 1995 Regents of the University of Michigan. 19 * All rights reserved. 20 * 21 * Redistribution and use in source and binary forms are permitted 22 * provided that this notice is preserved and that due credit is given 23 * to the University of Michigan at Ann Arbor. The name of the University 24 * may not be used to endorse or promote products derived from this 25 * software without specific prior written permission. This software 26 * is provided ``as is'' without express or implied warranty. 27 */ 28 29 #include "portable.h" 30 31 #include <stdio.h> 32 33 #ifdef HAVE_FCNTL_H 34 #include <fcntl.h> 35 #endif 36 37 #include <ac/ctype.h> 38 #include <ac/errno.h> 39 #include <ac/socket.h> 40 #include <ac/string.h> 41 #include <ac/time.h> 42 43 #include "slap.h" 44 45 /* 46 * Allocate in chunks, minimum of 1000 at a time. 47 */ 48 #define CHUNK_SIZE 1000 49 typedef struct slap_list { 50 struct slap_list *next; 51 } slap_list; 52 static slap_list *attr_chunks; 53 static Attribute *attr_list; 54 static ldap_pvt_thread_mutex_t attr_mutex; 55 56 int 57 attr_prealloc( int num ) 58 { 59 Attribute *a; 60 slap_list *s; 61 62 if (!num) return 0; 63 64 s = ch_calloc( 1, sizeof(slap_list) + num * sizeof(Attribute)); 65 s->next = attr_chunks; 66 attr_chunks = s; 67 68 a = (Attribute *)(s+1); 69 for ( ;num>1; num--) { 70 a->a_next = a+1; 71 a++; 72 } 73 a->a_next = attr_list; 74 attr_list = (Attribute *)(s+1); 75 76 return 0; 77 } 78 79 Attribute * 80 attr_alloc( AttributeDescription *ad ) 81 { 82 Attribute *a; 83 84 ldap_pvt_thread_mutex_lock( &attr_mutex ); 85 if ( !attr_list ) 86 attr_prealloc( CHUNK_SIZE ); 87 a = attr_list; 88 attr_list = a->a_next; 89 a->a_next = NULL; 90 ldap_pvt_thread_mutex_unlock( &attr_mutex ); 91 92 a->a_desc = ad; 93 if ( ad && ( ad->ad_type->sat_flags & SLAP_AT_SORTED_VAL )) 94 a->a_flags |= SLAP_ATTR_SORTED_VALS; 95 96 return a; 97 } 98 99 /* Return a list of num attrs */ 100 Attribute * 101 attrs_alloc( int num ) 102 { 103 Attribute *head = NULL; 104 Attribute **a; 105 106 ldap_pvt_thread_mutex_lock( &attr_mutex ); 107 for ( a = &attr_list; *a && num > 0; a = &(*a)->a_next ) { 108 if ( !head ) 109 head = *a; 110 num--; 111 } 112 attr_list = *a; 113 if ( num > 0 ) { 114 attr_prealloc( num > CHUNK_SIZE ? num : CHUNK_SIZE ); 115 *a = attr_list; 116 for ( ; *a && num > 0; a = &(*a)->a_next ) { 117 if ( !head ) 118 head = *a; 119 num--; 120 } 121 attr_list = *a; 122 } 123 *a = NULL; 124 ldap_pvt_thread_mutex_unlock( &attr_mutex ); 125 126 return head; 127 } 128 129 130 void 131 attr_clean( Attribute *a ) 132 { 133 if ( a->a_nvals && a->a_nvals != a->a_vals && 134 !( a->a_flags & SLAP_ATTR_DONT_FREE_VALS )) { 135 if ( a->a_flags & SLAP_ATTR_DONT_FREE_DATA ) { 136 free( a->a_nvals ); 137 } else { 138 ber_bvarray_free( a->a_nvals ); 139 } 140 } 141 /* a_vals may be equal to slap_dummy_bv, a static empty berval; 142 * this is used as a placeholder for attributes that do not carry 143 * values, e.g. when proxying search entries with the "attrsonly" 144 * bit set. */ 145 if ( a->a_vals != &slap_dummy_bv && 146 !( a->a_flags & SLAP_ATTR_DONT_FREE_VALS )) { 147 if ( a->a_flags & SLAP_ATTR_DONT_FREE_DATA ) { 148 free( a->a_vals ); 149 } else { 150 ber_bvarray_free( a->a_vals ); 151 } 152 } 153 a->a_desc = NULL; 154 a->a_vals = NULL; 155 a->a_nvals = NULL; 156 #ifdef LDAP_COMP_MATCH 157 a->a_comp_data = NULL; 158 #endif 159 a->a_flags = 0; 160 a->a_numvals = 0; 161 } 162 163 void 164 attr_free( Attribute *a ) 165 { 166 attr_clean( a ); 167 ldap_pvt_thread_mutex_lock( &attr_mutex ); 168 a->a_next = attr_list; 169 attr_list = a; 170 ldap_pvt_thread_mutex_unlock( &attr_mutex ); 171 } 172 173 #ifdef LDAP_COMP_MATCH 174 void 175 comp_tree_free( Attribute *a ) 176 { 177 Attribute *next; 178 179 for( ; a != NULL ; a = next ) { 180 next = a->a_next; 181 if ( component_destructor && a->a_comp_data ) { 182 if ( a->a_comp_data->cd_mem_op ) 183 component_destructor( a->a_comp_data->cd_mem_op ); 184 free ( a->a_comp_data ); 185 } 186 } 187 } 188 #endif 189 190 void 191 attrs_free( Attribute *a ) 192 { 193 if ( a ) { 194 Attribute *b = (Attribute *)0xBAD, *tail, *next; 195 196 /* save tail */ 197 tail = a; 198 do { 199 next = a->a_next; 200 attr_clean( a ); 201 a->a_next = b; 202 b = a; 203 a = next; 204 } while ( next ); 205 206 ldap_pvt_thread_mutex_lock( &attr_mutex ); 207 /* replace NULL with current attr list and let attr list 208 * start from last attribute returned to list */ 209 tail->a_next = attr_list; 210 attr_list = b; 211 ldap_pvt_thread_mutex_unlock( &attr_mutex ); 212 } 213 } 214 215 static void 216 attr_dup2( Attribute *tmp, Attribute *a ) 217 { 218 tmp->a_flags = a->a_flags & SLAP_ATTR_PERSISTENT_FLAGS; 219 if ( a->a_vals != NULL ) { 220 unsigned i, j; 221 222 tmp->a_numvals = a->a_numvals; 223 tmp->a_vals = ch_malloc( (tmp->a_numvals + 1) * sizeof(struct berval) ); 224 for ( i = 0; i < tmp->a_numvals; i++ ) { 225 ber_dupbv( &tmp->a_vals[i], &a->a_vals[i] ); 226 if ( BER_BVISNULL( &tmp->a_vals[i] ) ) break; 227 /* FIXME: error? */ 228 } 229 BER_BVZERO( &tmp->a_vals[i] ); 230 231 /* a_nvals must be non null; it may be equal to a_vals */ 232 assert( a->a_nvals != NULL ); 233 234 if ( a->a_nvals != a->a_vals ) { 235 236 tmp->a_nvals = ch_malloc( (tmp->a_numvals + 1) * sizeof(struct berval) ); 237 j = 0; 238 if ( i ) { 239 for ( ; !BER_BVISNULL( &a->a_nvals[j] ); j++ ) { 240 assert( j < i ); 241 ber_dupbv( &tmp->a_nvals[j], &a->a_nvals[j] ); 242 if ( BER_BVISNULL( &tmp->a_nvals[j] ) ) break; 243 /* FIXME: error? */ 244 } 245 assert( j == i ); 246 } 247 BER_BVZERO( &tmp->a_nvals[j] ); 248 249 } else { 250 tmp->a_nvals = tmp->a_vals; 251 } 252 } 253 } 254 255 Attribute * 256 attr_dup( Attribute *a ) 257 { 258 Attribute *tmp; 259 260 if ( a == NULL) return NULL; 261 262 tmp = attr_alloc( a->a_desc ); 263 attr_dup2( tmp, a ); 264 return tmp; 265 } 266 267 Attribute * 268 attrs_dup( Attribute *a ) 269 { 270 int i; 271 Attribute *tmp, *anew; 272 273 if( a == NULL ) return NULL; 274 275 /* count them */ 276 for( tmp=a,i=0; tmp; tmp=tmp->a_next ) { 277 i++; 278 } 279 280 anew = attrs_alloc( i ); 281 282 for( tmp=anew; a; a=a->a_next ) { 283 tmp->a_desc = a->a_desc; 284 attr_dup2( tmp, a ); 285 tmp=tmp->a_next; 286 } 287 288 return anew; 289 } 290 291 int 292 attr_valfind( 293 Attribute *a, 294 unsigned flags, 295 struct berval *val, 296 unsigned *slot, 297 void *ctx ) 298 { 299 struct berval nval = BER_BVNULL, *cval; 300 MatchingRule *mr; 301 const char *text; 302 int match = -1, rc; 303 unsigned i, n; 304 305 if ( flags & SLAP_MR_ORDERING ) 306 mr = a->a_desc->ad_type->sat_ordering; 307 else 308 mr = a->a_desc->ad_type->sat_equality; 309 310 if( !SLAP_IS_MR_ASSERTED_VALUE_NORMALIZED_MATCH( flags ) && 311 mr->smr_normalize ) 312 { 313 rc = (mr->smr_normalize)( 314 flags & (SLAP_MR_TYPE_MASK|SLAP_MR_SUBTYPE_MASK|SLAP_MR_VALUE_OF_SYNTAX), 315 a->a_desc->ad_type->sat_syntax, 316 mr, val, &nval, ctx ); 317 318 if( rc != LDAP_SUCCESS ) { 319 return LDAP_INVALID_SYNTAX; 320 } 321 cval = &nval; 322 } else { 323 cval = val; 324 } 325 326 n = a->a_numvals; 327 if ( (a->a_flags & SLAP_ATTR_SORTED_VALS) && n ) { 328 /* Binary search */ 329 unsigned base = 0; 330 331 do { 332 unsigned pivot = n >> 1; 333 i = base + pivot; 334 rc = value_match( &match, a->a_desc, mr, flags, 335 &a->a_nvals[i], cval, &text ); 336 if ( rc == LDAP_SUCCESS && match == 0 ) 337 break; 338 if ( match < 0 ) { 339 base = i+1; 340 n -= pivot+1; 341 } else { 342 n = pivot; 343 } 344 } while ( n ); 345 if ( match < 0 ) 346 i++; 347 } else { 348 /* Linear search */ 349 for ( i = 0; i < n; i++ ) { 350 const char *text; 351 352 rc = ordered_value_match( &match, a->a_desc, mr, flags, 353 &a->a_nvals[i], cval, &text ); 354 if ( rc == LDAP_SUCCESS && match == 0 ) 355 break; 356 } 357 } 358 if ( match ) 359 rc = LDAP_NO_SUCH_ATTRIBUTE; 360 if ( slot ) 361 *slot = i; 362 if ( nval.bv_val ) 363 slap_sl_free( nval.bv_val, ctx ); 364 365 return rc; 366 } 367 368 int 369 attr_valadd( 370 Attribute *a, 371 BerVarray vals, 372 BerVarray nvals, 373 int nn ) 374 { 375 int i; 376 BerVarray v2; 377 378 v2 = (BerVarray) SLAP_REALLOC( (char *) a->a_vals, 379 (a->a_numvals + nn + 1) * sizeof(struct berval) ); 380 if( v2 == NULL ) { 381 Debug(LDAP_DEBUG_TRACE, 382 "attr_valadd: SLAP_REALLOC failed.\n", 0, 0, 0 ); 383 return LBER_ERROR_MEMORY; 384 } 385 a->a_vals = v2; 386 if ( nvals ) { 387 v2 = (BerVarray) SLAP_REALLOC( (char *) a->a_nvals, 388 (a->a_numvals + nn + 1) * sizeof(struct berval) ); 389 if( v2 == NULL ) { 390 Debug(LDAP_DEBUG_TRACE, 391 "attr_valadd: SLAP_REALLOC failed.\n", 0, 0, 0 ); 392 return LBER_ERROR_MEMORY; 393 } 394 a->a_nvals = v2; 395 } else { 396 a->a_nvals = a->a_vals; 397 } 398 399 /* If sorted and old vals exist, must insert */ 400 if (( a->a_flags & SLAP_ATTR_SORTED_VALS ) && a->a_numvals ) { 401 unsigned slot; 402 int j, rc; 403 v2 = nvals ? nvals : vals; 404 for ( i = 0; i < nn; i++ ) { 405 rc = attr_valfind( a, SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX | 406 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, 407 &v2[i], &slot, NULL ); 408 if ( rc != LDAP_NO_SUCH_ATTRIBUTE ) { 409 /* should never happen */ 410 if ( rc == LDAP_SUCCESS ) 411 rc = LDAP_TYPE_OR_VALUE_EXISTS; 412 return rc; 413 } 414 for ( j = a->a_numvals; j >= (int)slot; j-- ) { 415 a->a_vals[j+1] = a->a_vals[j]; 416 if ( nvals ) 417 a->a_nvals[j+1] = a->a_nvals[j]; 418 } 419 ber_dupbv( &a->a_nvals[slot], &v2[i] ); 420 if ( nvals ) 421 ber_dupbv( &a->a_vals[slot], &vals[i] ); 422 a->a_numvals++; 423 } 424 BER_BVZERO( &a->a_vals[a->a_numvals] ); 425 if ( a->a_vals != a->a_nvals ) 426 BER_BVZERO( &a->a_nvals[a->a_numvals] ); 427 } else { 428 v2 = &a->a_vals[a->a_numvals]; 429 for ( i = 0 ; i < nn; i++ ) { 430 ber_dupbv( &v2[i], &vals[i] ); 431 if ( BER_BVISNULL( &v2[i] ) ) break; 432 } 433 BER_BVZERO( &v2[i] ); 434 435 if ( nvals ) { 436 v2 = &a->a_nvals[a->a_numvals]; 437 for ( i = 0 ; i < nn; i++ ) { 438 ber_dupbv( &v2[i], &nvals[i] ); 439 if ( BER_BVISNULL( &v2[i] ) ) break; 440 } 441 BER_BVZERO( &v2[i] ); 442 } 443 a->a_numvals += i; 444 } 445 return 0; 446 } 447 448 /* 449 * attr_merge - merge the given type and value with the list of 450 * attributes in attrs. 451 * 452 * nvals must be NULL if the attribute has no normalizer. 453 * In this case, a->a_nvals will be set equal to a->a_vals. 454 * 455 * returns 0 everything went ok 456 * -1 trouble 457 */ 458 459 int 460 attr_merge( 461 Entry *e, 462 AttributeDescription *desc, 463 BerVarray vals, 464 BerVarray nvals ) 465 { 466 int i = 0; 467 468 Attribute **a; 469 470 for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) { 471 if ( (*a)->a_desc == desc ) { 472 break; 473 } 474 } 475 476 if ( *a == NULL ) { 477 *a = attr_alloc( desc ); 478 } else { 479 /* 480 * FIXME: if the attribute already exists, the presence 481 * of nvals and the value of (*a)->a_nvals must be consistent 482 */ 483 assert( ( nvals == NULL && (*a)->a_nvals == (*a)->a_vals ) 484 || ( nvals != NULL && ( 485 ( (*a)->a_vals == NULL && (*a)->a_nvals == NULL ) 486 || ( (*a)->a_nvals != (*a)->a_vals ) ) ) ); 487 } 488 489 if ( vals != NULL ) { 490 for ( ; !BER_BVISNULL( &vals[i] ); i++ ) ; 491 } 492 return attr_valadd( *a, vals, nvals, i ); 493 } 494 495 /* 496 * if a normalization function is defined for the equality matchingRule 497 * of desc, the value is normalized and stored in nval; otherwise nval 498 * is NULL 499 */ 500 int 501 attr_normalize( 502 AttributeDescription *desc, 503 BerVarray vals, 504 BerVarray *nvalsp, 505 void *memctx ) 506 { 507 int rc = LDAP_SUCCESS; 508 BerVarray nvals = NULL; 509 510 *nvalsp = NULL; 511 512 if ( desc->ad_type->sat_equality && 513 desc->ad_type->sat_equality->smr_normalize ) 514 { 515 int i; 516 517 for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ ); 518 519 nvals = slap_sl_calloc( sizeof(struct berval), i + 1, memctx ); 520 for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ ) { 521 rc = desc->ad_type->sat_equality->smr_normalize( 522 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 523 desc->ad_type->sat_syntax, 524 desc->ad_type->sat_equality, 525 &vals[i], &nvals[i], memctx ); 526 527 if ( rc != LDAP_SUCCESS ) { 528 BER_BVZERO( &nvals[i + 1] ); 529 break; 530 } 531 } 532 BER_BVZERO( &nvals[i] ); 533 *nvalsp = nvals; 534 } 535 536 if ( rc != LDAP_SUCCESS && nvals != NULL ) { 537 ber_bvarray_free_x( nvals, memctx ); 538 } 539 540 return rc; 541 } 542 543 int 544 attr_merge_normalize( 545 Entry *e, 546 AttributeDescription *desc, 547 BerVarray vals, 548 void *memctx ) 549 { 550 BerVarray nvals = NULL; 551 int rc; 552 553 rc = attr_normalize( desc, vals, &nvals, memctx ); 554 if ( rc == LDAP_SUCCESS ) { 555 rc = attr_merge( e, desc, vals, nvals ); 556 if ( nvals != NULL ) { 557 ber_bvarray_free_x( nvals, memctx ); 558 } 559 } 560 561 return rc; 562 } 563 564 int 565 attr_merge_one( 566 Entry *e, 567 AttributeDescription *desc, 568 struct berval *val, 569 struct berval *nval ) 570 { 571 Attribute **a; 572 573 for ( a = &e->e_attrs; *a != NULL; a = &(*a)->a_next ) { 574 if ( (*a)->a_desc == desc ) { 575 break; 576 } 577 } 578 579 if ( *a == NULL ) { 580 *a = attr_alloc( desc ); 581 } 582 583 return attr_valadd( *a, val, nval, 1 ); 584 } 585 586 /* 587 * if a normalization function is defined for the equality matchingRule 588 * of desc, the value is normalized and stored in nval; otherwise nval 589 * is NULL 590 */ 591 int 592 attr_normalize_one( 593 AttributeDescription *desc, 594 struct berval *val, 595 struct berval *nval, 596 void *memctx ) 597 { 598 int rc = LDAP_SUCCESS; 599 600 BER_BVZERO( nval ); 601 602 if ( desc->ad_type->sat_equality && 603 desc->ad_type->sat_equality->smr_normalize ) 604 { 605 rc = desc->ad_type->sat_equality->smr_normalize( 606 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 607 desc->ad_type->sat_syntax, 608 desc->ad_type->sat_equality, 609 val, nval, memctx ); 610 611 if ( rc != LDAP_SUCCESS ) { 612 return rc; 613 } 614 } 615 616 return rc; 617 } 618 619 int 620 attr_merge_normalize_one( 621 Entry *e, 622 AttributeDescription *desc, 623 struct berval *val, 624 void *memctx ) 625 { 626 struct berval nval = BER_BVNULL; 627 struct berval *nvalp = NULL; 628 int rc; 629 630 rc = attr_normalize_one( desc, val, &nval, memctx ); 631 if ( rc == LDAP_SUCCESS && !BER_BVISNULL( &nval ) ) { 632 nvalp = &nval; 633 } 634 635 rc = attr_merge_one( e, desc, val, nvalp ); 636 if ( nvalp != NULL ) { 637 slap_sl_free( nval.bv_val, memctx ); 638 } 639 return rc; 640 } 641 642 /* 643 * attrs_find - find attribute(s) by AttributeDescription 644 * returns next attribute which is subtype of provided description. 645 */ 646 647 Attribute * 648 attrs_find( 649 Attribute *a, 650 AttributeDescription *desc ) 651 { 652 for ( ; a != NULL; a = a->a_next ) { 653 if ( is_ad_subtype( a->a_desc, desc ) ) { 654 return( a ); 655 } 656 } 657 658 return( NULL ); 659 } 660 661 /* 662 * attr_find - find attribute by type 663 */ 664 665 Attribute * 666 attr_find( 667 Attribute *a, 668 AttributeDescription *desc ) 669 { 670 for ( ; a != NULL; a = a->a_next ) { 671 if ( a->a_desc == desc ) { 672 return( a ); 673 } 674 } 675 676 return( NULL ); 677 } 678 679 /* 680 * attr_delete - delete the attribute type in list pointed to by attrs 681 * return 0 deleted ok 682 * 1 not found in list a 683 * -1 something bad happened 684 */ 685 686 int 687 attr_delete( 688 Attribute **attrs, 689 AttributeDescription *desc ) 690 { 691 Attribute **a; 692 693 for ( a = attrs; *a != NULL; a = &(*a)->a_next ) { 694 if ( (*a)->a_desc == desc ) { 695 Attribute *save = *a; 696 *a = (*a)->a_next; 697 attr_free( save ); 698 699 return LDAP_SUCCESS; 700 } 701 } 702 703 return LDAP_NO_SUCH_ATTRIBUTE; 704 } 705 706 int 707 attr_init( void ) 708 { 709 ldap_pvt_thread_mutex_init( &attr_mutex ); 710 return 0; 711 } 712 713 int 714 attr_destroy( void ) 715 { 716 slap_list *a; 717 718 for ( a=attr_chunks; a; a=attr_chunks ) { 719 attr_chunks = a->next; 720 free( a ); 721 } 722 ldap_pvt_thread_mutex_destroy( &attr_mutex ); 723 return 0; 724 } 725