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