1 /* ad.c - routines for dealing with attribute descriptions */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2009 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
23 #include <ac/socket.h>
24 #include <ac/string.h>
30 static AttributeName anlist_no_attrs[] = {
31 { BER_BVC( LDAP_NO_ATTRS ), NULL, 0, NULL },
32 { BER_BVNULL, NULL, 0, NULL }
35 static AttributeName anlist_all_user_attributes[] = {
36 { BER_BVC( LDAP_ALL_USER_ATTRIBUTES ), NULL, 0, NULL },
37 { BER_BVNULL, NULL, 0, NULL }
40 static AttributeName anlist_all_operational_attributes[] = {
41 { BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ), NULL, 0, NULL },
42 { BER_BVNULL, NULL, 0, NULL }
45 static AttributeName anlist_all_attributes[] = {
46 { BER_BVC( LDAP_ALL_USER_ATTRIBUTES ), NULL, 0, NULL },
47 { BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ), NULL, 0, NULL },
48 { BER_BVNULL, NULL, 0, NULL }
51 AttributeName *slap_anlist_no_attrs = anlist_no_attrs;
52 AttributeName *slap_anlist_all_user_attributes = anlist_all_user_attributes;
53 AttributeName *slap_anlist_all_operational_attributes = anlist_all_operational_attributes;
54 AttributeName *slap_anlist_all_attributes = anlist_all_attributes;
56 typedef struct Attr_option {
57 struct berval name; /* option name or prefix */
58 int prefix; /* NAME is a tag and range prefix */
61 static Attr_option lang_option = { BER_BVC("lang-"), 1 };
63 /* Options sorted by name, and number of options */
64 static Attr_option *options = &lang_option;
65 static int option_count = 1;
67 static int msad_range_hack = 0;
69 static Attr_option *ad_find_option_definition( const char *opt, int optlen );
71 static int ad_keystring(
76 if( !AD_LEADCHAR( bv->bv_val[0] ) ) {
80 for( i=1; i<bv->bv_len; i++ ) {
81 if( !AD_CHAR( bv->bv_val[i] )) {
82 if ( msad_range_hack && bv->bv_val[i] == '=' )
90 void ad_destroy( AttributeDescription *ad )
92 AttributeDescription *n;
94 for (; ad != NULL; ad = n) {
100 /* Is there an AttributeDescription for this type that uses these tags? */
101 AttributeDescription * ad_find_tags(
103 struct berval *tags )
105 AttributeDescription *ad;
107 ldap_pvt_thread_mutex_lock( &type->sat_ad_mutex );
108 for (ad = type->sat_ad; ad; ad=ad->ad_next)
110 if (ad->ad_tags.bv_len == tags->bv_len &&
111 !strcasecmp(ad->ad_tags.bv_val, tags->bv_val))
114 ldap_pvt_thread_mutex_unlock( &type->sat_ad_mutex );
120 AttributeDescription **ad,
124 bv.bv_val = (char *) str;
125 bv.bv_len = strlen( str );
127 return slap_bv2ad( &bv, ad, text );
130 static char *strchrlen(
138 for( p=beg; *p && p < end; p++ ) {
151 AttributeDescription **ad,
154 int rtn = LDAP_UNDEFINED_TYPE;
155 AttributeDescription desc, *d2;
156 char *name, *options, *optn;
161 /* hardcoded limits for speed */
162 #define MAX_TAGGING_OPTIONS 128
163 struct berval tags[MAX_TAGGING_OPTIONS+1];
164 #define MAX_TAGS_LEN 1024
165 char tagbuf[MAX_TAGS_LEN];
167 assert( ad != NULL );
168 assert( *ad == NULL ); /* temporary */
170 if( bv == NULL || BER_BVISNULL( bv ) || BER_BVISEMPTY( bv ) ) {
171 *text = "empty AttributeDescription";
175 /* make sure description is IA5 */
176 if( ad_keystring( bv ) ) {
177 *text = "AttributeDescription contains inappropriate characters";
181 /* find valid base attribute type; parse in place */
184 BER_BVZERO( &desc.ad_tags );
186 options = ber_bvchr( bv, ';' );
187 if ( options != NULL && (unsigned) ( options - name ) < bv->bv_len ) {
188 /* don't go past the end of the berval! */
189 desc.ad_cname.bv_len = options - name;
193 desc.ad_type = at_bvfind( &desc.ad_cname );
194 if( desc.ad_type == NULL ) {
195 *text = "attribute type undefined";
199 if( is_at_operational( desc.ad_type ) && options != NULL ) {
200 *text = "operational attribute with options undefined";
205 * parse options in place
209 optn = bv->bv_val + bv->bv_len;
211 for( opt=options; opt != NULL; opt=next ) {
214 next = strchrlen( opt, optn, ';', &optlen );
217 *text = "zero length option is invalid";
220 } else if ( optlen == STRLENOF("binary") &&
221 strncasecmp( opt, "binary", STRLENOF("binary") ) == 0 )
224 if( slap_ad_is_binary( &desc ) ) {
225 *text = "option \"binary\" specified multiple times";
229 if( !slap_syntax_is_binary( desc.ad_type->sat_syntax )) {
230 /* not stored in binary, disallow option */
231 *text = "option \"binary\" not supported with type";
235 desc.ad_flags |= SLAP_DESC_BINARY;
238 } else if ( ad_find_option_definition( opt, optlen ) ) {
241 if( opt[optlen-1] == '-' ||
242 ( opt[optlen-1] == '=' && msad_range_hack )) {
243 desc.ad_flags |= SLAP_DESC_TAG_RANGE;
246 if( ntags >= MAX_TAGGING_OPTIONS ) {
247 *text = "too many tagging options";
252 * tags should be presented in sorted order,
253 * so run the array in reverse.
255 for( i=ntags-1; i>=0; i-- ) {
258 rc = strncasecmp( opt, tags[i].bv_val,
259 (unsigned) optlen < tags[i].bv_len
260 ? (unsigned) optlen : tags[i].bv_len );
262 if( rc == 0 && (unsigned)optlen == tags[i].bv_len ) {
263 /* duplicate (ignore) */
266 } else if ( rc > 0 ||
267 ( rc == 0 && (unsigned)optlen > tags[i].bv_len ))
269 AC_MEMCPY( &tags[i+2], &tags[i+1],
270 (ntags-i-1)*sizeof(struct berval) );
271 tags[i+1].bv_val = opt;
272 tags[i+1].bv_len = optlen;
278 AC_MEMCPY( &tags[1], &tags[0],
279 ntags*sizeof(struct berval) );
281 tags[0].bv_val = opt;
282 tags[0].bv_len = optlen;
285 tagslen += optlen + 1;
289 *text = "unrecognized option";
297 if( tagslen > MAX_TAGS_LEN ) {
298 *text = "tagging options too long";
302 desc.ad_tags.bv_val = tagbuf;
305 for( i=0; i<ntags; i++ ) {
306 AC_MEMCPY( &desc.ad_tags.bv_val[tagslen],
307 tags[i].bv_val, tags[i].bv_len );
309 tagslen += tags[i].bv_len;
310 desc.ad_tags.bv_val[tagslen++] = ';';
313 desc.ad_tags.bv_val[--tagslen] = '\0';
314 desc.ad_tags.bv_len = tagslen;
317 /* see if a matching description is already cached */
318 for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
319 if( d2->ad_flags != desc.ad_flags ) {
322 if( d2->ad_tags.bv_len != desc.ad_tags.bv_len ) {
325 if( d2->ad_tags.bv_len == 0 ) {
328 if( strncasecmp( d2->ad_tags.bv_val, desc.ad_tags.bv_val,
329 desc.ad_tags.bv_len ) == 0 )
335 /* Not found, add new one */
338 ldap_pvt_thread_mutex_lock( &desc.ad_type->sat_ad_mutex );
339 /* check again now that we've locked */
340 for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
341 if (d2->ad_flags != desc.ad_flags)
343 if (d2->ad_tags.bv_len != desc.ad_tags.bv_len)
345 if (d2->ad_tags.bv_len == 0)
347 if (strncasecmp(d2->ad_tags.bv_val, desc.ad_tags.bv_val,
348 desc.ad_tags.bv_len) == 0)
352 ldap_pvt_thread_mutex_unlock( &desc.ad_type->sat_ad_mutex );
356 /* Allocate a single contiguous block. If there are no
357 * options, we just need space for the AttrDesc structure.
358 * Otherwise, we need to tack on the full name length +
359 * options length, + maybe tagging options length again.
361 if (desc.ad_tags.bv_len || desc.ad_flags != SLAP_DESC_NONE) {
362 dlen = desc.ad_type->sat_cname.bv_len + 1;
363 if (desc.ad_tags.bv_len) {
364 dlen += 1 + desc.ad_tags.bv_len;
366 if ( slap_ad_is_binary( &desc ) ) {
367 dlen += 1 + STRLENOF(";binary") + desc.ad_tags.bv_len;
371 d2 = ch_malloc(sizeof(AttributeDescription) + dlen);
373 d2->ad_type = desc.ad_type;
374 d2->ad_flags = desc.ad_flags;
375 d2->ad_cname.bv_len = desc.ad_type->sat_cname.bv_len;
376 d2->ad_tags.bv_len = desc.ad_tags.bv_len;
379 d2->ad_cname.bv_val = d2->ad_type->sat_cname.bv_val;
380 d2->ad_tags.bv_val = NULL;
384 d2->ad_cname.bv_val = (char *)(d2+1);
385 strcpy(d2->ad_cname.bv_val, d2->ad_type->sat_cname.bv_val);
386 cp = d2->ad_cname.bv_val + d2->ad_cname.bv_len;
387 if( slap_ad_is_binary( &desc ) ) {
390 if( desc.ad_tags.bv_len ) {
391 lp = desc.ad_tags.bv_val;
392 while( strncasecmp(lp, "binary", STRLENOF("binary")) < 0
393 && (lp = strchr( lp, ';' )) != NULL )
395 if( lp != desc.ad_tags.bv_val ) {
398 ? (unsigned) (lp - desc.ad_tags.bv_val - 1)
399 : strlen( desc.ad_tags.bv_val ));
400 cp = lutil_strncopy(cp, desc.ad_tags.bv_val, j);
403 cp = lutil_strcopy(cp, ";binary");
406 cp = lutil_strcopy(cp, lp);
408 d2->ad_cname.bv_len = cp - d2->ad_cname.bv_val;
409 if( desc.ad_tags.bv_len )
410 ldap_pvt_str2lower(op);
415 if( desc.ad_tags.bv_len ) {
416 lp = d2->ad_cname.bv_val + d2->ad_cname.bv_len + j;
419 d2->ad_tags.bv_val = lp;
420 strcpy(lp, desc.ad_tags.bv_val);
421 ldap_pvt_str2lower(lp);
423 d2->ad_cname.bv_len += 1 + desc.ad_tags.bv_len;
426 /* Add new desc to list. We always want the bare Desc with
427 * no options to stay at the head of the list, assuming
428 * that one will be used most frequently.
430 if (desc.ad_type->sat_ad == NULL || dlen == 0) {
431 d2->ad_next = desc.ad_type->sat_ad;
432 desc.ad_type->sat_ad = d2;
434 d2->ad_next = desc.ad_type->sat_ad->ad_next;
435 desc.ad_type->sat_ad->ad_next = d2;
437 ldap_pvt_thread_mutex_unlock( &desc.ad_type->sat_ad_mutex );
449 static int is_ad_subtags(
450 struct berval *subtagsbv,
451 struct berval *suptagsbv )
453 const char *suptags, *supp, *supdelimp, *supn;
454 const char *subtags, *subp, *subdelimp, *subn;
457 subtags =subtagsbv->bv_val;
458 suptags =suptagsbv->bv_val;
459 subn = subtags + subtagsbv->bv_len;
460 supn = suptags + suptagsbv->bv_len;
462 for( supp=suptags ; supp; supp=supdelimp ) {
463 supdelimp = strchrlen( supp, supn, ';', &suplen );
464 if( supdelimp ) supdelimp++;
466 for( subp=subtags ; subp; subp=subdelimp ) {
467 subdelimp = strchrlen( subp, subn, ';', &sublen );
468 if( subdelimp ) subdelimp++;
471 ? ( suplen-1 == sublen && supp[suplen-1] == '-'
472 && strncmp( supp, subp, sublen ) == 0 )
473 : ( ( suplen == sublen || supp[suplen-1] == '-' )
474 && strncmp( supp, subp, suplen ) == 0 ) )
487 AttributeDescription *sub,
488 AttributeDescription *super
494 for ( a = sub->ad_type; a; a=a->sat_sup ) {
495 if ( a == super->ad_type ) break;
501 /* ensure sub does support all flags of super */
502 lr = sub->ad_tags.bv_len ? SLAP_DESC_TAG_RANGE : 0;
503 if(( super->ad_flags & ( sub->ad_flags | lr )) != super->ad_flags ) {
507 /* check for tagging options */
508 if ( super->ad_tags.bv_len == 0 )
510 if ( sub->ad_tags.bv_len == 0 )
513 return is_ad_subtags( &sub->ad_tags, &super->ad_tags );
517 AttributeDescription *desc,
518 AttributeName *attrs )
520 if (! attrs ) return 0;
522 for( ; attrs->an_name.bv_val; attrs++ ) {
526 if ( attrs->an_desc ) {
529 if ( desc == attrs->an_desc ) {
534 * EXTENSION: if requested description is preceeded by
535 * a '-' character, do not match on subtypes.
537 if ( attrs->an_name.bv_val[0] == '-' ) {
541 /* Is this a subtype of the requested attr? */
542 for (a = desc->ad_type; a; a=a->sat_sup) {
543 if ( a == attrs->an_desc->ad_type )
549 /* Does desc support all the requested flags? */
550 lr = desc->ad_tags.bv_len ? SLAP_DESC_TAG_RANGE : 0;
551 if(( attrs->an_desc->ad_flags & (desc->ad_flags | lr))
552 != attrs->an_desc->ad_flags ) {
555 /* Do the descs have compatible tags? */
556 if ( attrs->an_desc->ad_tags.bv_len == 0 ) {
559 if ( desc->ad_tags.bv_len == 0) {
562 if ( is_ad_subtags( &desc->ad_tags,
563 &attrs->an_desc->ad_tags ) ) {
569 if ( ber_bvccmp( &attrs->an_name, '*' ) ) {
570 if ( !is_at_operational( desc->ad_type ) ) {
576 if ( ber_bvccmp( &attrs->an_name, '+' ) ) {
577 if ( is_at_operational( desc->ad_type ) ) {
584 * EXTENSION: see if requested description is @objectClass
585 * if so, return attributes which the class requires/allows
586 * else if requested description is !objectClass, return
587 * attributes which the class does not require/allow
590 if( oc == NULL && attrs->an_name.bv_val ) {
591 switch( attrs->an_name.bv_val[0] ) {
592 case '@': /* @objectClass */
593 case '+': /* +objectClass (deprecated) */
594 case '!': { /* exclude */
595 struct berval ocname;
596 ocname.bv_len = attrs->an_name.bv_len - 1;
597 ocname.bv_val = &attrs->an_name.bv_val[1];
598 oc = oc_bvfind( &ocname );
599 attrs->an_oc_exclude = 0;
600 if ( oc && attrs->an_name.bv_val[0] == '!' ) {
601 attrs->an_oc_exclude = 1;
605 default: /* old (deprecated) way */
606 oc = oc_bvfind( &attrs->an_name );
611 if ( attrs->an_oc_exclude ) {
612 if ( oc == slap_schema.si_oc_extensibleObject ) {
613 /* extensibleObject allows the return of anything */
617 if( oc->soc_required ) {
618 /* allow return of required attributes */
621 for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
622 for (a = desc->ad_type; a; a=a->sat_sup) {
623 if ( a == oc->soc_required[i] ) {
630 if( oc->soc_allowed ) {
631 /* allow return of allowed attributes */
633 for ( i = 0; oc->soc_allowed[i] != NULL; i++ ) {
634 for (a = desc->ad_type; a; a=a->sat_sup) {
635 if ( a == oc->soc_allowed[i] ) {
645 if ( oc == slap_schema.si_oc_extensibleObject ) {
646 /* extensibleObject allows the return of anything */
650 if( oc->soc_required ) {
651 /* allow return of required attributes */
654 for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
655 for (a = desc->ad_type; a; a=a->sat_sup) {
656 if ( a == oc->soc_required[i] ) {
663 if( oc->soc_allowed ) {
664 /* allow return of allowed attributes */
666 for ( i = 0; oc->soc_allowed[i] != NULL; i++ ) {
667 for (a = desc->ad_type; a; a=a->sat_sup) {
668 if ( a == oc->soc_allowed[i] ) {
678 /* give it a chance of being retrieved by a proxy... */
679 (void)slap_bv2undef_ad( &attrs->an_name,
680 &attrs->an_desc, &text,
681 SLAP_AD_PROXIED|SLAP_AD_NOINSERT );
689 int slap_str2undef_ad(
691 AttributeDescription **ad,
696 bv.bv_val = (char *) str;
697 bv.bv_len = strlen( str );
699 return slap_bv2undef_ad( &bv, ad, text, flags );
702 int slap_bv2undef_ad(
704 AttributeDescription **ad,
708 AttributeDescription *desc;
711 assert( ad != NULL );
713 if( bv == NULL || bv->bv_len == 0 ) {
714 *text = "empty AttributeDescription";
715 return LDAP_UNDEFINED_TYPE;
718 /* make sure description is IA5 */
719 if( ad_keystring( bv ) ) {
720 *text = "AttributeDescription contains inappropriate characters";
721 return LDAP_UNDEFINED_TYPE;
724 /* use the appropriate type */
725 if ( flags & SLAP_AD_PROXIED ) {
726 at = slap_schema.si_at_proxied;
729 at = slap_schema.si_at_undefined;
732 for( desc = at->sat_ad; desc; desc=desc->ad_next ) {
733 if( desc->ad_cname.bv_len == bv->bv_len &&
734 !strcasecmp( desc->ad_cname.bv_val, bv->bv_val ) )
741 if ( flags & SLAP_AD_NOINSERT ) {
743 return LDAP_UNDEFINED_TYPE;
746 desc = ch_malloc(sizeof(AttributeDescription) + 1 +
749 desc->ad_flags = SLAP_DESC_NONE;
750 BER_BVZERO( &desc->ad_tags );
752 desc->ad_cname.bv_len = bv->bv_len;
753 desc->ad_cname.bv_val = (char *)(desc+1);
754 strcpy(desc->ad_cname.bv_val, bv->bv_val);
756 /* canonical to upper case */
757 ldap_pvt_str2upper( desc->ad_cname.bv_val );
759 /* shouldn't we protect this for concurrency? */
761 ldap_pvt_thread_mutex_lock( &ad_undef_mutex );
762 desc->ad_next = desc->ad_type->sat_ad;
763 desc->ad_type->sat_ad = desc;
764 ldap_pvt_thread_mutex_unlock( &ad_undef_mutex );
766 Debug( LDAP_DEBUG_ANY,
767 "%s attributeDescription \"%s\" inserted.\n",
768 ( flags & SLAP_AD_PROXIED ) ? "PROXIED" : "UNKNOWN",
769 desc->ad_cname.bv_val, 0 );
781 AttributeDescription *
786 AttributeDescription *ad =
787 slap_sl_mfuncs.bmf_malloc( sizeof(AttributeDescription) +
788 bv->bv_len + 1, memctx );
790 ad->ad_cname.bv_val = (char *)(ad+1);
791 strncpy( ad->ad_cname.bv_val, bv->bv_val, bv->bv_len+1 );
792 ad->ad_cname.bv_len = bv->bv_len;
793 ad->ad_flags = SLAP_DESC_TEMPORARY;
794 ad->ad_type = slap_schema.si_at_undefined;
805 AttributeDescription **u_ad, **n_ad;
807 /* Get to last ad on the new type */
808 for ( n_ad = &nat->sat_ad; *n_ad; n_ad = &(*n_ad)->ad_next ) ;
810 for ( u_ad = &at->sat_ad; *u_ad; ) {
813 ber_str2bv( name, 0, 0, &bv );
815 /* remove iff undef == name or undef == name;tag */
816 if ( (*u_ad)->ad_cname.bv_len >= bv.bv_len
817 && strncasecmp( (*u_ad)->ad_cname.bv_val, bv.bv_val, bv.bv_len ) == 0
818 && ( (*u_ad)->ad_cname.bv_val[ bv.bv_len ] == '\0'
819 || (*u_ad)->ad_cname.bv_val[ bv.bv_len ] == ';' ) )
821 AttributeDescription *tmp = *u_ad;
823 *u_ad = (*u_ad)->ad_next;
827 /* ad_cname was contiguous, no leak here */
828 tmp->ad_cname = nat->sat_cname;
830 n_ad = &tmp->ad_next;
832 u_ad = &(*u_ad)->ad_next;
840 slap_ad_undef_promote(
846 ldap_pvt_thread_mutex_lock( &ad_undef_mutex );
848 rc = undef_promote( slap_schema.si_at_undefined, name, at );
850 rc = undef_promote( slap_schema.si_at_proxied, name, at );
853 ldap_pvt_thread_mutex_unlock( &ad_undef_mutex );
864 if( a == NULL ) return 0;
866 for ( ; a->an_name.bv_val; a++ ) {
867 if ( a->an_name.bv_len != s->bv_len) continue;
868 if ( strcasecmp( s->bv_val, a->an_name.bv_val ) == 0 ) {
877 * Convert a delimited string into a list of AttributeNames; add
878 * on to an existing list if it was given. If the string is not
879 * a valid attribute name, if a '-' is prepended it is skipped
880 * and the remaining name is tried again; if a '@' (or '+') is
881 * prepended, an objectclass name is searched instead; if a '!'
882 * is prepended, the objectclass name is negated.
884 * NOTE: currently, if a valid attribute name is not found, the
885 * same string is also checked as valid objectclass name; however,
886 * this behavior is deprecated.
889 str2anlist( AttributeName *an, char *in, const char *brkstr )
898 /* find last element in list */
901 for ( i = 0; !BER_BVISNULL( &an[ i ].an_name ) ; i++)
905 /* protect the input string from strtok */
906 str = ch_strdup( in );
908 /* Count words in string */
910 for ( s = str; *s; s++ ) {
911 if ( strchr( brkstr, *s ) != NULL ) {
916 an = ch_realloc( an, ( i + j + 1 ) * sizeof( AttributeName ) );
918 for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
920 s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
922 /* put a stop mark */
923 BER_BVZERO( &anew[1].an_name );
925 anew->an_desc = NULL;
927 anew->an_oc_exclude = 0;
928 ber_str2bv(s, 0, 1, &anew->an_name);
929 slap_bv2ad(&anew->an_name, &anew->an_desc, &text);
930 if ( !anew->an_desc ) {
931 switch( anew->an_name.bv_val[0] ) {
933 struct berval adname;
934 adname.bv_len = anew->an_name.bv_len - 1;
935 adname.bv_val = &anew->an_name.bv_val[1];
936 slap_bv2ad(&adname, &anew->an_desc, &text);
937 if ( !anew->an_desc ) {
943 case '+': /* (deprecated) */
945 struct berval ocname;
946 ocname.bv_len = anew->an_name.bv_len - 1;
947 ocname.bv_val = &anew->an_name.bv_val[1];
948 anew->an_oc = oc_bvfind( &ocname );
949 if ( !anew->an_oc ) {
953 if ( anew->an_name.bv_val[0] == '!' ) {
954 anew->an_oc_exclude = 1;
959 /* old (deprecated) way */
960 anew->an_oc = oc_bvfind( &anew->an_name );
961 if ( !anew->an_oc ) {
969 BER_BVZERO( &anew->an_name );
974 anlist_free( an, 1, NULL );
977 * overwrites input string
986 anlist_free( AttributeName *an, int freename, void *ctx )
995 for ( i = 0; an[i].an_name.bv_val; i++ ) {
996 ber_memfree_x( an[i].an_name.bv_val, ctx );
1000 ber_memfree_x( an, ctx );
1003 char **anlist2charray_x( AttributeName *an, int dup, void *ctx )
1009 for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ )
1011 attrs = (char **) slap_sl_malloc( (i + 1) * sizeof(char *), ctx );
1012 for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
1014 attrs[i] = ch_strdup( an[i].an_name.bv_val );
1016 attrs[i] = an[i].an_name.bv_val;
1026 char **anlist2charray( AttributeName *an, int dup )
1028 return anlist2charray_x( an, dup, NULL );
1032 anlist2attrs( AttributeName * anlist )
1039 if ( anlist == NULL )
1042 for ( i = 0; anlist[i].an_name.bv_val; i++ ) {
1043 if ( ( oc = anlist[i].an_oc ) ) {
1044 for ( j = 0; oc->soc_required && oc->soc_required[j]; j++ ) ;
1046 for ( j = 0; oc->soc_allowed && oc->soc_allowed[j]; j++ ) ;
1054 attrs = anlist2charray( anlist, 1 );
1059 attrs = (char **) ch_realloc( attrs, (i + k + 1) * sizeof( char * ));
1061 for ( i = 0; anlist[i].an_name.bv_val; i++ ) {
1062 if ( ( oc = anlist[i].an_oc ) ) {
1063 for ( j = 0; oc->soc_required && oc->soc_required[j]; j++ ) {
1064 attrs[n++] = ch_strdup(
1065 oc->soc_required[j]->sat_cname.bv_val );
1067 for ( j = 0; oc->soc_allowed && oc->soc_allowed[j]; j++ ) {
1068 attrs[n++] = ch_strdup(
1069 oc->soc_allowed[j]->sat_cname.bv_val );
1078 while ( attrs && attrs[i] ) {
1079 if ( *attrs[i] == '@' ) {
1080 ch_free( attrs[i] );
1081 for ( j = i; attrs[j]; j++ ) {
1082 attrs[j] = attrs[j+1];
1089 for ( i = 0; attrs && attrs[i]; i++ ) {
1091 while ( attrs && attrs[j] ) {
1092 if ( !strcmp( attrs[i], attrs[j] )) {
1093 ch_free( attrs[j] );
1094 for ( k = j; attrs && attrs[k]; k++ ) {
1095 attrs[k] = attrs[k+1];
1104 attrs = (char **) ch_realloc( attrs, (i+1) * sizeof( char * ));
1111 file2anlist( AttributeName *an, const char *fname, const char *brkstr )
1117 size_t lmax = LBUFSIZ;
1119 fp = fopen( fname, "r" );
1121 Debug( LDAP_DEBUG_ANY,
1122 "get_attrs_from_file: failed to open attribute list file "
1123 "\"%s\": %s\n", fname, strerror(errno), 0 );
1127 lcur = line = (char *) ch_malloc( lmax );
1129 Debug( LDAP_DEBUG_ANY,
1130 "get_attrs_from_file: could not allocate memory\n",
1136 while ( fgets( lcur, LBUFSIZ, fp ) != NULL ) {
1137 if ( ( c = strchr( lcur, '\n' ) ) ) {
1140 } else if ( *(c-1) == '\r' ) {
1147 line = (char *) ch_realloc( line, lmax );
1149 Debug( LDAP_DEBUG_ANY,
1150 "get_attrs_from_file: could not allocate memory\n",
1155 lcur = line + strlen( line );
1158 an = str2anlist( an, line, brkstr );
1169 /* Define an attribute option. */
1171 ad_define_option( const char *name, const char *fname, int lineno )
1174 unsigned int optlen;
1176 if ( options == &lang_option ) {
1185 if ( !DESC_CHAR( name[optlen] ) ) {
1186 /* allow trailing '=', same as '-' */
1187 if ( name[optlen] == '=' && !name[optlen+1] ) {
1188 msad_range_hack = 1;
1191 Debug( LDAP_DEBUG_ANY,
1192 "%s: line %d: illegal option name \"%s\"\n",
1193 fname, lineno, name );
1196 } while ( name[++optlen] );
1198 options = ch_realloc( options,
1199 (option_count+1) * sizeof(Attr_option) );
1201 if ( strcasecmp( name, "binary" ) == 0
1202 || ad_find_option_definition( name, optlen ) ) {
1203 Debug( LDAP_DEBUG_ANY,
1204 "%s: line %d: option \"%s\" is already defined\n",
1205 fname, lineno, name );
1209 for ( i = option_count; i; --i ) {
1210 if ( strcasecmp( name, options[i-1].name.bv_val ) >= 0 )
1212 options[i] = options[i-1];
1215 options[i].name.bv_val = ch_strdup( name );
1216 options[i].name.bv_len = optlen;
1217 options[i].prefix = (name[optlen-1] == '-') ||
1218 (name[optlen-1] == '=');
1220 if ( i != option_count &&
1221 options[i].prefix &&
1222 optlen < options[i+1].name.bv_len &&
1223 strncasecmp( name, options[i+1].name.bv_val, optlen ) == 0 ) {
1224 Debug( LDAP_DEBUG_ANY,
1225 "%s: line %d: option \"%s\" overrides previous option\n",
1226 fname, lineno, name );
1235 ad_unparse_options( BerVarray *res )
1238 for ( i = 0; i < option_count; i++ ) {
1239 value_add_one( res, &options[i].name );
1243 /* Find the definition of the option name or prefix matching the arguments */
1244 static Attr_option *
1245 ad_find_option_definition( const char *opt, int optlen )
1247 int top = 0, bot = option_count;
1248 while ( top < bot ) {
1249 int mid = (top + bot) / 2;
1250 int mlen = options[mid].name.bv_len;
1251 char *mname = options[mid].name.bv_val;
1253 if ( optlen < mlen ) {
1254 j = strncasecmp( opt, mname, optlen ) - 1;
1256 j = strncasecmp( opt, mname, mlen );
1257 if ( j==0 && (optlen==mlen || options[mid].prefix) )
1258 return &options[mid];
1268 MatchingRule *ad_mr(
1269 AttributeDescription *ad,
1272 switch( usage & SLAP_MR_TYPE_MASK ) {
1274 case SLAP_MR_EQUALITY:
1275 return ad->ad_type->sat_equality;
1277 case SLAP_MR_ORDERING:
1278 return ad->ad_type->sat_ordering;
1280 case SLAP_MR_SUBSTR:
1281 return ad->ad_type->sat_substr;
1285 assert( 0 /* ad_mr: bad usage */);