1 /* $NetBSD: ad.c,v 1.1.1.6 2018/02/06 01:53:15 christos Exp $ */ 2 3 /* ad.c - routines for dealing with attribute descriptions */ 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 19 #include <sys/cdefs.h> 20 __RCSID("$NetBSD: ad.c,v 1.1.1.6 2018/02/06 01:53:15 christos Exp $"); 21 22 #include "portable.h" 23 24 #include <stdio.h> 25 26 #include <ac/ctype.h> 27 #include <ac/errno.h> 28 #include <ac/socket.h> 29 #include <ac/string.h> 30 #include <ac/time.h> 31 32 #include "slap.h" 33 #include "lutil.h" 34 35 static struct berval bv_no_attrs = BER_BVC( LDAP_NO_ATTRS ); 36 static struct berval bv_all_user_attrs = BER_BVC( "*" ); 37 static struct berval bv_all_operational_attrs = BER_BVC( "+" ); 38 39 static AttributeName anlist_no_attrs[] = { 40 { BER_BVC( LDAP_NO_ATTRS ), NULL, 0, NULL }, 41 { BER_BVNULL, NULL, 0, NULL } 42 }; 43 44 static AttributeName anlist_all_user_attributes[] = { 45 { BER_BVC( LDAP_ALL_USER_ATTRIBUTES ), NULL, 0, NULL }, 46 { BER_BVNULL, NULL, 0, NULL } 47 }; 48 49 static AttributeName anlist_all_operational_attributes[] = { 50 { BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ), NULL, 0, NULL }, 51 { BER_BVNULL, NULL, 0, NULL } 52 }; 53 54 static AttributeName anlist_all_attributes[] = { 55 { BER_BVC( LDAP_ALL_USER_ATTRIBUTES ), NULL, 0, NULL }, 56 { BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ), NULL, 0, NULL }, 57 { BER_BVNULL, NULL, 0, NULL } 58 }; 59 60 AttributeName *slap_anlist_no_attrs = anlist_no_attrs; 61 AttributeName *slap_anlist_all_user_attributes = anlist_all_user_attributes; 62 AttributeName *slap_anlist_all_operational_attributes = anlist_all_operational_attributes; 63 AttributeName *slap_anlist_all_attributes = anlist_all_attributes; 64 65 struct berval * slap_bv_no_attrs = &bv_no_attrs; 66 struct berval * slap_bv_all_user_attrs = &bv_all_user_attrs; 67 struct berval * slap_bv_all_operational_attrs = &bv_all_operational_attrs; 68 69 typedef struct Attr_option { 70 struct berval name; /* option name or prefix */ 71 int prefix; /* NAME is a tag and range prefix */ 72 } Attr_option; 73 74 static Attr_option lang_option = { BER_BVC("lang-"), 1 }; 75 76 /* Options sorted by name, and number of options */ 77 static Attr_option *options = &lang_option; 78 static int option_count = 1; 79 80 static int msad_range_hack = 0; 81 82 static int ad_count; 83 84 static Attr_option *ad_find_option_definition( const char *opt, int optlen ); 85 86 int ad_keystring( 87 struct berval *bv ) 88 { 89 ber_len_t i; 90 91 if( !AD_LEADCHAR( bv->bv_val[0] ) ) { 92 return 1; 93 } 94 95 for( i=1; i<bv->bv_len; i++ ) { 96 if( !AD_CHAR( bv->bv_val[i] )) { 97 if ( msad_range_hack && bv->bv_val[i] == '=' ) 98 continue; 99 return 1; 100 } 101 } 102 return 0; 103 } 104 105 void ad_destroy( AttributeDescription *ad ) 106 { 107 AttributeDescription *n; 108 109 for (; ad != NULL; ad = n) { 110 n = ad->ad_next; 111 ldap_memfree( ad ); 112 } 113 } 114 115 /* Is there an AttributeDescription for this type that uses these tags? */ 116 AttributeDescription * ad_find_tags( 117 AttributeType *type, 118 struct berval *tags ) 119 { 120 AttributeDescription *ad; 121 122 ldap_pvt_thread_mutex_lock( &type->sat_ad_mutex ); 123 for (ad = type->sat_ad; ad; ad=ad->ad_next) 124 { 125 if (ad->ad_tags.bv_len == tags->bv_len && 126 !strcasecmp(ad->ad_tags.bv_val, tags->bv_val)) 127 break; 128 } 129 ldap_pvt_thread_mutex_unlock( &type->sat_ad_mutex ); 130 return ad; 131 } 132 133 int slap_str2ad( 134 const char *str, 135 AttributeDescription **ad, 136 const char **text ) 137 { 138 struct berval bv; 139 bv.bv_val = (char *) str; 140 bv.bv_len = strlen( str ); 141 142 return slap_bv2ad( &bv, ad, text ); 143 } 144 145 static char *strchrlen( 146 const char *beg, 147 const char *end, 148 const char ch, 149 int *len ) 150 { 151 const char *p; 152 153 for( p=beg; *p && p < end; p++ ) { 154 if( *p == ch ) { 155 *len = p - beg; 156 return (char *) p; 157 } 158 } 159 160 *len = p - beg; 161 return NULL; 162 } 163 164 int slap_bv2ad( 165 struct berval *bv, 166 AttributeDescription **ad, 167 const char **text ) 168 { 169 int rtn = LDAP_UNDEFINED_TYPE; 170 AttributeDescription desc, *d2; 171 char *name, *options, *optn; 172 char *opt, *next; 173 int ntags; 174 int tagslen; 175 176 /* hardcoded limits for speed */ 177 #define MAX_TAGGING_OPTIONS 128 178 struct berval tags[MAX_TAGGING_OPTIONS+1]; 179 #define MAX_TAGS_LEN 1024 180 char tagbuf[MAX_TAGS_LEN]; 181 182 assert( ad != NULL ); 183 assert( *ad == NULL ); /* temporary */ 184 185 if( bv == NULL || BER_BVISNULL( bv ) || BER_BVISEMPTY( bv ) ) { 186 *text = "empty AttributeDescription"; 187 return rtn; 188 } 189 190 /* make sure description is IA5 */ 191 if( ad_keystring( bv ) ) { 192 *text = "AttributeDescription contains inappropriate characters"; 193 return rtn; 194 } 195 196 /* find valid base attribute type; parse in place */ 197 desc.ad_cname = *bv; 198 desc.ad_flags = 0; 199 BER_BVZERO( &desc.ad_tags ); 200 name = bv->bv_val; 201 options = ber_bvchr( bv, ';' ); 202 if ( options != NULL && (unsigned) ( options - name ) < bv->bv_len ) { 203 /* don't go past the end of the berval! */ 204 desc.ad_cname.bv_len = options - name; 205 } else { 206 options = NULL; 207 } 208 desc.ad_type = at_bvfind( &desc.ad_cname ); 209 if( desc.ad_type == NULL ) { 210 *text = "attribute type undefined"; 211 return rtn; 212 } 213 214 if( is_at_operational( desc.ad_type ) && options != NULL ) { 215 *text = "operational attribute with options undefined"; 216 return rtn; 217 } 218 219 /* 220 * parse options in place 221 */ 222 ntags = 0; 223 tagslen = 0; 224 optn = bv->bv_val + bv->bv_len; 225 226 for( opt=options; opt != NULL; opt=next ) { 227 int optlen; 228 opt++; 229 next = strchrlen( opt, optn, ';', &optlen ); 230 231 if( optlen == 0 ) { 232 *text = "zero length option is invalid"; 233 return rtn; 234 235 } else if ( optlen == STRLENOF("binary") && 236 strncasecmp( opt, "binary", STRLENOF("binary") ) == 0 ) 237 { 238 /* binary option */ 239 if( slap_ad_is_binary( &desc ) ) { 240 *text = "option \"binary\" specified multiple times"; 241 return rtn; 242 } 243 244 if( !slap_syntax_is_binary( desc.ad_type->sat_syntax )) { 245 /* not stored in binary, disallow option */ 246 *text = "option \"binary\" not supported with type"; 247 return rtn; 248 } 249 250 desc.ad_flags |= SLAP_DESC_BINARY; 251 continue; 252 253 } else if ( ad_find_option_definition( opt, optlen ) ) { 254 int i; 255 256 if( opt[optlen-1] == '-' || 257 ( opt[optlen-1] == '=' && msad_range_hack )) { 258 desc.ad_flags |= SLAP_DESC_TAG_RANGE; 259 } 260 261 if( ntags >= MAX_TAGGING_OPTIONS ) { 262 *text = "too many tagging options"; 263 return rtn; 264 } 265 266 /* 267 * tags should be presented in sorted order, 268 * so run the array in reverse. 269 */ 270 for( i=ntags-1; i>=0; i-- ) { 271 int rc; 272 273 rc = strncasecmp( opt, tags[i].bv_val, 274 (unsigned) optlen < tags[i].bv_len 275 ? (unsigned) optlen : tags[i].bv_len ); 276 277 if( rc == 0 && (unsigned)optlen == tags[i].bv_len ) { 278 /* duplicate (ignore) */ 279 ntags--; 280 goto done; 281 282 } else if ( rc > 0 || 283 ( rc == 0 && (unsigned)optlen > tags[i].bv_len )) 284 { 285 AC_MEMCPY( &tags[i+2], &tags[i+1], 286 (ntags-i-1)*sizeof(struct berval) ); 287 tags[i+1].bv_val = opt; 288 tags[i+1].bv_len = optlen; 289 goto done; 290 } 291 } 292 293 if( ntags ) { 294 AC_MEMCPY( &tags[1], &tags[0], 295 ntags*sizeof(struct berval) ); 296 } 297 tags[0].bv_val = opt; 298 tags[0].bv_len = optlen; 299 300 done:; 301 tagslen += optlen + 1; 302 ntags++; 303 304 } else { 305 *text = "unrecognized option"; 306 return rtn; 307 } 308 } 309 310 if( ntags > 0 ) { 311 int i; 312 313 if( tagslen > MAX_TAGS_LEN ) { 314 *text = "tagging options too long"; 315 return rtn; 316 } 317 318 desc.ad_tags.bv_val = tagbuf; 319 tagslen = 0; 320 321 for( i=0; i<ntags; i++ ) { 322 AC_MEMCPY( &desc.ad_tags.bv_val[tagslen], 323 tags[i].bv_val, tags[i].bv_len ); 324 325 tagslen += tags[i].bv_len; 326 desc.ad_tags.bv_val[tagslen++] = ';'; 327 } 328 329 desc.ad_tags.bv_val[--tagslen] = '\0'; 330 desc.ad_tags.bv_len = tagslen; 331 } 332 333 /* see if a matching description is already cached */ 334 for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) { 335 if( d2->ad_flags != desc.ad_flags ) { 336 continue; 337 } 338 if( d2->ad_tags.bv_len != desc.ad_tags.bv_len ) { 339 continue; 340 } 341 if( d2->ad_tags.bv_len == 0 ) { 342 break; 343 } 344 if( strncasecmp( d2->ad_tags.bv_val, desc.ad_tags.bv_val, 345 desc.ad_tags.bv_len ) == 0 ) 346 { 347 break; 348 } 349 } 350 351 /* Not found, add new one */ 352 while (d2 == NULL) { 353 size_t dlen = 0; 354 ldap_pvt_thread_mutex_lock( &desc.ad_type->sat_ad_mutex ); 355 /* check again now that we've locked */ 356 for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) { 357 if (d2->ad_flags != desc.ad_flags) 358 continue; 359 if (d2->ad_tags.bv_len != desc.ad_tags.bv_len) 360 continue; 361 if (d2->ad_tags.bv_len == 0) 362 break; 363 if (strncasecmp(d2->ad_tags.bv_val, desc.ad_tags.bv_val, 364 desc.ad_tags.bv_len) == 0) 365 break; 366 } 367 if (d2) { 368 ldap_pvt_thread_mutex_unlock( &desc.ad_type->sat_ad_mutex ); 369 break; 370 } 371 372 /* Allocate a single contiguous block. If there are no 373 * options, we just need space for the AttrDesc structure. 374 * Otherwise, we need to tack on the full name length + 375 * options length, + maybe tagging options length again. 376 */ 377 if (desc.ad_tags.bv_len || desc.ad_flags != SLAP_DESC_NONE) { 378 dlen = desc.ad_type->sat_cname.bv_len + 1; 379 if (desc.ad_tags.bv_len) { 380 dlen += 1 + desc.ad_tags.bv_len; 381 } 382 if ( slap_ad_is_binary( &desc ) ) { 383 dlen += 1 + STRLENOF(";binary") + desc.ad_tags.bv_len; 384 } 385 } 386 387 d2 = ch_malloc(sizeof(AttributeDescription) + dlen); 388 d2->ad_next = NULL; 389 d2->ad_type = desc.ad_type; 390 d2->ad_flags = desc.ad_flags; 391 d2->ad_cname.bv_len = desc.ad_type->sat_cname.bv_len; 392 d2->ad_tags.bv_len = desc.ad_tags.bv_len; 393 ldap_pvt_thread_mutex_lock( &ad_index_mutex ); 394 d2->ad_index = ++ad_count; 395 ldap_pvt_thread_mutex_unlock( &ad_index_mutex ); 396 397 if (dlen == 0) { 398 d2->ad_cname.bv_val = d2->ad_type->sat_cname.bv_val; 399 d2->ad_tags.bv_val = NULL; 400 } else { 401 char *cp, *op, *lp; 402 int j; 403 d2->ad_cname.bv_val = (char *)(d2+1); 404 strcpy(d2->ad_cname.bv_val, d2->ad_type->sat_cname.bv_val); 405 cp = d2->ad_cname.bv_val + d2->ad_cname.bv_len; 406 if( slap_ad_is_binary( &desc ) ) { 407 op = cp; 408 lp = NULL; 409 if( desc.ad_tags.bv_len ) { 410 lp = desc.ad_tags.bv_val; 411 while( strncasecmp(lp, "binary", STRLENOF("binary")) < 0 412 && (lp = strchr( lp, ';' )) != NULL ) 413 ++lp; 414 if( lp != desc.ad_tags.bv_val ) { 415 *cp++ = ';'; 416 j = (lp 417 ? (unsigned) (lp - desc.ad_tags.bv_val - 1) 418 : strlen( desc.ad_tags.bv_val )); 419 cp = lutil_strncopy(cp, desc.ad_tags.bv_val, j); 420 } 421 } 422 cp = lutil_strcopy(cp, ";binary"); 423 if( lp != NULL ) { 424 *cp++ = ';'; 425 cp = lutil_strcopy(cp, lp); 426 } 427 d2->ad_cname.bv_len = cp - d2->ad_cname.bv_val; 428 if( desc.ad_tags.bv_len ) 429 ldap_pvt_str2lower(op); 430 j = 1; 431 } else { 432 j = 0; 433 } 434 if( desc.ad_tags.bv_len ) { 435 lp = d2->ad_cname.bv_val + d2->ad_cname.bv_len + j; 436 if ( j == 0 ) 437 *lp++ = ';'; 438 d2->ad_tags.bv_val = lp; 439 strcpy(lp, desc.ad_tags.bv_val); 440 ldap_pvt_str2lower(lp); 441 if( j == 0 ) 442 d2->ad_cname.bv_len += 1 + desc.ad_tags.bv_len; 443 } 444 } 445 /* Add new desc to list. We always want the bare Desc with 446 * no options to stay at the head of the list, assuming 447 * that one will be used most frequently. 448 */ 449 if (desc.ad_type->sat_ad == NULL || dlen == 0) { 450 d2->ad_next = desc.ad_type->sat_ad; 451 desc.ad_type->sat_ad = d2; 452 } else { 453 d2->ad_next = desc.ad_type->sat_ad->ad_next; 454 desc.ad_type->sat_ad->ad_next = d2; 455 } 456 ldap_pvt_thread_mutex_unlock( &desc.ad_type->sat_ad_mutex ); 457 } 458 459 if( *ad == NULL ) { 460 *ad = d2; 461 } else { 462 **ad = *d2; 463 } 464 465 return LDAP_SUCCESS; 466 } 467 468 static int is_ad_subtags( 469 struct berval *subtagsbv, 470 struct berval *suptagsbv ) 471 { 472 const char *suptags, *supp, *supdelimp, *supn; 473 const char *subtags, *subp, *subdelimp, *subn; 474 int suplen, sublen; 475 476 subtags =subtagsbv->bv_val; 477 suptags =suptagsbv->bv_val; 478 subn = subtags + subtagsbv->bv_len; 479 supn = suptags + suptagsbv->bv_len; 480 481 for( supp=suptags ; supp; supp=supdelimp ) { 482 supdelimp = strchrlen( supp, supn, ';', &suplen ); 483 if( supdelimp ) supdelimp++; 484 485 for( subp=subtags ; subp; subp=subdelimp ) { 486 subdelimp = strchrlen( subp, subn, ';', &sublen ); 487 if( subdelimp ) subdelimp++; 488 489 if ( suplen > sublen 490 ? ( suplen-1 == sublen && supp[suplen-1] == '-' 491 && strncmp( supp, subp, sublen ) == 0 ) 492 : ( ( suplen == sublen || supp[suplen-1] == '-' ) 493 && strncmp( supp, subp, suplen ) == 0 ) ) 494 { 495 goto match; 496 } 497 } 498 499 return 0; 500 match:; 501 } 502 return 1; 503 } 504 505 int is_ad_subtype( 506 AttributeDescription *sub, 507 AttributeDescription *super 508 ) 509 { 510 AttributeType *a; 511 int lr; 512 513 for ( a = sub->ad_type; a; a=a->sat_sup ) { 514 if ( a == super->ad_type ) break; 515 } 516 if( !a ) { 517 return 0; 518 } 519 520 /* ensure sub does support all flags of super */ 521 lr = sub->ad_tags.bv_len ? SLAP_DESC_TAG_RANGE : 0; 522 if(( super->ad_flags & ( sub->ad_flags | lr )) != super->ad_flags ) { 523 return 0; 524 } 525 526 /* check for tagging options */ 527 if ( super->ad_tags.bv_len == 0 ) 528 return 1; 529 if ( sub->ad_tags.bv_len == 0 ) 530 return 0; 531 532 return is_ad_subtags( &sub->ad_tags, &super->ad_tags ); 533 } 534 535 int ad_inlist( 536 AttributeDescription *desc, 537 AttributeName *attrs ) 538 { 539 if (! attrs ) return 0; 540 541 for( ; attrs->an_name.bv_val; attrs++ ) { 542 AttributeType *a; 543 ObjectClass *oc; 544 545 if ( attrs->an_desc ) { 546 int lr; 547 548 if ( desc == attrs->an_desc ) { 549 return 1; 550 } 551 552 /* 553 * EXTENSION: if requested description is preceeded by 554 * a '-' character, do not match on subtypes. 555 */ 556 if ( attrs->an_name.bv_val[0] == '-' ) { 557 continue; 558 } 559 560 /* Is this a subtype of the requested attr? */ 561 for (a = desc->ad_type; a; a=a->sat_sup) { 562 if ( a == attrs->an_desc->ad_type ) 563 break; 564 } 565 if ( !a ) { 566 continue; 567 } 568 /* Does desc support all the requested flags? */ 569 lr = desc->ad_tags.bv_len ? SLAP_DESC_TAG_RANGE : 0; 570 if(( attrs->an_desc->ad_flags & (desc->ad_flags | lr)) 571 != attrs->an_desc->ad_flags ) { 572 continue; 573 } 574 /* Do the descs have compatible tags? */ 575 if ( attrs->an_desc->ad_tags.bv_len == 0 ) { 576 return 1; 577 } 578 if ( desc->ad_tags.bv_len == 0) { 579 continue; 580 } 581 if ( is_ad_subtags( &desc->ad_tags, 582 &attrs->an_desc->ad_tags ) ) { 583 return 1; 584 } 585 continue; 586 } 587 588 if ( ber_bvccmp( &attrs->an_name, '*' ) ) { 589 if ( !is_at_operational( desc->ad_type ) ) { 590 return 1; 591 } 592 continue; 593 } 594 595 if ( ber_bvccmp( &attrs->an_name, '+' ) ) { 596 if ( is_at_operational( desc->ad_type ) ) { 597 return 1; 598 } 599 continue; 600 } 601 602 /* 603 * EXTENSION: see if requested description is @objectClass 604 * if so, return attributes which the class requires/allows 605 * else if requested description is !objectClass, return 606 * attributes which the class does not require/allow 607 */ 608 if ( !( attrs->an_flags & SLAP_AN_OCINITED )) { 609 if( attrs->an_name.bv_val ) { 610 switch( attrs->an_name.bv_val[0] ) { 611 case '@': /* @objectClass */ 612 case '+': /* +objectClass (deprecated) */ 613 case '!': { /* exclude */ 614 struct berval ocname; 615 ocname.bv_len = attrs->an_name.bv_len - 1; 616 ocname.bv_val = &attrs->an_name.bv_val[1]; 617 oc = oc_bvfind( &ocname ); 618 if ( oc && attrs->an_name.bv_val[0] == '!' ) { 619 attrs->an_flags |= SLAP_AN_OCEXCLUDE; 620 } else { 621 attrs->an_flags &= ~SLAP_AN_OCEXCLUDE; 622 } 623 } break; 624 625 default: /* old (deprecated) way */ 626 oc = oc_bvfind( &attrs->an_name ); 627 } 628 attrs->an_oc = oc; 629 } 630 attrs->an_flags |= SLAP_AN_OCINITED; 631 } 632 oc = attrs->an_oc; 633 if( oc != NULL ) { 634 if ( attrs->an_flags & SLAP_AN_OCEXCLUDE ) { 635 if ( oc == slap_schema.si_oc_extensibleObject ) { 636 /* extensibleObject allows the return of anything */ 637 return 0; 638 } 639 640 if( oc->soc_required ) { 641 /* allow return of required attributes */ 642 int i; 643 644 for ( i = 0; oc->soc_required[i] != NULL; i++ ) { 645 for (a = desc->ad_type; a; a=a->sat_sup) { 646 if ( a == oc->soc_required[i] ) { 647 return 0; 648 } 649 } 650 } 651 } 652 653 if( oc->soc_allowed ) { 654 /* allow return of allowed attributes */ 655 int i; 656 for ( i = 0; oc->soc_allowed[i] != NULL; i++ ) { 657 for (a = desc->ad_type; a; a=a->sat_sup) { 658 if ( a == oc->soc_allowed[i] ) { 659 return 0; 660 } 661 } 662 } 663 } 664 665 return 1; 666 } 667 668 if ( oc == slap_schema.si_oc_extensibleObject ) { 669 /* extensibleObject allows the return of anything */ 670 return 1; 671 } 672 673 if( oc->soc_required ) { 674 /* allow return of required attributes */ 675 int i; 676 677 for ( i = 0; oc->soc_required[i] != NULL; i++ ) { 678 for (a = desc->ad_type; a; a=a->sat_sup) { 679 if ( a == oc->soc_required[i] ) { 680 return 1; 681 } 682 } 683 } 684 } 685 686 if( oc->soc_allowed ) { 687 /* allow return of allowed attributes */ 688 int i; 689 for ( i = 0; oc->soc_allowed[i] != NULL; i++ ) { 690 for (a = desc->ad_type; a; a=a->sat_sup) { 691 if ( a == oc->soc_allowed[i] ) { 692 return 1; 693 } 694 } 695 } 696 } 697 698 } else { 699 const char *text; 700 701 /* give it a chance of being retrieved by a proxy... */ 702 (void)slap_bv2undef_ad( &attrs->an_name, 703 &attrs->an_desc, &text, 704 SLAP_AD_PROXIED|SLAP_AD_NOINSERT ); 705 } 706 } 707 708 return 0; 709 } 710 711 712 int slap_str2undef_ad( 713 const char *str, 714 AttributeDescription **ad, 715 const char **text, 716 unsigned flags ) 717 { 718 struct berval bv; 719 bv.bv_val = (char *) str; 720 bv.bv_len = strlen( str ); 721 722 return slap_bv2undef_ad( &bv, ad, text, flags ); 723 } 724 725 int slap_bv2undef_ad( 726 struct berval *bv, 727 AttributeDescription **ad, 728 const char **text, 729 unsigned flags ) 730 { 731 AttributeDescription *desc; 732 AttributeType *at; 733 734 assert( ad != NULL ); 735 736 if( bv == NULL || bv->bv_len == 0 ) { 737 *text = "empty AttributeDescription"; 738 return LDAP_UNDEFINED_TYPE; 739 } 740 741 /* make sure description is IA5 */ 742 if( ad_keystring( bv ) ) { 743 *text = "AttributeDescription contains inappropriate characters"; 744 return LDAP_UNDEFINED_TYPE; 745 } 746 747 /* use the appropriate type */ 748 if ( flags & SLAP_AD_PROXIED ) { 749 at = slap_schema.si_at_proxied; 750 751 } else { 752 at = slap_schema.si_at_undefined; 753 } 754 755 for( desc = at->sat_ad; desc; desc=desc->ad_next ) { 756 if( desc->ad_cname.bv_len == bv->bv_len && 757 !strcasecmp( desc->ad_cname.bv_val, bv->bv_val ) ) 758 { 759 break; 760 } 761 } 762 763 if( !desc ) { 764 if ( flags & SLAP_AD_NOINSERT ) { 765 *text = NULL; 766 return LDAP_UNDEFINED_TYPE; 767 } 768 769 desc = ch_malloc(sizeof(AttributeDescription) + 1 + 770 bv->bv_len); 771 772 desc->ad_flags = SLAP_DESC_NONE; 773 BER_BVZERO( &desc->ad_tags ); 774 775 desc->ad_cname.bv_len = bv->bv_len; 776 desc->ad_cname.bv_val = (char *)(desc+1); 777 strncpy(desc->ad_cname.bv_val, bv->bv_val, bv->bv_len); 778 desc->ad_cname.bv_val[bv->bv_len] = '\0'; 779 780 /* canonical to upper case */ 781 ldap_pvt_str2upper( desc->ad_cname.bv_val ); 782 783 /* shouldn't we protect this for concurrency? */ 784 desc->ad_type = at; 785 desc->ad_index = 0; 786 ldap_pvt_thread_mutex_lock( &ad_undef_mutex ); 787 desc->ad_next = desc->ad_type->sat_ad; 788 desc->ad_type->sat_ad = desc; 789 ldap_pvt_thread_mutex_unlock( &ad_undef_mutex ); 790 791 Debug( LDAP_DEBUG_ANY, 792 "%s attributeDescription \"%s\" inserted.\n", 793 ( flags & SLAP_AD_PROXIED ) ? "PROXIED" : "UNKNOWN", 794 desc->ad_cname.bv_val, 0 ); 795 } 796 797 if( !*ad ) { 798 *ad = desc; 799 } else { 800 **ad = *desc; 801 } 802 803 return LDAP_SUCCESS; 804 } 805 806 AttributeDescription * 807 slap_bv2tmp_ad( 808 struct berval *bv, 809 void *memctx ) 810 { 811 AttributeDescription *ad = 812 slap_sl_mfuncs.bmf_malloc( sizeof(AttributeDescription) + 813 bv->bv_len + 1, memctx ); 814 815 ad->ad_cname.bv_val = (char *)(ad+1); 816 strncpy( ad->ad_cname.bv_val, bv->bv_val, bv->bv_len+1 ); 817 ad->ad_cname.bv_len = bv->bv_len; 818 ad->ad_flags = SLAP_DESC_TEMPORARY; 819 ad->ad_type = slap_schema.si_at_undefined; 820 821 return ad; 822 } 823 824 static int 825 undef_promote( 826 AttributeType *at, 827 char *name, 828 AttributeType *nat ) 829 { 830 AttributeDescription **u_ad, **n_ad; 831 832 /* Get to last ad on the new type */ 833 for ( n_ad = &nat->sat_ad; *n_ad; n_ad = &(*n_ad)->ad_next ) ; 834 835 for ( u_ad = &at->sat_ad; *u_ad; ) { 836 struct berval bv; 837 838 ber_str2bv( name, 0, 0, &bv ); 839 840 /* remove iff undef == name or undef == name;tag */ 841 if ( (*u_ad)->ad_cname.bv_len >= bv.bv_len 842 && strncasecmp( (*u_ad)->ad_cname.bv_val, bv.bv_val, bv.bv_len ) == 0 843 && ( (*u_ad)->ad_cname.bv_val[ bv.bv_len ] == '\0' 844 || (*u_ad)->ad_cname.bv_val[ bv.bv_len ] == ';' ) ) 845 { 846 AttributeDescription *tmp = *u_ad; 847 848 *u_ad = (*u_ad)->ad_next; 849 850 tmp->ad_type = nat; 851 tmp->ad_next = NULL; 852 /* ad_cname was contiguous, no leak here */ 853 tmp->ad_cname = nat->sat_cname; 854 ldap_pvt_thread_mutex_lock( &ad_index_mutex ); 855 tmp->ad_index = ++ad_count; 856 ldap_pvt_thread_mutex_unlock( &ad_index_mutex ); 857 *n_ad = tmp; 858 n_ad = &tmp->ad_next; 859 } else { 860 u_ad = &(*u_ad)->ad_next; 861 } 862 } 863 864 return 0; 865 } 866 867 int 868 slap_ad_undef_promote( 869 char *name, 870 AttributeType *at ) 871 { 872 int rc; 873 874 ldap_pvt_thread_mutex_lock( &ad_undef_mutex ); 875 876 rc = undef_promote( slap_schema.si_at_undefined, name, at ); 877 if ( rc == 0 ) { 878 rc = undef_promote( slap_schema.si_at_proxied, name, at ); 879 } 880 881 ldap_pvt_thread_mutex_unlock( &ad_undef_mutex ); 882 883 return rc; 884 } 885 886 int 887 an_find( 888 AttributeName *a, 889 struct berval *s 890 ) 891 { 892 if( a == NULL ) return 0; 893 894 for ( ; a->an_name.bv_val; a++ ) { 895 if ( a->an_name.bv_len != s->bv_len) continue; 896 if ( strcasecmp( s->bv_val, a->an_name.bv_val ) == 0 ) { 897 return( 1 ); 898 } 899 } 900 901 return( 0 ); 902 } 903 904 /* 905 * Convert a delimited string into a list of AttributeNames; add 906 * on to an existing list if it was given. If the string is not 907 * a valid attribute name, if a '-' is prepended it is skipped 908 * and the remaining name is tried again; if a '@' (or '+') is 909 * prepended, an objectclass name is searched instead; if a '!' 910 * is prepended, the objectclass name is negated. 911 * 912 * NOTE: currently, if a valid attribute name is not found, the 913 * same string is also checked as valid objectclass name; however, 914 * this behavior is deprecated. 915 */ 916 AttributeName * 917 str2anlist( AttributeName *an, char *in, const char *brkstr ) 918 { 919 char *str; 920 char *s; 921 char *lasts; 922 int i, j; 923 const char *text; 924 AttributeName *anew; 925 926 /* find last element in list */ 927 i = 0; 928 if ( an != NULL ) { 929 for ( i = 0; !BER_BVISNULL( &an[ i ].an_name ) ; i++) 930 ; 931 } 932 933 /* protect the input string from strtok */ 934 str = ch_strdup( in ); 935 936 /* Count words in string */ 937 j = 1; 938 for ( s = str; *s; s++ ) { 939 if ( strchr( brkstr, *s ) != NULL ) { 940 j++; 941 } 942 } 943 944 an = ch_realloc( an, ( i + j + 1 ) * sizeof( AttributeName ) ); 945 anew = an + i; 946 for ( s = ldap_pvt_strtok( str, brkstr, &lasts ); 947 s != NULL; 948 s = ldap_pvt_strtok( NULL, brkstr, &lasts ) ) 949 { 950 /* put a stop mark */ 951 BER_BVZERO( &anew[1].an_name ); 952 953 anew->an_desc = NULL; 954 anew->an_oc = NULL; 955 anew->an_flags = 0; 956 ber_str2bv(s, 0, 1, &anew->an_name); 957 slap_bv2ad(&anew->an_name, &anew->an_desc, &text); 958 if ( !anew->an_desc ) { 959 switch( anew->an_name.bv_val[0] ) { 960 case '-': { 961 struct berval adname; 962 adname.bv_len = anew->an_name.bv_len - 1; 963 adname.bv_val = &anew->an_name.bv_val[1]; 964 slap_bv2ad(&adname, &anew->an_desc, &text); 965 if ( !anew->an_desc ) { 966 goto reterr; 967 } 968 } break; 969 970 case '@': 971 case '+': /* (deprecated) */ 972 case '!': { 973 struct berval ocname; 974 ocname.bv_len = anew->an_name.bv_len - 1; 975 ocname.bv_val = &anew->an_name.bv_val[1]; 976 anew->an_oc = oc_bvfind( &ocname ); 977 if ( !anew->an_oc ) { 978 goto reterr; 979 } 980 981 if ( anew->an_name.bv_val[0] == '!' ) { 982 anew->an_flags |= SLAP_AN_OCEXCLUDE; 983 } 984 } break; 985 986 default: 987 /* old (deprecated) way */ 988 anew->an_oc = oc_bvfind( &anew->an_name ); 989 if ( !anew->an_oc ) { 990 goto reterr; 991 } 992 } 993 } 994 anew->an_flags |= SLAP_AN_OCINITED; 995 anew++; 996 } 997 998 BER_BVZERO( &anew->an_name ); 999 free( str ); 1000 return( an ); 1001 1002 reterr: 1003 anlist_free( an, 1, NULL ); 1004 1005 /* 1006 * overwrites input string 1007 * on error! 1008 */ 1009 strcpy( in, s ); 1010 free( str ); 1011 return NULL; 1012 } 1013 1014 void 1015 anlist_free( AttributeName *an, int freename, void *ctx ) 1016 { 1017 if ( an == NULL ) { 1018 return; 1019 } 1020 1021 if ( freename ) { 1022 int i; 1023 1024 for ( i = 0; an[i].an_name.bv_val; i++ ) { 1025 ber_memfree_x( an[i].an_name.bv_val, ctx ); 1026 } 1027 } 1028 1029 ber_memfree_x( an, ctx ); 1030 } 1031 1032 char **anlist2charray_x( AttributeName *an, int dup, void *ctx ) 1033 { 1034 char **attrs; 1035 int i; 1036 1037 if ( an != NULL ) { 1038 for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) 1039 ; 1040 attrs = (char **) slap_sl_malloc( (i + 1) * sizeof(char *), ctx ); 1041 for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) { 1042 if ( dup ) 1043 attrs[i] = ch_strdup( an[i].an_name.bv_val ); 1044 else 1045 attrs[i] = an[i].an_name.bv_val; 1046 } 1047 attrs[i] = NULL; 1048 } else { 1049 attrs = NULL; 1050 } 1051 1052 return attrs; 1053 } 1054 1055 char **anlist2charray( AttributeName *an, int dup ) 1056 { 1057 return anlist2charray_x( an, dup, NULL ); 1058 } 1059 1060 char** 1061 anlist2attrs( AttributeName * anlist ) 1062 { 1063 int i, j, k = 0; 1064 int n; 1065 char **attrs; 1066 ObjectClass *oc; 1067 1068 if ( anlist == NULL ) 1069 return NULL; 1070 1071 for ( i = 0; anlist[i].an_name.bv_val; i++ ) { 1072 if ( ( oc = anlist[i].an_oc ) ) { 1073 for ( j = 0; oc->soc_required && oc->soc_required[j]; j++ ) ; 1074 k += j; 1075 for ( j = 0; oc->soc_allowed && oc->soc_allowed[j]; j++ ) ; 1076 k += j; 1077 } 1078 } 1079 1080 if ( i == 0 ) 1081 return NULL; 1082 1083 attrs = anlist2charray( anlist, 1 ); 1084 1085 n = i; 1086 1087 if ( k ) 1088 attrs = (char **) ch_realloc( attrs, (i + k + 1) * sizeof( char * )); 1089 1090 for ( i = 0; anlist[i].an_name.bv_val; i++ ) { 1091 if ( ( oc = anlist[i].an_oc ) ) { 1092 for ( j = 0; oc->soc_required && oc->soc_required[j]; j++ ) { 1093 attrs[n++] = ch_strdup( 1094 oc->soc_required[j]->sat_cname.bv_val ); 1095 } 1096 for ( j = 0; oc->soc_allowed && oc->soc_allowed[j]; j++ ) { 1097 attrs[n++] = ch_strdup( 1098 oc->soc_allowed[j]->sat_cname.bv_val ); 1099 } 1100 } 1101 } 1102 1103 if ( attrs ) 1104 attrs[n] = NULL; 1105 1106 i = 0; 1107 while ( attrs && attrs[i] ) { 1108 if ( *attrs[i] == '@' ) { 1109 ch_free( attrs[i] ); 1110 for ( j = i; attrs[j]; j++ ) { 1111 attrs[j] = attrs[j+1]; 1112 } 1113 } else { 1114 i++; 1115 } 1116 } 1117 1118 for ( i = 0; attrs && attrs[i]; i++ ) { 1119 j = i + 1; 1120 while ( attrs && attrs[j] ) { 1121 if ( !strcmp( attrs[i], attrs[j] )) { 1122 ch_free( attrs[j] ); 1123 for ( k = j; attrs && attrs[k]; k++ ) { 1124 attrs[k] = attrs[k+1]; 1125 } 1126 } else { 1127 j++; 1128 } 1129 } 1130 } 1131 1132 if ( i != n ) 1133 attrs = (char **) ch_realloc( attrs, (i+1) * sizeof( char * )); 1134 1135 return attrs; 1136 } 1137 1138 #define LBUFSIZ 80 1139 AttributeName* 1140 file2anlist( AttributeName *an, const char *fname, const char *brkstr ) 1141 { 1142 FILE *fp; 1143 char *line = NULL; 1144 char *lcur = NULL; 1145 char *c; 1146 size_t lmax = LBUFSIZ; 1147 1148 fp = fopen( fname, "r" ); 1149 if ( fp == NULL ) { 1150 Debug( LDAP_DEBUG_ANY, 1151 "get_attrs_from_file: failed to open attribute list file " 1152 "\"%s\": %s\n", fname, strerror(errno), 0 ); 1153 return NULL; 1154 } 1155 1156 lcur = line = (char *) ch_malloc( lmax ); 1157 if ( !line ) { 1158 Debug( LDAP_DEBUG_ANY, 1159 "get_attrs_from_file: could not allocate memory\n", 1160 0, 0, 0 ); 1161 fclose(fp); 1162 return NULL; 1163 } 1164 1165 while ( fgets( lcur, LBUFSIZ, fp ) != NULL ) { 1166 if ( ( c = strchr( lcur, '\n' ) ) ) { 1167 if ( c == line ) { 1168 *c = '\0'; 1169 } else if ( *(c-1) == '\r' ) { 1170 *(c-1) = '\0'; 1171 } else { 1172 *c = '\0'; 1173 } 1174 } else { 1175 lmax += LBUFSIZ; 1176 line = (char *) ch_realloc( line, lmax ); 1177 if ( !line ) { 1178 Debug( LDAP_DEBUG_ANY, 1179 "get_attrs_from_file: could not allocate memory\n", 1180 0, 0, 0 ); 1181 fclose(fp); 1182 return NULL; 1183 } 1184 lcur = line + strlen( line ); 1185 continue; 1186 } 1187 an = str2anlist( an, line, brkstr ); 1188 if ( an == NULL ) 1189 break; 1190 lcur = line; 1191 } 1192 ch_free( line ); 1193 fclose(fp); 1194 return an; 1195 } 1196 #undef LBUFSIZ 1197 1198 /* Define an attribute option. */ 1199 int 1200 ad_define_option( const char *name, const char *fname, int lineno ) 1201 { 1202 int i; 1203 unsigned int optlen; 1204 1205 if ( options == &lang_option ) { 1206 options = NULL; 1207 option_count = 0; 1208 } 1209 if ( name == NULL ) 1210 return 0; 1211 1212 optlen = 0; 1213 do { 1214 if ( !DESC_CHAR( name[optlen] ) ) { 1215 /* allow trailing '=', same as '-' */ 1216 if ( name[optlen] == '=' && !name[optlen+1] ) { 1217 msad_range_hack = 1; 1218 continue; 1219 } 1220 Debug( LDAP_DEBUG_ANY, 1221 "%s: line %d: illegal option name \"%s\"\n", 1222 fname, lineno, name ); 1223 return 1; 1224 } 1225 } while ( name[++optlen] ); 1226 1227 options = ch_realloc( options, 1228 (option_count+1) * sizeof(Attr_option) ); 1229 1230 if ( strcasecmp( name, "binary" ) == 0 1231 || ad_find_option_definition( name, optlen ) ) { 1232 Debug( LDAP_DEBUG_ANY, 1233 "%s: line %d: option \"%s\" is already defined\n", 1234 fname, lineno, name ); 1235 return 1; 1236 } 1237 1238 for ( i = option_count; i; --i ) { 1239 if ( strcasecmp( name, options[i-1].name.bv_val ) >= 0 ) 1240 break; 1241 options[i] = options[i-1]; 1242 } 1243 1244 options[i].name.bv_val = ch_strdup( name ); 1245 options[i].name.bv_len = optlen; 1246 options[i].prefix = (name[optlen-1] == '-') || 1247 (name[optlen-1] == '='); 1248 1249 if ( i != option_count && 1250 options[i].prefix && 1251 optlen < options[i+1].name.bv_len && 1252 strncasecmp( name, options[i+1].name.bv_val, optlen ) == 0 ) { 1253 Debug( LDAP_DEBUG_ANY, 1254 "%s: line %d: option \"%s\" overrides previous option\n", 1255 fname, lineno, name ); 1256 return 1; 1257 } 1258 1259 option_count++; 1260 return 0; 1261 } 1262 1263 void 1264 ad_unparse_options( BerVarray *res ) 1265 { 1266 int i; 1267 for ( i = 0; i < option_count; i++ ) { 1268 value_add_one( res, &options[i].name ); 1269 } 1270 } 1271 1272 /* Find the definition of the option name or prefix matching the arguments */ 1273 static Attr_option * 1274 ad_find_option_definition( const char *opt, int optlen ) 1275 { 1276 int top = 0, bot = option_count; 1277 while ( top < bot ) { 1278 int mid = (top + bot) / 2; 1279 int mlen = options[mid].name.bv_len; 1280 char *mname = options[mid].name.bv_val; 1281 int j; 1282 if ( optlen < mlen ) { 1283 j = strncasecmp( opt, mname, optlen ) - 1; 1284 } else { 1285 j = strncasecmp( opt, mname, mlen ); 1286 if ( j==0 && (optlen==mlen || options[mid].prefix) ) 1287 return &options[mid]; 1288 } 1289 if ( j < 0 ) 1290 bot = mid; 1291 else 1292 top = mid + 1; 1293 } 1294 return NULL; 1295 } 1296 1297 MatchingRule *ad_mr( 1298 AttributeDescription *ad, 1299 unsigned usage ) 1300 { 1301 switch( usage & SLAP_MR_TYPE_MASK ) { 1302 case SLAP_MR_NONE: 1303 case SLAP_MR_EQUALITY: 1304 return ad->ad_type->sat_equality; 1305 break; 1306 case SLAP_MR_ORDERING: 1307 return ad->ad_type->sat_ordering; 1308 break; 1309 case SLAP_MR_SUBSTR: 1310 return ad->ad_type->sat_substr; 1311 break; 1312 case SLAP_MR_EXT: 1313 default: 1314 assert( 0 /* ad_mr: bad usage */); 1315 } 1316 return NULL; 1317 } 1318