1 /* ad.c - routines for dealing with attribute descriptions */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/ad.c,v 1.95.2.4 2008/02/11 23:26:43 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2008 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 Attr_option
*ad_find_option_definition( const char *opt
, int optlen
);
69 static int ad_keystring(
74 if( !AD_LEADCHAR( bv
->bv_val
[0] ) ) {
78 for( i
=1; i
<bv
->bv_len
; i
++ ) {
79 if( !AD_CHAR( bv
->bv_val
[i
] ) ) {
86 void ad_destroy( AttributeDescription
*ad
)
88 AttributeDescription
*n
;
90 for (; ad
!= NULL
; ad
= n
) {
96 /* Is there an AttributeDescription for this type that uses these tags? */
97 AttributeDescription
* ad_find_tags(
101 AttributeDescription
*ad
;
103 ldap_pvt_thread_mutex_lock( &type
->sat_ad_mutex
);
104 for (ad
= type
->sat_ad
; ad
; ad
=ad
->ad_next
)
106 if (ad
->ad_tags
.bv_len
== tags
->bv_len
&&
107 !strcasecmp(ad
->ad_tags
.bv_val
, tags
->bv_val
))
110 ldap_pvt_thread_mutex_unlock( &type
->sat_ad_mutex
);
116 AttributeDescription
**ad
,
120 bv
.bv_val
= (char *) str
;
121 bv
.bv_len
= strlen( str
);
123 return slap_bv2ad( &bv
, ad
, text
);
126 static char *strchrlen(
134 for( p
=beg
; *p
&& p
< end
; p
++ ) {
147 AttributeDescription
**ad
,
150 int rtn
= LDAP_UNDEFINED_TYPE
;
151 AttributeDescription desc
, *d2
;
152 char *name
, *options
, *optn
;
157 /* hardcoded limits for speed */
158 #define MAX_TAGGING_OPTIONS 128
159 struct berval tags
[MAX_TAGGING_OPTIONS
+1];
160 #define MAX_TAGS_LEN 1024
161 char tagbuf
[MAX_TAGS_LEN
];
163 assert( ad
!= NULL
);
164 assert( *ad
== NULL
); /* temporary */
166 if( bv
== NULL
|| BER_BVISNULL( bv
) || BER_BVISEMPTY( bv
) ) {
167 *text
= "empty AttributeDescription";
171 /* make sure description is IA5 */
172 if( ad_keystring( bv
) ) {
173 *text
= "AttributeDescription contains inappropriate characters";
177 /* find valid base attribute type; parse in place */
180 BER_BVZERO( &desc
.ad_tags
);
182 options
= ber_bvchr( bv
, ';' );
183 if ( options
!= NULL
&& (unsigned) ( options
- name
) < bv
->bv_len
) {
184 /* don't go past the end of the berval! */
185 desc
.ad_cname
.bv_len
= options
- name
;
189 desc
.ad_type
= at_bvfind( &desc
.ad_cname
);
190 if( desc
.ad_type
== NULL
) {
191 *text
= "attribute type undefined";
195 if( is_at_operational( desc
.ad_type
) && options
!= NULL
) {
196 *text
= "operational attribute with options undefined";
201 * parse options in place
205 optn
= bv
->bv_val
+ bv
->bv_len
;
207 for( opt
=options
; opt
!= NULL
; opt
=next
) {
210 next
= strchrlen( opt
, optn
, ';', &optlen
);
213 *text
= "zero length option is invalid";
216 } else if ( optlen
== STRLENOF("binary") &&
217 strncasecmp( opt
, "binary", STRLENOF("binary") ) == 0 )
220 if( slap_ad_is_binary( &desc
) ) {
221 *text
= "option \"binary\" specified multiple times";
225 if( !slap_syntax_is_binary( desc
.ad_type
->sat_syntax
)) {
226 /* not stored in binary, disallow option */
227 *text
= "option \"binary\" not supported with type";
231 desc
.ad_flags
|= SLAP_DESC_BINARY
;
234 } else if ( ad_find_option_definition( opt
, optlen
) ) {
237 if( opt
[optlen
-1] == '-' ) {
238 desc
.ad_flags
|= SLAP_DESC_TAG_RANGE
;
241 if( ntags
>= MAX_TAGGING_OPTIONS
) {
242 *text
= "too many tagging options";
247 * tags should be presented in sorted order,
248 * so run the array in reverse.
250 for( i
=ntags
-1; i
>=0; i
-- ) {
253 rc
= strncasecmp( opt
, tags
[i
].bv_val
,
254 (unsigned) optlen
< tags
[i
].bv_len
255 ? (unsigned) optlen
: tags
[i
].bv_len
);
257 if( rc
== 0 && (unsigned)optlen
== tags
[i
].bv_len
) {
258 /* duplicate (ignore) */
261 } else if ( rc
> 0 ||
262 ( rc
== 0 && (unsigned)optlen
> tags
[i
].bv_len
))
264 AC_MEMCPY( &tags
[i
+2], &tags
[i
+1],
265 (ntags
-i
-1)*sizeof(struct berval
) );
266 tags
[i
+1].bv_val
= opt
;
267 tags
[i
+1].bv_len
= optlen
;
273 AC_MEMCPY( &tags
[1], &tags
[0],
274 ntags
*sizeof(struct berval
) );
276 tags
[0].bv_val
= opt
;
277 tags
[0].bv_len
= optlen
;
280 tagslen
+= optlen
+ 1;
284 *text
= "unrecognized option";
292 if( tagslen
> MAX_TAGS_LEN
) {
293 *text
= "tagging options too long";
297 desc
.ad_tags
.bv_val
= tagbuf
;
300 for( i
=0; i
<ntags
; i
++ ) {
301 AC_MEMCPY( &desc
.ad_tags
.bv_val
[tagslen
],
302 tags
[i
].bv_val
, tags
[i
].bv_len
);
304 tagslen
+= tags
[i
].bv_len
;
305 desc
.ad_tags
.bv_val
[tagslen
++] = ';';
308 desc
.ad_tags
.bv_val
[--tagslen
] = '\0';
309 desc
.ad_tags
.bv_len
= tagslen
;
312 /* see if a matching description is already cached */
313 for (d2
= desc
.ad_type
->sat_ad
; d2
; d2
=d2
->ad_next
) {
314 if( d2
->ad_flags
!= desc
.ad_flags
) {
317 if( d2
->ad_tags
.bv_len
!= desc
.ad_tags
.bv_len
) {
320 if( d2
->ad_tags
.bv_len
== 0 ) {
323 if( strncasecmp( d2
->ad_tags
.bv_val
, desc
.ad_tags
.bv_val
,
324 desc
.ad_tags
.bv_len
) == 0 )
330 /* Not found, add new one */
333 ldap_pvt_thread_mutex_lock( &desc
.ad_type
->sat_ad_mutex
);
334 /* check again now that we've locked */
335 for (d2
= desc
.ad_type
->sat_ad
; d2
; d2
=d2
->ad_next
) {
336 if (d2
->ad_flags
!= desc
.ad_flags
)
338 if (d2
->ad_tags
.bv_len
!= desc
.ad_tags
.bv_len
)
340 if (d2
->ad_tags
.bv_len
== 0)
342 if (strncasecmp(d2
->ad_tags
.bv_val
, desc
.ad_tags
.bv_val
,
343 desc
.ad_tags
.bv_len
) == 0)
347 ldap_pvt_thread_mutex_unlock( &desc
.ad_type
->sat_ad_mutex
);
351 /* Allocate a single contiguous block. If there are no
352 * options, we just need space for the AttrDesc structure.
353 * Otherwise, we need to tack on the full name length +
354 * options length, + maybe tagging options length again.
356 if (desc
.ad_tags
.bv_len
|| desc
.ad_flags
!= SLAP_DESC_NONE
) {
357 dlen
= desc
.ad_type
->sat_cname
.bv_len
+ 1;
358 if (desc
.ad_tags
.bv_len
) {
359 dlen
+= 1 + desc
.ad_tags
.bv_len
;
361 if ( slap_ad_is_binary( &desc
) ) {
362 dlen
+= 1 + STRLENOF(";binary") + desc
.ad_tags
.bv_len
;
366 d2
= ch_malloc(sizeof(AttributeDescription
) + dlen
);
368 d2
->ad_type
= desc
.ad_type
;
369 d2
->ad_flags
= desc
.ad_flags
;
370 d2
->ad_cname
.bv_len
= desc
.ad_type
->sat_cname
.bv_len
;
371 d2
->ad_tags
.bv_len
= desc
.ad_tags
.bv_len
;
374 d2
->ad_cname
.bv_val
= d2
->ad_type
->sat_cname
.bv_val
;
375 d2
->ad_tags
.bv_val
= NULL
;
379 d2
->ad_cname
.bv_val
= (char *)(d2
+1);
380 strcpy(d2
->ad_cname
.bv_val
, d2
->ad_type
->sat_cname
.bv_val
);
381 cp
= d2
->ad_cname
.bv_val
+ d2
->ad_cname
.bv_len
;
382 if( slap_ad_is_binary( &desc
) ) {
385 if( desc
.ad_tags
.bv_len
) {
386 lp
= desc
.ad_tags
.bv_val
;
387 while( strncasecmp(lp
, "binary", STRLENOF("binary")) < 0
388 && (lp
= strchr( lp
, ';' )) != NULL
)
390 if( lp
!= desc
.ad_tags
.bv_val
) {
393 ? (unsigned) (lp
- desc
.ad_tags
.bv_val
- 1)
394 : strlen( desc
.ad_tags
.bv_val
));
395 cp
= lutil_strncopy(cp
, desc
.ad_tags
.bv_val
, j
);
398 cp
= lutil_strcopy(cp
, ";binary");
401 cp
= lutil_strcopy(cp
, lp
);
403 d2
->ad_cname
.bv_len
= cp
- d2
->ad_cname
.bv_val
;
404 if( desc
.ad_tags
.bv_len
)
405 ldap_pvt_str2lower(op
);
410 if( desc
.ad_tags
.bv_len
) {
411 lp
= d2
->ad_cname
.bv_val
+ d2
->ad_cname
.bv_len
+ j
;
414 d2
->ad_tags
.bv_val
= lp
;
415 strcpy(lp
, desc
.ad_tags
.bv_val
);
416 ldap_pvt_str2lower(lp
);
418 d2
->ad_cname
.bv_len
+= 1 + desc
.ad_tags
.bv_len
;
421 /* Add new desc to list. We always want the bare Desc with
422 * no options to stay at the head of the list, assuming
423 * that one will be used most frequently.
425 if (desc
.ad_type
->sat_ad
== NULL
|| dlen
== 0) {
426 d2
->ad_next
= desc
.ad_type
->sat_ad
;
427 desc
.ad_type
->sat_ad
= d2
;
429 d2
->ad_next
= desc
.ad_type
->sat_ad
->ad_next
;
430 desc
.ad_type
->sat_ad
->ad_next
= d2
;
432 ldap_pvt_thread_mutex_unlock( &desc
.ad_type
->sat_ad_mutex
);
444 static int is_ad_subtags(
445 struct berval
*subtagsbv
,
446 struct berval
*suptagsbv
)
448 const char *suptags
, *supp
, *supdelimp
, *supn
;
449 const char *subtags
, *subp
, *subdelimp
, *subn
;
452 subtags
=subtagsbv
->bv_val
;
453 suptags
=suptagsbv
->bv_val
;
454 subn
= subtags
+ subtagsbv
->bv_len
;
455 supn
= suptags
+ suptagsbv
->bv_len
;
457 for( supp
=suptags
; supp
; supp
=supdelimp
) {
458 supdelimp
= strchrlen( supp
, supn
, ';', &suplen
);
459 if( supdelimp
) supdelimp
++;
461 for( subp
=subtags
; subp
; subp
=subdelimp
) {
462 subdelimp
= strchrlen( subp
, subn
, ';', &sublen
);
463 if( subdelimp
) subdelimp
++;
466 ? ( suplen
-1 == sublen
&& supp
[suplen
-1] == '-'
467 && strncmp( supp
, subp
, sublen
) == 0 )
468 : ( ( suplen
== sublen
|| supp
[suplen
-1] == '-' )
469 && strncmp( supp
, subp
, suplen
) == 0 ) )
482 AttributeDescription
*sub
,
483 AttributeDescription
*super
489 for ( a
= sub
->ad_type
; a
; a
=a
->sat_sup
) {
490 if ( a
== super
->ad_type
) break;
496 /* ensure sub does support all flags of super */
497 lr
= sub
->ad_tags
.bv_len
? SLAP_DESC_TAG_RANGE
: 0;
498 if(( super
->ad_flags
& ( sub
->ad_flags
| lr
)) != super
->ad_flags
) {
502 /* check for tagging options */
503 if ( super
->ad_tags
.bv_len
== 0 )
505 if ( sub
->ad_tags
.bv_len
== 0 )
508 return is_ad_subtags( &sub
->ad_tags
, &super
->ad_tags
);
512 AttributeDescription
*desc
,
513 AttributeName
*attrs
)
515 if (! attrs
) return 0;
517 for( ; attrs
->an_name
.bv_val
; attrs
++ ) {
521 if ( attrs
->an_desc
) {
524 if ( desc
== attrs
->an_desc
) {
529 * EXTENSION: if requested description is preceeded by
530 * a '-' character, do not match on subtypes.
532 if ( attrs
->an_name
.bv_val
[0] == '-' ) {
536 /* Is this a subtype of the requested attr? */
537 for (a
= desc
->ad_type
; a
; a
=a
->sat_sup
) {
538 if ( a
== attrs
->an_desc
->ad_type
)
544 /* Does desc support all the requested flags? */
545 lr
= desc
->ad_tags
.bv_len
? SLAP_DESC_TAG_RANGE
: 0;
546 if(( attrs
->an_desc
->ad_flags
& (desc
->ad_flags
| lr
))
547 != attrs
->an_desc
->ad_flags
) {
550 /* Do the descs have compatible tags? */
551 if ( attrs
->an_desc
->ad_tags
.bv_len
== 0 ) {
554 if ( desc
->ad_tags
.bv_len
== 0) {
557 if ( is_ad_subtags( &desc
->ad_tags
,
558 &attrs
->an_desc
->ad_tags
) ) {
564 if ( ber_bvccmp( &attrs
->an_name
, '*' ) ) {
565 if ( !is_at_operational( desc
->ad_type
) ) {
571 if ( ber_bvccmp( &attrs
->an_name
, '+' ) ) {
572 if ( is_at_operational( desc
->ad_type
) ) {
579 * EXTENSION: see if requested description is @objectClass
580 * if so, return attributes which the class requires/allows
581 * else if requested description is !objectClass, return
582 * attributes which the class does not require/allow
585 if( oc
== NULL
&& attrs
->an_name
.bv_val
) {
586 switch( attrs
->an_name
.bv_val
[0] ) {
587 case '@': /* @objectClass */
588 case '+': /* +objectClass (deprecated) */
589 case '!': { /* exclude */
590 struct berval ocname
;
591 ocname
.bv_len
= attrs
->an_name
.bv_len
- 1;
592 ocname
.bv_val
= &attrs
->an_name
.bv_val
[1];
593 oc
= oc_bvfind( &ocname
);
594 attrs
->an_oc_exclude
= 0;
595 if ( oc
&& attrs
->an_name
.bv_val
[0] == '!' ) {
596 attrs
->an_oc_exclude
= 1;
600 default: /* old (deprecated) way */
601 oc
= oc_bvfind( &attrs
->an_name
);
606 if ( attrs
->an_oc_exclude
) {
607 if ( oc
== slap_schema
.si_oc_extensibleObject
) {
608 /* extensibleObject allows the return of anything */
612 if( oc
->soc_required
) {
613 /* allow return of required attributes */
616 for ( i
= 0; oc
->soc_required
[i
] != NULL
; i
++ ) {
617 for (a
= desc
->ad_type
; a
; a
=a
->sat_sup
) {
618 if ( a
== oc
->soc_required
[i
] ) {
625 if( oc
->soc_allowed
) {
626 /* allow return of allowed attributes */
628 for ( i
= 0; oc
->soc_allowed
[i
] != NULL
; i
++ ) {
629 for (a
= desc
->ad_type
; a
; a
=a
->sat_sup
) {
630 if ( a
== oc
->soc_allowed
[i
] ) {
640 if ( oc
== slap_schema
.si_oc_extensibleObject
) {
641 /* extensibleObject allows the return of anything */
645 if( oc
->soc_required
) {
646 /* allow return of required attributes */
649 for ( i
= 0; oc
->soc_required
[i
] != NULL
; i
++ ) {
650 for (a
= desc
->ad_type
; a
; a
=a
->sat_sup
) {
651 if ( a
== oc
->soc_required
[i
] ) {
658 if( oc
->soc_allowed
) {
659 /* allow return of allowed attributes */
661 for ( i
= 0; oc
->soc_allowed
[i
] != NULL
; i
++ ) {
662 for (a
= desc
->ad_type
; a
; a
=a
->sat_sup
) {
663 if ( a
== oc
->soc_allowed
[i
] ) {
673 /* give it a chance of being retrieved by a proxy... */
674 (void)slap_bv2undef_ad( &attrs
->an_name
,
675 &attrs
->an_desc
, &text
,
676 SLAP_AD_PROXIED
|SLAP_AD_NOINSERT
);
684 int slap_str2undef_ad(
686 AttributeDescription
**ad
,
691 bv
.bv_val
= (char *) str
;
692 bv
.bv_len
= strlen( str
);
694 return slap_bv2undef_ad( &bv
, ad
, text
, flags
);
697 int slap_bv2undef_ad(
699 AttributeDescription
**ad
,
703 AttributeDescription
*desc
;
706 assert( ad
!= NULL
);
708 if( bv
== NULL
|| bv
->bv_len
== 0 ) {
709 *text
= "empty AttributeDescription";
710 return LDAP_UNDEFINED_TYPE
;
713 /* make sure description is IA5 */
714 if( ad_keystring( bv
) ) {
715 *text
= "AttributeDescription contains inappropriate characters";
716 return LDAP_UNDEFINED_TYPE
;
719 /* use the appropriate type */
720 if ( flags
& SLAP_AD_PROXIED
) {
721 at
= slap_schema
.si_at_proxied
;
724 at
= slap_schema
.si_at_undefined
;
727 for( desc
= at
->sat_ad
; desc
; desc
=desc
->ad_next
) {
728 if( desc
->ad_cname
.bv_len
== bv
->bv_len
&&
729 !strcasecmp( desc
->ad_cname
.bv_val
, bv
->bv_val
) )
736 if ( flags
& SLAP_AD_NOINSERT
) {
738 return LDAP_UNDEFINED_TYPE
;
741 desc
= ch_malloc(sizeof(AttributeDescription
) + 1 +
744 desc
->ad_flags
= SLAP_DESC_NONE
;
745 BER_BVZERO( &desc
->ad_tags
);
747 desc
->ad_cname
.bv_len
= bv
->bv_len
;
748 desc
->ad_cname
.bv_val
= (char *)(desc
+1);
749 strcpy(desc
->ad_cname
.bv_val
, bv
->bv_val
);
751 /* canonical to upper case */
752 ldap_pvt_str2upper( desc
->ad_cname
.bv_val
);
754 /* shouldn't we protect this for concurrency? */
756 ldap_pvt_thread_mutex_lock( &ad_undef_mutex
);
757 desc
->ad_next
= desc
->ad_type
->sat_ad
;
758 desc
->ad_type
->sat_ad
= desc
;
759 ldap_pvt_thread_mutex_unlock( &ad_undef_mutex
);
761 Debug( LDAP_DEBUG_ANY
,
762 "%s attributeDescription \"%s\" inserted.\n",
763 ( flags
& SLAP_AD_PROXIED
) ? "PROXIED" : "UNKNOWN",
764 desc
->ad_cname
.bv_val
, 0 );
776 AttributeDescription
*
781 AttributeDescription
*ad
=
782 slap_sl_mfuncs
.bmf_malloc( sizeof(AttributeDescription
) +
783 bv
->bv_len
+ 1, memctx
);
785 ad
->ad_cname
.bv_val
= (char *)(ad
+1);
786 strncpy( ad
->ad_cname
.bv_val
, bv
->bv_val
, bv
->bv_len
+1 );
787 ad
->ad_cname
.bv_len
= bv
->bv_len
;
788 ad
->ad_flags
= SLAP_DESC_TEMPORARY
;
789 ad
->ad_type
= slap_schema
.si_at_undefined
;
800 AttributeDescription
**u_ad
, **n_ad
;
802 /* Get to last ad on the new type */
803 for ( n_ad
= &nat
->sat_ad
; *n_ad
; n_ad
= &(*n_ad
)->ad_next
) ;
805 for ( u_ad
= &at
->sat_ad
; *u_ad
; ) {
808 ber_str2bv( name
, 0, 0, &bv
);
810 /* remove iff undef == name or undef == name;tag */
811 if ( (*u_ad
)->ad_cname
.bv_len
>= bv
.bv_len
812 && strncasecmp( (*u_ad
)->ad_cname
.bv_val
, bv
.bv_val
, bv
.bv_len
) == 0
813 && ( (*u_ad
)->ad_cname
.bv_val
[ bv
.bv_len
] == '\0'
814 || (*u_ad
)->ad_cname
.bv_val
[ bv
.bv_len
] == ';' ) )
816 AttributeDescription
*tmp
= *u_ad
;
818 *u_ad
= (*u_ad
)->ad_next
;
822 n_ad
= &tmp
->ad_next
;
824 u_ad
= &(*u_ad
)->ad_next
;
832 slap_ad_undef_promote(
838 ldap_pvt_thread_mutex_lock( &ad_undef_mutex
);
840 rc
= undef_promote( slap_schema
.si_at_undefined
, name
, at
);
842 rc
= undef_promote( slap_schema
.si_at_proxied
, name
, at
);
845 ldap_pvt_thread_mutex_unlock( &ad_undef_mutex
);
856 if( a
== NULL
) return 0;
858 for ( ; a
->an_name
.bv_val
; a
++ ) {
859 if ( a
->an_name
.bv_len
!= s
->bv_len
) continue;
860 if ( strcasecmp( s
->bv_val
, a
->an_name
.bv_val
) == 0 ) {
869 * Convert a delimited string into a list of AttributeNames; add
870 * on to an existing list if it was given. If the string is not
871 * a valid attribute name, if a '-' is prepended it is skipped
872 * and the remaining name is tried again; if a '@' (or '+') is
873 * prepended, an objectclass name is searched instead; if a '!'
874 * is prepended, the objectclass name is negated.
876 * NOTE: currently, if a valid attribute name is not found, the
877 * same string is also checked as valid objectclass name; however,
878 * this behavior is deprecated.
881 str2anlist( AttributeName
*an
, char *in
, const char *brkstr
)
890 /* find last element in list */
893 for ( i
= 0; !BER_BVISNULL( &an
[ i
].an_name
) ; i
++)
897 /* protect the input string from strtok */
898 str
= ch_strdup( in
);
900 /* Count words in string */
902 for ( s
= str
; *s
; s
++ ) {
903 if ( strchr( brkstr
, *s
) != NULL
) {
908 an
= ch_realloc( an
, ( i
+ j
+ 1 ) * sizeof( AttributeName
) );
910 for ( s
= ldap_pvt_strtok( str
, brkstr
, &lasts
);
912 s
= ldap_pvt_strtok( NULL
, brkstr
, &lasts
) )
914 /* put a stop mark */
915 BER_BVZERO( &anew
[1].an_name
);
917 anew
->an_desc
= NULL
;
919 anew
->an_oc_exclude
= 0;
920 ber_str2bv(s
, 0, 1, &anew
->an_name
);
921 slap_bv2ad(&anew
->an_name
, &anew
->an_desc
, &text
);
922 if ( !anew
->an_desc
) {
923 switch( anew
->an_name
.bv_val
[0] ) {
925 struct berval adname
;
926 adname
.bv_len
= anew
->an_name
.bv_len
- 1;
927 adname
.bv_val
= &anew
->an_name
.bv_val
[1];
928 slap_bv2ad(&adname
, &anew
->an_desc
, &text
);
929 if ( !anew
->an_desc
) {
935 case '+': /* (deprecated) */
937 struct berval ocname
;
938 ocname
.bv_len
= anew
->an_name
.bv_len
- 1;
939 ocname
.bv_val
= &anew
->an_name
.bv_val
[1];
940 anew
->an_oc
= oc_bvfind( &ocname
);
941 if ( !anew
->an_oc
) {
945 if ( anew
->an_name
.bv_val
[0] == '!' ) {
946 anew
->an_oc_exclude
= 1;
951 /* old (deprecated) way */
952 anew
->an_oc
= oc_bvfind( &anew
->an_name
);
953 if ( !anew
->an_oc
) {
961 BER_BVZERO( &anew
->an_name
);
966 anlist_free( an
, 1, NULL
);
969 * overwrites input string
978 anlist_free( AttributeName
*an
, int freename
, void *ctx
)
987 for ( i
= 0; an
[i
].an_name
.bv_val
; i
++ ) {
988 ber_memfree_x( an
[i
].an_name
.bv_val
, ctx
);
992 ber_memfree_x( an
, ctx
);
995 char **anlist2charray_x( AttributeName
*an
, int dup
, void *ctx
)
1001 for ( i
= 0; !BER_BVISNULL( &an
[i
].an_name
); i
++ )
1003 attrs
= (char **) slap_sl_malloc( (i
+ 1) * sizeof(char *), ctx
);
1004 for ( i
= 0; !BER_BVISNULL( &an
[i
].an_name
); i
++ ) {
1006 attrs
[i
] = ch_strdup( an
[i
].an_name
.bv_val
);
1008 attrs
[i
] = an
[i
].an_name
.bv_val
;
1018 char **anlist2charray( AttributeName
*an
, int dup
)
1020 return anlist2charray_x( an
, dup
, NULL
);
1024 anlist2attrs( AttributeName
* anlist
)
1031 if ( anlist
== NULL
)
1034 for ( i
= 0; anlist
[i
].an_name
.bv_val
; i
++ ) {
1035 if ( ( oc
= anlist
[i
].an_oc
) ) {
1036 for ( j
= 0; oc
->soc_required
&& oc
->soc_required
[j
]; j
++ ) ;
1038 for ( j
= 0; oc
->soc_allowed
&& oc
->soc_allowed
[j
]; j
++ ) ;
1046 attrs
= anlist2charray( anlist
, 1 );
1051 attrs
= (char **) ch_realloc( attrs
, (i
+ k
+ 1) * sizeof( char * ));
1053 for ( i
= 0; anlist
[i
].an_name
.bv_val
; i
++ ) {
1054 if ( ( oc
= anlist
[i
].an_oc
) ) {
1055 for ( j
= 0; oc
->soc_required
&& oc
->soc_required
[j
]; j
++ ) {
1056 attrs
[n
++] = ch_strdup(
1057 oc
->soc_required
[j
]->sat_cname
.bv_val
);
1059 for ( j
= 0; oc
->soc_allowed
&& oc
->soc_allowed
[j
]; j
++ ) {
1060 attrs
[n
++] = ch_strdup(
1061 oc
->soc_allowed
[j
]->sat_cname
.bv_val
);
1070 while ( attrs
&& attrs
[i
] ) {
1071 if ( *attrs
[i
] == '@' ) {
1072 ch_free( attrs
[i
] );
1073 for ( j
= i
; attrs
[j
]; j
++ ) {
1074 attrs
[j
] = attrs
[j
+1];
1081 for ( i
= 0; attrs
&& attrs
[i
]; i
++ ) {
1083 while ( attrs
&& attrs
[j
] ) {
1084 if ( !strcmp( attrs
[i
], attrs
[j
] )) {
1085 ch_free( attrs
[j
] );
1086 for ( k
= j
; attrs
&& attrs
[k
]; k
++ ) {
1087 attrs
[k
] = attrs
[k
+1];
1096 attrs
= (char **) ch_realloc( attrs
, (i
+1) * sizeof( char * ));
1103 file2anlist( AttributeName
*an
, const char *fname
, const char *brkstr
)
1109 size_t lmax
= LBUFSIZ
;
1111 fp
= fopen( fname
, "r" );
1113 Debug( LDAP_DEBUG_ANY
,
1114 "get_attrs_from_file: failed to open attribute list file "
1115 "\"%s\": %s\n", fname
, strerror(errno
), 0 );
1119 lcur
= line
= (char *) ch_malloc( lmax
);
1121 Debug( LDAP_DEBUG_ANY
,
1122 "get_attrs_from_file: could not allocate memory\n",
1128 while ( fgets( lcur
, LBUFSIZ
, fp
) != NULL
) {
1129 if ( ( c
= strchr( lcur
, '\n' ) ) ) {
1132 } else if ( *(c
-1) == '\r' ) {
1139 line
= (char *) ch_realloc( line
, lmax
);
1141 Debug( LDAP_DEBUG_ANY
,
1142 "get_attrs_from_file: could not allocate memory\n",
1147 lcur
= line
+ strlen( line
);
1150 an
= str2anlist( an
, line
, brkstr
);
1161 /* Define an attribute option. */
1163 ad_define_option( const char *name
, const char *fname
, int lineno
)
1166 unsigned int optlen
;
1168 if ( options
== &lang_option
) {
1177 if ( !DESC_CHAR( name
[optlen
] ) ) {
1178 Debug( LDAP_DEBUG_ANY
,
1179 "%s: line %d: illegal option name \"%s\"\n",
1180 fname
, lineno
, name
);
1183 } while ( name
[++optlen
] );
1185 options
= ch_realloc( options
,
1186 (option_count
+1) * sizeof(Attr_option
) );
1188 if ( strcasecmp( name
, "binary" ) == 0
1189 || ad_find_option_definition( name
, optlen
) ) {
1190 Debug( LDAP_DEBUG_ANY
,
1191 "%s: line %d: option \"%s\" is already defined\n",
1192 fname
, lineno
, name
);
1196 for ( i
= option_count
; i
; --i
) {
1197 if ( strcasecmp( name
, options
[i
-1].name
.bv_val
) >= 0 )
1199 options
[i
] = options
[i
-1];
1202 options
[i
].name
.bv_val
= ch_strdup( name
);
1203 options
[i
].name
.bv_len
= optlen
;
1204 options
[i
].prefix
= (name
[optlen
-1] == '-');
1206 if ( i
!= option_count
&&
1207 options
[i
].prefix
&&
1208 optlen
< options
[i
+1].name
.bv_len
&&
1209 strncasecmp( name
, options
[i
+1].name
.bv_val
, optlen
) == 0 ) {
1210 Debug( LDAP_DEBUG_ANY
,
1211 "%s: line %d: option \"%s\" overrides previous option\n",
1212 fname
, lineno
, name
);
1221 ad_unparse_options( BerVarray
*res
)
1224 for ( i
= 0; i
< option_count
; i
++ ) {
1225 value_add_one( res
, &options
[i
].name
);
1229 /* Find the definition of the option name or prefix matching the arguments */
1230 static Attr_option
*
1231 ad_find_option_definition( const char *opt
, int optlen
)
1233 int top
= 0, bot
= option_count
;
1234 while ( top
< bot
) {
1235 int mid
= (top
+ bot
) / 2;
1236 int mlen
= options
[mid
].name
.bv_len
;
1237 char *mname
= options
[mid
].name
.bv_val
;
1239 if ( optlen
< mlen
) {
1240 j
= strncasecmp( opt
, mname
, optlen
) - 1;
1242 j
= strncasecmp( opt
, mname
, mlen
);
1243 if ( j
==0 && (optlen
==mlen
|| options
[mid
].prefix
) )
1244 return &options
[mid
];
1254 MatchingRule
*ad_mr(
1255 AttributeDescription
*ad
,
1258 switch( usage
& SLAP_MR_TYPE_MASK
) {
1260 case SLAP_MR_EQUALITY
:
1261 return ad
->ad_type
->sat_equality
;
1263 case SLAP_MR_ORDERING
:
1264 return ad
->ad_type
->sat_ordering
;
1266 case SLAP_MR_SUBSTR
:
1267 return ad
->ad_type
->sat_substr
;
1271 assert( 0 /* ad_mr: bad usage */);