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