/* $OpenLDAP$ */
/*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
/* ad.c - routines for dealing with attribute descriptions */
return 0;
}
-void ad_destroy( void *in )
+void ad_destroy( AttributeDescription *ad )
{
- AttributeDescription *ad = in, *n;
+ AttributeDescription *n;
- for (;ad;ad = n) {
+ for (; ad != NULL; ad = n) {
n = ad->ad_next;
- ldap_memfree(ad);
+ ldap_memfree( ad );
}
}
return slap_bv2ad( &bv, ad, text );
}
+static char *strchrlen(
+ const char *p,
+ const char ch,
+ int *len )
+{
+ int i;
+
+ for( i=0; p[i]; i++ ) {
+ if( p[i] == ch ) {
+ *len = i;
+ return (char *) &p[i];
+ }
+ }
+
+ *len = i;
+ return NULL;
+}
+
int slap_bv2ad(
struct berval *bv,
AttributeDescription **ad,
const char **text )
{
int rtn = LDAP_UNDEFINED_TYPE;
- int i;
AttributeDescription desc, *d2;
char *name, *options;
+ char *opt, *next;
+ int nlang;
+ int langlen;
+
+ /* hardcoded limits for speed */
+#define MAX_LANG_OPTIONS 128
+ struct berval langs[MAX_LANG_OPTIONS+1];
+#define MAX_LANG_LEN 1024
+ char langbuf[MAX_LANG_LEN];
assert( ad != NULL );
assert( *ad == NULL ); /* temporary */
}
/* find valid base attribute type; parse in place */
+ memset( &desc, 0, sizeof( desc ));
desc.ad_cname = *bv;
name = bv->bv_val;
options = strchr(name, ';');
- if (options != NULL)
+ if( options != NULL ) {
desc.ad_cname.bv_len = options - name;
+ }
desc.ad_type = at_bvfind( &desc.ad_cname );
if( desc.ad_type == NULL ) {
*text = "attribute type undefined";
return rtn;
}
- desc.ad_flags = SLAP_DESC_NONE;
- desc.ad_lang.bv_len = 0;
- desc.ad_lang.bv_val = NULL;
-
- /* parse options in place */
- for( ; options != NULL; ) {
- name = options+1;
- options = strchr( name, ';' );
- if ( options != NULL )
- i = options - name;
- else
- i = bv->bv_len - (name - bv->bv_val);
+ if( is_at_operational( desc.ad_type ) && options != NULL ) {
+ *text = "operational attribute with options undefined";
+ return rtn;
+ }
- if( i == sizeof("binary")-1 && strncasecmp( name, "binary", i) == 0 ) {
+ /*
+ * parse options in place
+ */
+ nlang = 0;
+ memset( langs, 0, sizeof( langs ));
+ langlen = 0;
+
+ for( opt=options; opt != NULL; opt=next ) {
+ int optlen;
+ opt++;
+ next = strchrlen( opt, ';', &optlen );
+
+ if( optlen == 0 ) {
+ *text = "zero length option is invalid";
+ return rtn;
+
+ } else if ( optlen == sizeof("binary")-1 &&
+ strncasecmp( opt, "binary", sizeof("binary")-1 ) == 0 )
+ {
+ /* binary option */
if( slap_ad_is_binary( &desc ) ) {
*text = "option \"binary\" specified multiple times";
- goto done;
+ return rtn;
}
if( !slap_syntax_is_binary( desc.ad_type->sat_syntax )) {
/* not stored in binary, disallow option */
- *text = "option \"binary\" with type not supported";
- goto done;
+ *text = "option \"binary\" not supported with type";
+ return rtn;
}
desc.ad_flags |= SLAP_DESC_BINARY;
+ continue;
- } else if ( i >= sizeof("lang-") && strncasecmp( name, "lang-",
- sizeof("lang-")-1 ) == 0)
+ } else if ( optlen >= sizeof("lang-")-1 &&
+ strncasecmp( opt, "lang-", sizeof("lang-")-1 ) == 0 )
{
- if( desc.ad_lang.bv_len != 0 ) {
- *text = "multiple language tag options specified";
- goto done;
+ int i;
+
+ if( opt[optlen-1] == '-' ) {
+ desc.ad_flags |= SLAP_DESC_LANG_RANGE;
+ }
+
+ if( nlang >= MAX_LANG_OPTIONS ) {
+ *text = "too many language options";
+ return rtn;
}
- desc.ad_lang.bv_val = name;
- desc.ad_lang.bv_len = i;
+ /*
+ * tags should be presented in sorted order,
+ * so run the array in reverse.
+ */
+ for( i=nlang-1; i>=0; i-- ) {
+ int rc;
+
+ rc = strncasecmp( opt, langs[i].bv_val,
+ (unsigned) optlen < langs[i].bv_len
+ ? optlen : langs[i].bv_len );
+
+ if( rc == 0 && (unsigned)optlen == langs[i].bv_len ) {
+ /* duplicate (ignore) */
+ goto done;
+
+ } else if ( rc > 0 ||
+ ( rc == 0 && (unsigned)optlen > langs[i].bv_len ))
+ {
+ AC_MEMCPY( &langs[i+1], &langs[i],
+ (nlang-i)*sizeof(struct berval) );
+ langs[i].bv_val = opt;
+ langs[i].bv_len = optlen;
+ goto done;
+ }
+ }
+
+ if( nlang ) {
+ AC_MEMCPY( &langs[1], &langs[0],
+ nlang*sizeof(struct berval) );
+ }
+ langs[0].bv_val = opt;
+ langs[0].bv_len = optlen;
+
+done:;
+ langlen += optlen + 1;
+ nlang++;
+
} else {
*text = "unrecognized option";
- goto done;
+ return rtn;
+ }
+ }
+
+ if( nlang > 0 ) {
+ int i;
+
+ if( langlen > MAX_LANG_LEN ) {
+ *text = "language options too long";
+ return rtn;
}
+
+ desc.ad_lang.bv_val = langbuf;
+ langlen = 0;
+
+ for( i=0; i<nlang; i++ ) {
+ AC_MEMCPY( &desc.ad_lang.bv_val[langlen],
+ langs[i].bv_val, langs[i].bv_len );
+
+ langlen += langs[i].bv_len;
+ desc.ad_lang.bv_val[langlen++] = ';';
+ }
+
+ desc.ad_lang.bv_val[--langlen] = '\0';
+ desc.ad_lang.bv_len = langlen;
}
/* see if a matching description is already cached */
for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
- if (d2->ad_flags != desc.ad_flags)
+ if( d2->ad_flags != desc.ad_flags ) {
continue;
- if (d2->ad_lang.bv_len != desc.ad_lang.bv_len)
+ }
+ if( d2->ad_lang.bv_len != desc.ad_lang.bv_len ) {
continue;
- if (d2->ad_lang.bv_len == 0)
+ }
+ if( d2->ad_lang.bv_len == 0 ) {
break;
- if (strncasecmp(d2->ad_lang.bv_val, desc.ad_lang.bv_val,
- desc.ad_lang.bv_len) == 0)
+ }
+ if( strncasecmp( d2->ad_lang.bv_val, desc.ad_lang.bv_val,
+ desc.ad_lang.bv_len ) == 0 )
+ {
break;
+ }
}
/* Not found, add new one */
while (d2 == NULL) {
- int dlen = 0;
+ size_t dlen = 0;
ldap_pvt_thread_mutex_lock( &desc.ad_type->sat_ad_mutex );
/* check again now that we've locked */
for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
* Otherwise, we need to tack on the full name length +
* options length.
*/
- i = sizeof(AttributeDescription);
if (desc.ad_lang.bv_len || desc.ad_flags != SLAP_DESC_NONE) {
- if (desc.ad_lang.bv_len)
- dlen = desc.ad_lang.bv_len+1;
- dlen += desc.ad_type->sat_cname.bv_len+1;
+ dlen = desc.ad_type->sat_cname.bv_len;
+ if (desc.ad_lang.bv_len) {
+ dlen += 1+desc.ad_lang.bv_len;
+ }
if( slap_ad_is_binary( &desc ) ) {
- dlen += sizeof("binary");
+ dlen += sizeof(";binary")-1;
}
}
- d2 = ch_malloc(i + dlen);
+ d2 = ch_malloc(sizeof(AttributeDescription) + dlen + 1);
d2->ad_type = desc.ad_type;
d2->ad_flags = desc.ad_flags;
- d2->ad_cname.bv_len = desc.ad_cname.bv_len;
+ d2->ad_cname.bv_len = desc.ad_type->sat_cname.bv_len;
d2->ad_lang.bv_len = desc.ad_lang.bv_len;
+
if (dlen == 0) {
d2->ad_cname.bv_val = d2->ad_type->sat_cname.bv_val;
d2->ad_lang.bv_val = NULL;
if( slap_ad_is_binary( &desc ) ) {
strcpy(d2->ad_cname.bv_val+d2->ad_cname.bv_len,
";binary");
- d2->ad_cname.bv_len += sizeof("binary");
+ d2->ad_cname.bv_len += sizeof(";binary")-1;
}
if( d2->ad_lang.bv_len ) {
d2->ad_cname.bv_val[d2->ad_cname.bv_len++]=';';
**ad = *d2;
}
- rtn = LDAP_SUCCESS;
+ return LDAP_SUCCESS;
+}
+
+static int is_ad_sublang(
+ const char *sublang,
+ const char *suplang )
+{
+ const char *supp, *supdelimp;
+ const char *subp, *subdelimp;
+ int suplen, sublen;
+
+ if( suplang == NULL ) return 1;
+ if( sublang == NULL ) return 0;
+
+ for( supp=suplang ; supp; supp=supdelimp ) {
+ supdelimp = strchrlen( supp, ';', &suplen );
+ if( supdelimp ) supdelimp++;
+
+ for( subp=sublang ; subp; subp=subdelimp ) {
+ subdelimp = strchrlen( subp, ';', &sublen );
+ if( subdelimp ) subdelimp++;
+
+ if ((( suplen < sublen && supp[suplen-1] == '-' ) ||
+ suplen == sublen ) && strncmp( supp, subp, suplen ) == 0 )
+ {
+ goto match;
+ }
+ }
-done:
- return rtn;
+ return 0;
+match:;
+ }
+ return 1;
}
int is_ad_subtype(
AttributeDescription *super
)
{
+ int lr;
+
if( !is_at_subtype( sub->ad_type, super->ad_type ) ) {
return 0;
}
- if( super->ad_flags && ( super->ad_flags != sub->ad_flags )) {
+ /* ensure sub does support all flags of super */
+ lr = sub->ad_lang.bv_len ? SLAP_DESC_LANG_RANGE : 0;
+ if(( super->ad_flags & ( sub->ad_flags | lr )) != super->ad_flags ) {
return 0;
}
- if( super->ad_lang.bv_len && (sub->ad_lang.bv_len !=
- super->ad_lang.bv_len || strcmp( super->ad_lang.bv_val,
- sub->ad_lang.bv_val)))
- {
+ /* check for language tags */
+ if ( !is_ad_sublang( sub->ad_lang.bv_val, super->ad_lang.bv_val )) {
return 0;
}
return 1;
}
-
int ad_inlist(
AttributeDescription *desc,
AttributeName *attrs )
{
- for( ; attrs; attrs=attrs->an_next ) {
+ if (! attrs ) return 0;
+
+ for( ; attrs->an_name.bv_val; attrs++ ) {
ObjectClass *oc;
int rc;
continue;
}
-
/*
* EXTENSION: see if requested description is an object class
* if so, return attributes which the class requires/allows
*/
- oc = oc_bvfind( &attrs->an_name );
+ oc = attrs->an_oc;
+ if( oc == NULL ) {
+ oc = oc_bvfind( &attrs->an_name );
+ attrs->an_oc = oc;
+ }
if( oc != NULL ) {
if ( oc == slap_schema.si_oc_extensibleObject ) {
/* extensibleObject allows the return of anything */
int i;
for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
rc = is_at_subtype( desc->ad_type,
- oc->soc_allowed[i] );
+ oc->soc_required[i] );
if( rc ) return 1;
}
}
+
if( oc->soc_allowed ) {
/* allow return of allowed attributes */
int i;
if( rc ) return 1;
}
}
+
} else {
/* short-circuit this search next time around */
if (!slap_schema.si_at_undefined->sat_ad) {
return LDAP_UNDEFINED_TYPE;
}
- for (desc = slap_schema.si_at_undefined->sat_ad; desc;
- desc=desc->ad_next)
- if (desc->ad_cname.bv_len == bv->bv_len &&
- !strcasecmp(desc->ad_cname.bv_val, bv->bv_val))
+ for( desc = slap_schema.si_at_undefined->sat_ad; desc;
+ desc=desc->ad_next )
+ {
+ if( desc->ad_cname.bv_len == bv->bv_len &&
+ !strcasecmp( desc->ad_cname.bv_val, bv->bv_val ))
+ {
break;
+ }
+ }
- if (!desc) {
- desc = ch_malloc(sizeof(AttributeDescription) +
- bv->bv_len + 1);
+ if( !desc ) {
+ desc = ch_malloc(sizeof(AttributeDescription) + 1 +
+ bv->bv_len);
desc->ad_flags = SLAP_DESC_NONE;
desc->ad_lang.bv_val = NULL;
desc->ad_type->sat_ad = desc;
}
- if (!*ad)
+ if( !*ad ) {
*ad = desc;
- else
+ } else {
**ad = *desc;
+ }
return LDAP_SUCCESS;
}
{
if( a == NULL ) return 0;
- for ( ; a; a=a->an_next ) {
+ for ( ; a->an_name.bv_val; a++ ) {
if ( a->an_name.bv_len != s->bv_len) continue;
if ( strcasecmp( s->bv_val, a->an_name.bv_val ) == 0 ) {
return( 1 );
* to an existing list if it was given.
*/
AttributeName *
-str2anlist( AttributeName *an, const char *in, const char *brkstr )
+str2anlist( AttributeName *an, char *in, const char *brkstr )
{
char *str;
char *s;
char *lasts;
+ int i, j;
const char *text;
- AttributeName *a, *anew;
+ AttributeName *anew;
+ /* find last element in list */
+ for (i = 0; an && an[i].an_name.bv_val; i++);
+
/* protect the input string from strtok */
str = ch_strdup( in );
- /* find last element in list */
- for (a = an; a && a->an_next; a=a->an_next);
-
+ /* Count words in string */
+ j=1;
+ for ( s = str; *s; s++ ) {
+ if ( strchr( brkstr, *s ) != NULL ) {
+ j++;
+ }
+ }
+
+ an = ch_realloc( an, ( i + j + 1 ) * sizeof( AttributeName ) );
+ anew = an + i;
for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
s != NULL;
s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
{
- anew = ch_malloc( sizeof( AttributeName ) );
- anew->an_next = NULL;
anew->an_desc = NULL;
+ anew->an_oc = NULL;
ber_str2bv(s, 0, 1, &anew->an_name);
slap_bv2ad(&anew->an_name, &anew->an_desc, &text);
- if (!an) {
- an = anew;
- } else {
- a->an_next = anew;
+ if ( !anew->an_desc ) {
+ anew->an_oc = oc_bvfind( &anew->an_name );
+ if ( !anew->an_oc ) {
+ free( an );
+ /* overwrites input string on error! */
+ strcpy( in, s );
+ return NULL;
+ }
}
- a = anew;
+ anew++;
}
+ anew->an_name.bv_val = NULL;
free( str );
return( an );
}
+