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