X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fad.c;h=3d1335b435d86c45d0073b9794e92502be90c6a8;hb=c5b6a86502dc0c16027cd87e3d9544e9078083db;hp=7d413ea87cf390215add7b734dc7a2189f51b045;hpb=92c6c9c25dda27b767755e8d4df5e7ba63db78c2;p=openldap diff --git a/servers/slapd/ad.c b/servers/slapd/ad.c index 7d413ea87c..3d1335b435 100644 --- a/servers/slapd/ad.c +++ b/servers/slapd/ad.c @@ -1,6 +1,6 @@ /* $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 */ @@ -35,13 +35,13 @@ static int ad_keystring( 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 ); } } @@ -75,15 +75,41 @@ int slap_str2ad( 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 */ @@ -100,76 +126,159 @@ int slap_bv2ad( } /* 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; + } + + /* + * 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++; - desc.ad_lang.bv_val = name; - desc.ad_lang.bv_len = i; } 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; isat_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) { @@ -193,21 +302,22 @@ int slap_bv2ad( * 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; @@ -217,7 +327,7 @@ int slap_bv2ad( 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++]=';'; @@ -250,10 +360,39 @@ int slap_bv2ad( **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++; -done: - return rtn; + 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; + } + } + + return 0; +match:; + } + return 1; } int is_ad_subtype( @@ -261,40 +400,39 @@ 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, - struct berval **attrs ) + AttributeName *attrs ) { - int i; - for( i=0; attrs[i] != NULL; i++ ) { + if (! attrs ) return 0; + + for( ; attrs->an_name.bv_val; attrs++ ) { ObjectClass *oc; - AttributeDescription *ad = NULL; - const char *text; int rc; - rc = slap_bv2ad( attrs[i], &ad, &text ); - if( rc == LDAP_SUCCESS ) { - rc = is_ad_subtype( desc, ad ); - if( rc ) return 1; + if ( attrs->an_desc ) { + if ( is_ad_subtype( desc, attrs->an_desc )) + return 1; continue; } @@ -302,7 +440,11 @@ int ad_inlist( * EXTENSION: see if requested description is an object class * if so, return attributes which the class requires/allows */ - oc = oc_bvfind( attrs[i] ); + 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 */ @@ -314,10 +456,11 @@ int ad_inlist( 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; @@ -327,6 +470,17 @@ int ad_inlist( if( rc ) return 1; } } + + } else { + /* short-circuit this search next time around */ + if (!slap_schema.si_at_undefined->sat_ad) { + const char *text; + slap_bv2undef_ad(&attrs->an_name, + &attrs->an_desc, &text); + } else { + attrs->an_desc = + slap_schema.si_at_undefined->sat_ad; + } } } @@ -366,15 +520,19 @@ int slap_bv2undef_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; @@ -392,10 +550,84 @@ int slap_bv2undef_ad( desc->ad_type->sat_ad = desc; } - if (!*ad) + if( !*ad ) { *ad = desc; - else + } else { **ad = *desc; + } return LDAP_SUCCESS; } + +int +an_find( + AttributeName *a, + struct berval *s +) +{ + if( a == NULL ) return 0; + + 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 ); + } + } + + return( 0 ); +} + +/* Convert a delimited string into a list of AttributeNames; Add on + * to an existing list if it was given. + */ +AttributeName * +str2anlist( AttributeName *an, char *in, const char *brkstr ) +{ + char *str; + char *s; + char *lasts; + int i, j; + const char *text; + 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 ); + + /* 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->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 ( !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; + } + } + anew++; + } + anew->an_name.bv_val = NULL; + + free( str ); + return( an ); +} +