1/* $NetBSD: attr.c,v 1.3 2021/08/14 16:14:58 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-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/* 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.3 2021/08/14 16:14:58 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 52typedef struct slap_list { 53 struct slap_list *next; 54} slap_list; 55static slap_list *attr_chunks; 56static Attribute *attrs_list; 57static ldap_pvt_thread_mutex_t attr_mutex; 58 59int 60attr_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 = attrs_list; 77 attrs_list = (Attribute *)(s+1); 78 79 return 0; 80} 81 82Attribute * 83attr_alloc( AttributeDescription *ad ) 84{ 85 Attribute *a; 86 87 ldap_pvt_thread_mutex_lock( &attr_mutex ); 88 if ( !attrs_list ) 89 attr_prealloc( CHUNK_SIZE ); 90 a = attrs_list; 91 attrs_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 */ 103Attribute * 104attrs_alloc( int num ) 105{ 106 Attribute *head = NULL; 107 Attribute **a; 108 109 ldap_pvt_thread_mutex_lock( &attr_mutex ); 110 for ( a = &attrs_list; *a && num > 0; a = &(*a)->a_next ) { 111 if ( !head ) 112 head = *a; 113 num--; 114 } 115 attrs_list = *a; 116 if ( num > 0 ) { 117 attr_prealloc( num > CHUNK_SIZE ? num : CHUNK_SIZE ); 118 *a = attrs_list; 119 for ( ; *a && num > 0; a = &(*a)->a_next ) { 120 if ( !head ) 121 head = *a; 122 num--; 123 } 124 attrs_list = *a; 125 } 126 *a = NULL; 127 ldap_pvt_thread_mutex_unlock( &attr_mutex ); 128 129 return head; 130} 131 132 133void 134attr_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 166void 167attr_free( Attribute *a ) 168{ 169 attr_clean( a ); 170 ldap_pvt_thread_mutex_lock( &attr_mutex ); 171 a->a_next = attrs_list; 172 attrs_list = a; 173 ldap_pvt_thread_mutex_unlock( &attr_mutex ); 174} 175 176#ifdef LDAP_COMP_MATCH 177void 178comp_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 193void 194attrs_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 = attrs_list; 213 attrs_list = b; 214 ldap_pvt_thread_mutex_unlock( &attr_mutex ); 215 } 216} 217 218static void 219attr_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 258Attribute * 259attr_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 270Attribute * 271attrs_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 294int 295attr_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 371int 372attr_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" ); 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" ); 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 462int 463attr_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 */ 503int 504attr_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 546int 547attr_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 567int 568attr_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 */ 594int 595attr_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 622int 623attr_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 650Attribute * 651attrs_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 668Attribute * 669attr_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 689int 690attr_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 709int 710attr_init( void ) 711{ 712 ldap_pvt_thread_mutex_init( &attr_mutex ); 713 return 0; 714} 715 716int 717attr_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