Back to index

openldap  2.4.31
ad.c
Go to the documentation of this file.
00001 /* ad.c - routines for dealing with attribute descriptions */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 
00021 #include <ac/ctype.h>
00022 #include <ac/errno.h>
00023 #include <ac/socket.h>
00024 #include <ac/string.h>
00025 #include <ac/time.h>
00026 
00027 #include "slap.h"
00028 #include "lutil.h"
00029 
00030 static struct berval bv_no_attrs = BER_BVC( LDAP_NO_ATTRS );
00031 static struct berval bv_all_user_attrs = BER_BVC( "*" );
00032 static struct berval bv_all_operational_attrs = BER_BVC( "+" );
00033 
00034 static AttributeName anlist_no_attrs[] = {
00035        { BER_BVC( LDAP_NO_ATTRS ), NULL, 0, NULL },
00036        { BER_BVNULL, NULL, 0, NULL }
00037 };
00038 
00039 static AttributeName anlist_all_user_attributes[] = {
00040        { BER_BVC( LDAP_ALL_USER_ATTRIBUTES ), NULL, 0, NULL },
00041        { BER_BVNULL, NULL, 0, NULL }
00042 };
00043 
00044 static AttributeName anlist_all_operational_attributes[] = {
00045        { BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ), NULL, 0, NULL },
00046        { BER_BVNULL, NULL, 0, NULL }
00047 };
00048 
00049 static AttributeName anlist_all_attributes[] = {
00050        { BER_BVC( LDAP_ALL_USER_ATTRIBUTES ), NULL, 0, NULL },
00051        { BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ), NULL, 0, NULL },
00052        { BER_BVNULL, NULL, 0, NULL }
00053 };
00054 
00055 AttributeName *slap_anlist_no_attrs = anlist_no_attrs;
00056 AttributeName *slap_anlist_all_user_attributes = anlist_all_user_attributes;
00057 AttributeName *slap_anlist_all_operational_attributes = anlist_all_operational_attributes;
00058 AttributeName *slap_anlist_all_attributes = anlist_all_attributes;
00059 
00060 struct berval * slap_bv_no_attrs = &bv_no_attrs;
00061 struct berval * slap_bv_all_user_attrs = &bv_all_user_attrs;
00062 struct berval * slap_bv_all_operational_attrs = &bv_all_operational_attrs;
00063 
00064 typedef struct Attr_option {
00065        struct berval name;  /* option name or prefix */
00066        int           prefix;       /* NAME is a tag and range prefix */
00067 } Attr_option;
00068 
00069 static Attr_option lang_option = { BER_BVC("lang-"), 1 };
00070 
00071 /* Options sorted by name, and number of options */
00072 static Attr_option *options = &lang_option;
00073 static int option_count = 1;
00074 
00075 static int msad_range_hack = 0;
00076 
00077 static int ad_count;
00078 
00079 static Attr_option *ad_find_option_definition( const char *opt, int optlen );
00080 
00081 int ad_keystring(
00082        struct berval *bv )
00083 {
00084        ber_len_t i;
00085 
00086        if( !AD_LEADCHAR( bv->bv_val[0] ) ) {
00087               return 1;
00088        }
00089 
00090        for( i=1; i<bv->bv_len; i++ ) {
00091               if( !AD_CHAR( bv->bv_val[i] )) {
00092                      if ( msad_range_hack && bv->bv_val[i] == '=' )
00093                             continue;
00094                      return 1;
00095               }
00096        }
00097        return 0;
00098 }
00099 
00100 void ad_destroy( AttributeDescription *ad )
00101 {
00102        AttributeDescription *n;
00103 
00104        for (; ad != NULL; ad = n) {
00105               n = ad->ad_next;
00106               ldap_memfree( ad );
00107        }
00108 }
00109 
00110 /* Is there an AttributeDescription for this type that uses these tags? */
00111 AttributeDescription * ad_find_tags(
00112        AttributeType *type,
00113        struct berval *tags )
00114 {
00115        AttributeDescription *ad;
00116 
00117        ldap_pvt_thread_mutex_lock( &type->sat_ad_mutex );
00118        for (ad = type->sat_ad; ad; ad=ad->ad_next)
00119        {
00120               if (ad->ad_tags.bv_len == tags->bv_len &&
00121                      !strcasecmp(ad->ad_tags.bv_val, tags->bv_val))
00122                      break;
00123        }
00124        ldap_pvt_thread_mutex_unlock( &type->sat_ad_mutex );
00125        return ad;
00126 }
00127 
00128 int slap_str2ad(
00129        const char *str,
00130        AttributeDescription **ad,
00131        const char **text )
00132 {
00133        struct berval bv;
00134        bv.bv_val = (char *) str;
00135        bv.bv_len = strlen( str );
00136 
00137        return slap_bv2ad( &bv, ad, text );
00138 }
00139 
00140 static char *strchrlen(
00141        const char *beg, 
00142        const char *end,
00143        const char ch, 
00144        int *len )
00145 {
00146        const char *p;
00147 
00148        for( p=beg; *p && p < end; p++ ) {
00149               if( *p == ch ) {
00150                      *len = p - beg;
00151                      return (char *) p;
00152               }
00153        }
00154 
00155        *len = p - beg;
00156        return NULL;
00157 }
00158 
00159 int slap_bv2ad(
00160        struct berval *bv,
00161        AttributeDescription **ad,
00162        const char **text )
00163 {
00164        int rtn = LDAP_UNDEFINED_TYPE;
00165        AttributeDescription desc, *d2;
00166        char *name, *options, *optn;
00167        char *opt, *next;
00168        int ntags;
00169        int tagslen;
00170 
00171        /* hardcoded limits for speed */
00172 #define MAX_TAGGING_OPTIONS 128
00173        struct berval tags[MAX_TAGGING_OPTIONS+1];
00174 #define MAX_TAGS_LEN 1024
00175        char tagbuf[MAX_TAGS_LEN];
00176 
00177        assert( ad != NULL );
00178        assert( *ad == NULL ); /* temporary */
00179 
00180        if( bv == NULL || BER_BVISNULL( bv ) || BER_BVISEMPTY( bv ) ) {
00181               *text = "empty AttributeDescription";
00182               return rtn;
00183        }
00184 
00185        /* make sure description is IA5 */
00186        if( ad_keystring( bv ) ) {
00187               *text = "AttributeDescription contains inappropriate characters";
00188               return rtn;
00189        }
00190 
00191        /* find valid base attribute type; parse in place */
00192        desc.ad_cname = *bv;
00193        desc.ad_flags = 0;
00194        BER_BVZERO( &desc.ad_tags );
00195        name = bv->bv_val;
00196        options = ber_bvchr( bv, ';' );
00197        if ( options != NULL && (unsigned) ( options - name ) < bv->bv_len ) {
00198               /* don't go past the end of the berval! */
00199               desc.ad_cname.bv_len = options - name;
00200        } else {
00201               options = NULL;
00202        }
00203        desc.ad_type = at_bvfind( &desc.ad_cname );
00204        if( desc.ad_type == NULL ) {
00205               *text = "attribute type undefined";
00206               return rtn;
00207        }
00208 
00209        if( is_at_operational( desc.ad_type ) && options != NULL ) {
00210               *text = "operational attribute with options undefined";
00211               return rtn;
00212        }
00213 
00214        /*
00215         * parse options in place
00216         */
00217        ntags = 0;
00218        tagslen = 0;
00219        optn = bv->bv_val + bv->bv_len;
00220 
00221        for( opt=options; opt != NULL; opt=next ) {
00222               int optlen;
00223               opt++; 
00224               next = strchrlen( opt, optn, ';', &optlen );
00225 
00226               if( optlen == 0 ) {
00227                      *text = "zero length option is invalid";
00228                      return rtn;
00229               
00230               } else if ( optlen == STRLENOF("binary") &&
00231                      strncasecmp( opt, "binary", STRLENOF("binary") ) == 0 )
00232               {
00233                      /* binary option */
00234                      if( slap_ad_is_binary( &desc ) ) {
00235                             *text = "option \"binary\" specified multiple times";
00236                             return rtn;
00237                      }
00238 
00239                      if( !slap_syntax_is_binary( desc.ad_type->sat_syntax )) {
00240                             /* not stored in binary, disallow option */
00241                             *text = "option \"binary\" not supported with type";
00242                             return rtn;
00243                      }
00244 
00245                      desc.ad_flags |= SLAP_DESC_BINARY;
00246                      continue;
00247 
00248               } else if ( ad_find_option_definition( opt, optlen ) ) {
00249                      int i;
00250 
00251                      if( opt[optlen-1] == '-' ||
00252                             ( opt[optlen-1] == '=' && msad_range_hack )) {
00253                             desc.ad_flags |= SLAP_DESC_TAG_RANGE;
00254                      }
00255 
00256                      if( ntags >= MAX_TAGGING_OPTIONS ) {
00257                             *text = "too many tagging options";
00258                             return rtn;
00259                      }
00260 
00261                      /*
00262                       * tags should be presented in sorted order,
00263                       * so run the array in reverse.
00264                       */
00265                      for( i=ntags-1; i>=0; i-- ) {
00266                             int rc;
00267 
00268                             rc = strncasecmp( opt, tags[i].bv_val,
00269                                    (unsigned) optlen < tags[i].bv_len
00270                                           ? (unsigned) optlen : tags[i].bv_len );
00271 
00272                             if( rc == 0 && (unsigned)optlen == tags[i].bv_len ) {
00273                                    /* duplicate (ignore) */
00274                                    goto done;
00275 
00276                             } else if ( rc > 0 ||
00277                                    ( rc == 0 && (unsigned)optlen > tags[i].bv_len ))
00278                             {
00279                                    AC_MEMCPY( &tags[i+2], &tags[i+1],
00280                                           (ntags-i-1)*sizeof(struct berval) );
00281                                    tags[i+1].bv_val = opt;
00282                                    tags[i+1].bv_len = optlen;
00283                                    goto done;
00284                             }
00285                      }
00286 
00287                      if( ntags ) {
00288                             AC_MEMCPY( &tags[1], &tags[0],
00289                                    ntags*sizeof(struct berval) );
00290                      }
00291                      tags[0].bv_val = opt;
00292                      tags[0].bv_len = optlen;
00293 
00294 done:;
00295                      tagslen += optlen + 1;
00296                      ntags++;
00297 
00298               } else {
00299                      *text = "unrecognized option";
00300                      return rtn;
00301               }
00302        }
00303 
00304        if( ntags > 0 ) {
00305               int i;
00306 
00307               if( tagslen > MAX_TAGS_LEN ) {
00308                      *text = "tagging options too long";
00309                      return rtn;
00310               }
00311 
00312               desc.ad_tags.bv_val = tagbuf;
00313               tagslen = 0;
00314 
00315               for( i=0; i<ntags; i++ ) {
00316                      AC_MEMCPY( &desc.ad_tags.bv_val[tagslen],
00317                             tags[i].bv_val, tags[i].bv_len );
00318 
00319                      tagslen += tags[i].bv_len;
00320                      desc.ad_tags.bv_val[tagslen++] = ';';
00321               }
00322 
00323               desc.ad_tags.bv_val[--tagslen] = '\0';
00324               desc.ad_tags.bv_len = tagslen;
00325        }
00326 
00327        /* see if a matching description is already cached */
00328        for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
00329               if( d2->ad_flags != desc.ad_flags ) {
00330                      continue;
00331               }
00332               if( d2->ad_tags.bv_len != desc.ad_tags.bv_len ) {
00333                      continue;
00334               }
00335               if( d2->ad_tags.bv_len == 0 ) {
00336                      break;
00337               }
00338               if( strncasecmp( d2->ad_tags.bv_val, desc.ad_tags.bv_val,
00339                      desc.ad_tags.bv_len ) == 0 )
00340               {
00341                      break;
00342               }
00343        }
00344 
00345        /* Not found, add new one */
00346        while (d2 == NULL) {
00347               size_t dlen = 0;
00348               ldap_pvt_thread_mutex_lock( &desc.ad_type->sat_ad_mutex );
00349               /* check again now that we've locked */
00350               for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
00351                      if (d2->ad_flags != desc.ad_flags)
00352                             continue;
00353                      if (d2->ad_tags.bv_len != desc.ad_tags.bv_len)
00354                             continue;
00355                      if (d2->ad_tags.bv_len == 0)
00356                             break;
00357                      if (strncasecmp(d2->ad_tags.bv_val, desc.ad_tags.bv_val,
00358                             desc.ad_tags.bv_len) == 0)
00359                             break;
00360               }
00361               if (d2) {
00362                      ldap_pvt_thread_mutex_unlock( &desc.ad_type->sat_ad_mutex );
00363                      break;
00364               }
00365 
00366               /* Allocate a single contiguous block. If there are no
00367                * options, we just need space for the AttrDesc structure.
00368                * Otherwise, we need to tack on the full name length +
00369                * options length, + maybe tagging options length again.
00370                */
00371               if (desc.ad_tags.bv_len || desc.ad_flags != SLAP_DESC_NONE) {
00372                      dlen = desc.ad_type->sat_cname.bv_len + 1;
00373                      if (desc.ad_tags.bv_len) {
00374                             dlen += 1 + desc.ad_tags.bv_len;
00375                      }
00376                      if ( slap_ad_is_binary( &desc ) ) {
00377                             dlen += 1 + STRLENOF(";binary") + desc.ad_tags.bv_len;
00378                      }
00379               }
00380 
00381               d2 = ch_malloc(sizeof(AttributeDescription) + dlen);
00382               d2->ad_next = NULL;
00383               d2->ad_type = desc.ad_type;
00384               d2->ad_flags = desc.ad_flags;
00385               d2->ad_cname.bv_len = desc.ad_type->sat_cname.bv_len;
00386               d2->ad_tags.bv_len = desc.ad_tags.bv_len;
00387               ldap_pvt_thread_mutex_lock( &ad_index_mutex );
00388               d2->ad_index = ++ad_count;
00389               ldap_pvt_thread_mutex_unlock( &ad_index_mutex );
00390 
00391               if (dlen == 0) {
00392                      d2->ad_cname.bv_val = d2->ad_type->sat_cname.bv_val;
00393                      d2->ad_tags.bv_val = NULL;
00394               } else {
00395                      char *cp, *op, *lp;
00396                      int j;
00397                      d2->ad_cname.bv_val = (char *)(d2+1);
00398                      strcpy(d2->ad_cname.bv_val, d2->ad_type->sat_cname.bv_val);
00399                      cp = d2->ad_cname.bv_val + d2->ad_cname.bv_len;
00400                      if( slap_ad_is_binary( &desc ) ) {
00401                             op = cp;
00402                             lp = NULL;
00403                             if( desc.ad_tags.bv_len ) {
00404                                    lp = desc.ad_tags.bv_val;
00405                                    while( strncasecmp(lp, "binary", STRLENOF("binary")) < 0
00406                                           && (lp = strchr( lp, ';' )) != NULL )
00407                                           ++lp;
00408                                    if( lp != desc.ad_tags.bv_val ) {
00409                                           *cp++ = ';';
00410                                           j = (lp
00411                                                ? (unsigned) (lp - desc.ad_tags.bv_val - 1)
00412                                                : strlen( desc.ad_tags.bv_val ));
00413                                           cp = lutil_strncopy(cp, desc.ad_tags.bv_val, j);
00414                                    }
00415                             }
00416                             cp = lutil_strcopy(cp, ";binary");
00417                             if( lp != NULL ) {
00418                                    *cp++ = ';';
00419                                    cp = lutil_strcopy(cp, lp);
00420                             }
00421                             d2->ad_cname.bv_len = cp - d2->ad_cname.bv_val;
00422                             if( desc.ad_tags.bv_len )
00423                                    ldap_pvt_str2lower(op);
00424                             j = 1;
00425                      } else {
00426                             j = 0;
00427                      }
00428                      if( desc.ad_tags.bv_len ) {
00429                             lp = d2->ad_cname.bv_val + d2->ad_cname.bv_len + j;
00430                             if ( j == 0 )
00431                                    *lp++ = ';';
00432                             d2->ad_tags.bv_val = lp;
00433                             strcpy(lp, desc.ad_tags.bv_val);
00434                             ldap_pvt_str2lower(lp);
00435                             if( j == 0 )
00436                                    d2->ad_cname.bv_len += 1 + desc.ad_tags.bv_len;
00437                      }
00438               }
00439               /* Add new desc to list. We always want the bare Desc with
00440                * no options to stay at the head of the list, assuming
00441                * that one will be used most frequently.
00442                */
00443               if (desc.ad_type->sat_ad == NULL || dlen == 0) {
00444                      d2->ad_next = desc.ad_type->sat_ad;
00445                      desc.ad_type->sat_ad = d2;
00446               } else {
00447                      d2->ad_next = desc.ad_type->sat_ad->ad_next;
00448                      desc.ad_type->sat_ad->ad_next = d2;
00449               }
00450               ldap_pvt_thread_mutex_unlock( &desc.ad_type->sat_ad_mutex );
00451        }
00452 
00453        if( *ad == NULL ) {
00454               *ad = d2;
00455        } else {
00456               **ad = *d2;
00457        }
00458 
00459        return LDAP_SUCCESS;
00460 }
00461 
00462 static int is_ad_subtags(
00463        struct berval *subtagsbv, 
00464        struct berval *suptagsbv )
00465 {
00466        const char *suptags, *supp, *supdelimp, *supn;
00467        const char *subtags, *subp, *subdelimp, *subn;
00468        int  suplen, sublen;
00469 
00470        subtags =subtagsbv->bv_val;
00471        suptags =suptagsbv->bv_val;
00472        subn = subtags + subtagsbv->bv_len;
00473        supn = suptags + suptagsbv->bv_len;
00474 
00475        for( supp=suptags ; supp; supp=supdelimp ) {
00476               supdelimp = strchrlen( supp, supn, ';', &suplen );
00477               if( supdelimp ) supdelimp++;
00478 
00479               for( subp=subtags ; subp; subp=subdelimp ) {
00480                      subdelimp = strchrlen( subp, subn, ';', &sublen );
00481                      if( subdelimp ) subdelimp++;
00482 
00483                      if ( suplen > sublen
00484                              ? ( suplen-1 == sublen && supp[suplen-1] == '-'
00485                                     && strncmp( supp, subp, sublen ) == 0 )
00486                              : ( ( suplen == sublen || supp[suplen-1] == '-' )
00487                                     && strncmp( supp, subp, suplen ) == 0 ) )
00488                      {
00489                             goto match;
00490                      }
00491               }
00492 
00493               return 0;
00494 match:;
00495        }
00496        return 1;
00497 }
00498 
00499 int is_ad_subtype(
00500        AttributeDescription *sub,
00501        AttributeDescription *super
00502 )
00503 {
00504        AttributeType *a;
00505        int lr;
00506 
00507        for ( a = sub->ad_type; a; a=a->sat_sup ) {
00508               if ( a == super->ad_type ) break;
00509        }
00510        if( !a ) {
00511               return 0;
00512        }
00513 
00514        /* ensure sub does support all flags of super */
00515        lr = sub->ad_tags.bv_len ? SLAP_DESC_TAG_RANGE : 0;
00516        if(( super->ad_flags & ( sub->ad_flags | lr )) != super->ad_flags ) {
00517               return 0;
00518        }
00519 
00520        /* check for tagging options */
00521        if ( super->ad_tags.bv_len == 0 )
00522               return 1;
00523        if ( sub->ad_tags.bv_len == 0 )
00524               return 0;
00525 
00526        return is_ad_subtags( &sub->ad_tags, &super->ad_tags );
00527 }
00528 
00529 int ad_inlist(
00530        AttributeDescription *desc,
00531        AttributeName *attrs )
00532 {
00533        if (! attrs ) return 0;
00534 
00535        for( ; attrs->an_name.bv_val; attrs++ ) {
00536               AttributeType *a;
00537               ObjectClass *oc;
00538               
00539               if ( attrs->an_desc ) {
00540                      int lr;
00541 
00542                      if ( desc == attrs->an_desc ) {
00543                             return 1;
00544                      }
00545 
00546                      /*
00547                       * EXTENSION: if requested description is preceeded by
00548                       * a '-' character, do not match on subtypes.
00549                       */
00550                      if ( attrs->an_name.bv_val[0] == '-' ) {
00551                             continue;
00552                      }
00553                      
00554                      /* Is this a subtype of the requested attr? */
00555                      for (a = desc->ad_type; a; a=a->sat_sup) {
00556                             if ( a == attrs->an_desc->ad_type )
00557                                    break;
00558                      }
00559                      if ( !a ) {
00560                             continue;
00561                      }
00562                      /* Does desc support all the requested flags? */
00563                      lr = desc->ad_tags.bv_len ? SLAP_DESC_TAG_RANGE : 0;
00564                      if(( attrs->an_desc->ad_flags & (desc->ad_flags | lr))
00565                             != attrs->an_desc->ad_flags ) {
00566                             continue;
00567                      }
00568                      /* Do the descs have compatible tags? */
00569                      if ( attrs->an_desc->ad_tags.bv_len == 0 ) {
00570                             return 1;
00571                      }
00572                      if ( desc->ad_tags.bv_len == 0) {
00573                             continue;
00574                      }
00575                      if ( is_ad_subtags( &desc->ad_tags,
00576                             &attrs->an_desc->ad_tags ) ) {
00577                             return 1;
00578                      }
00579                      continue;
00580               }
00581 
00582               if ( ber_bvccmp( &attrs->an_name, '*' ) ) {
00583                      if ( !is_at_operational( desc->ad_type ) ) {
00584                             return 1;
00585                      }
00586                      continue;
00587               }
00588 
00589               if ( ber_bvccmp( &attrs->an_name, '+' ) ) {
00590                      if ( is_at_operational( desc->ad_type ) ) {
00591                             return 1;
00592                      }
00593                      continue;
00594               }
00595 
00596               /*
00597                * EXTENSION: see if requested description is @objectClass
00598                * if so, return attributes which the class requires/allows
00599                * else if requested description is !objectClass, return
00600                * attributes which the class does not require/allow
00601                */
00602               if ( !( attrs->an_flags & SLAP_AN_OCINITED )) {
00603                      if( attrs->an_name.bv_val ) {
00604                             switch( attrs->an_name.bv_val[0] ) {
00605                             case '@': /* @objectClass */
00606                             case '+': /* +objectClass (deprecated) */
00607                             case '!': { /* exclude */
00608                                           struct berval ocname;
00609                                           ocname.bv_len = attrs->an_name.bv_len - 1;
00610                                           ocname.bv_val = &attrs->an_name.bv_val[1];
00611                                           oc = oc_bvfind( &ocname );
00612                                           if ( oc && attrs->an_name.bv_val[0] == '!' ) {
00613                                                  attrs->an_flags |= SLAP_AN_OCEXCLUDE;
00614                                           } else {
00615                                                  attrs->an_flags &= ~SLAP_AN_OCEXCLUDE;
00616                                           }
00617                                    } break;
00618 
00619                             default: /* old (deprecated) way */
00620                                    oc = oc_bvfind( &attrs->an_name );
00621                             }
00622                             attrs->an_oc = oc;
00623                      }
00624                      attrs->an_flags |= SLAP_AN_OCINITED;
00625               }
00626               oc = attrs->an_oc;
00627               if( oc != NULL ) {
00628                      if ( attrs->an_flags & SLAP_AN_OCEXCLUDE ) {
00629                             if ( oc == slap_schema.si_oc_extensibleObject ) {
00630                                    /* extensibleObject allows the return of anything */
00631                                    return 0;
00632                             }
00633 
00634                             if( oc->soc_required ) {
00635                                    /* allow return of required attributes */
00636                                    int i;
00637                             
00638                                    for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
00639                                           for (a = desc->ad_type; a; a=a->sat_sup) {
00640                                                  if ( a == oc->soc_required[i] ) {
00641                                                         return 0;
00642                                                  }
00643                                           }
00644                                    }
00645                             }
00646 
00647                             if( oc->soc_allowed ) {
00648                                    /* allow return of allowed attributes */
00649                                    int i;
00650                                    for ( i = 0; oc->soc_allowed[i] != NULL; i++ ) {
00651                                           for (a = desc->ad_type; a; a=a->sat_sup) {
00652                                                  if ( a == oc->soc_allowed[i] ) {
00653                                                         return 0;
00654                                                  }
00655                                           }
00656                                    }
00657                             }
00658 
00659                             return 1;
00660                      }
00661                      
00662                      if ( oc == slap_schema.si_oc_extensibleObject ) {
00663                             /* extensibleObject allows the return of anything */
00664                             return 1;
00665                      }
00666 
00667                      if( oc->soc_required ) {
00668                             /* allow return of required attributes */
00669                             int i;
00670                             
00671                             for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
00672                                    for (a = desc->ad_type; a; a=a->sat_sup) {
00673                                           if ( a == oc->soc_required[i] ) {
00674                                                  return 1;
00675                                           }
00676                                    }
00677                             }
00678                      }
00679 
00680                      if( oc->soc_allowed ) {
00681                             /* allow return of allowed attributes */
00682                             int i;
00683                             for ( i = 0; oc->soc_allowed[i] != NULL; i++ ) {
00684                                    for (a = desc->ad_type; a; a=a->sat_sup) {
00685                                           if ( a == oc->soc_allowed[i] ) {
00686                                                  return 1;
00687                                           }
00688                                    }
00689                             }
00690                      }
00691 
00692               } else {
00693                      const char      *text;
00694 
00695                      /* give it a chance of being retrieved by a proxy... */
00696                      (void)slap_bv2undef_ad( &attrs->an_name,
00697                             &attrs->an_desc, &text,
00698                             SLAP_AD_PROXIED|SLAP_AD_NOINSERT );
00699               }
00700        }
00701 
00702        return 0;
00703 }
00704 
00705 
00706 int slap_str2undef_ad(
00707        const char *str,
00708        AttributeDescription **ad,
00709        const char **text,
00710        unsigned flags )
00711 {
00712        struct berval bv;
00713        bv.bv_val = (char *) str;
00714        bv.bv_len = strlen( str );
00715 
00716        return slap_bv2undef_ad( &bv, ad, text, flags );
00717 }
00718 
00719 int slap_bv2undef_ad(
00720        struct berval *bv,
00721        AttributeDescription **ad,
00722        const char **text,
00723        unsigned flags )
00724 {
00725        AttributeDescription *desc;
00726        AttributeType *at;
00727 
00728        assert( ad != NULL );
00729 
00730        if( bv == NULL || bv->bv_len == 0 ) {
00731               *text = "empty AttributeDescription";
00732               return LDAP_UNDEFINED_TYPE;
00733        }
00734 
00735        /* make sure description is IA5 */
00736        if( ad_keystring( bv ) ) {
00737               *text = "AttributeDescription contains inappropriate characters";
00738               return LDAP_UNDEFINED_TYPE;
00739        }
00740 
00741        /* use the appropriate type */
00742        if ( flags & SLAP_AD_PROXIED ) {
00743               at = slap_schema.si_at_proxied;
00744 
00745        } else {
00746               at = slap_schema.si_at_undefined;
00747        }
00748 
00749        for( desc = at->sat_ad; desc; desc=desc->ad_next ) {
00750               if( desc->ad_cname.bv_len == bv->bv_len &&
00751                   !strcasecmp( desc->ad_cname.bv_val, bv->bv_val ) )
00752               {
00753                      break;
00754               }
00755        }
00756 
00757        if( !desc ) {
00758               if ( flags & SLAP_AD_NOINSERT ) {
00759                      *text = NULL;
00760                      return LDAP_UNDEFINED_TYPE;
00761               }
00762        
00763               desc = ch_malloc(sizeof(AttributeDescription) + 1 +
00764                      bv->bv_len);
00765               
00766               desc->ad_flags = SLAP_DESC_NONE;
00767               BER_BVZERO( &desc->ad_tags );
00768 
00769               desc->ad_cname.bv_len = bv->bv_len;
00770               desc->ad_cname.bv_val = (char *)(desc+1);
00771               strcpy(desc->ad_cname.bv_val, bv->bv_val);
00772 
00773               /* canonical to upper case */
00774               ldap_pvt_str2upper( desc->ad_cname.bv_val );
00775 
00776               /* shouldn't we protect this for concurrency? */
00777               desc->ad_type = at;
00778               desc->ad_index = 0;
00779               ldap_pvt_thread_mutex_lock( &ad_undef_mutex );
00780               desc->ad_next = desc->ad_type->sat_ad;
00781               desc->ad_type->sat_ad = desc;
00782               ldap_pvt_thread_mutex_unlock( &ad_undef_mutex );
00783 
00784               Debug( LDAP_DEBUG_ANY,
00785                      "%s attributeDescription \"%s\" inserted.\n",
00786                      ( flags & SLAP_AD_PROXIED ) ? "PROXIED" : "UNKNOWN",
00787                      desc->ad_cname.bv_val, 0 );
00788        }
00789 
00790        if( !*ad ) {
00791               *ad = desc;
00792        } else {
00793               **ad = *desc;
00794        }
00795 
00796        return LDAP_SUCCESS;
00797 }
00798 
00799 AttributeDescription *
00800 slap_bv2tmp_ad(
00801        struct berval *bv,
00802        void *memctx )
00803 {
00804        AttributeDescription *ad =
00805                slap_sl_mfuncs.bmf_malloc( sizeof(AttributeDescription) +
00806                      bv->bv_len + 1, memctx );
00807 
00808        ad->ad_cname.bv_val = (char *)(ad+1);
00809        strncpy( ad->ad_cname.bv_val, bv->bv_val, bv->bv_len+1 );
00810        ad->ad_cname.bv_len = bv->bv_len;
00811        ad->ad_flags = SLAP_DESC_TEMPORARY;
00812        ad->ad_type = slap_schema.si_at_undefined;
00813 
00814        return ad;
00815 }
00816 
00817 static int
00818 undef_promote(
00819        AttributeType *at,
00820        char          *name,
00821        AttributeType *nat )
00822 {
00823        AttributeDescription **u_ad, **n_ad;
00824 
00825        /* Get to last ad on the new type */
00826        for ( n_ad = &nat->sat_ad; *n_ad; n_ad = &(*n_ad)->ad_next ) ;
00827 
00828        for ( u_ad = &at->sat_ad; *u_ad; ) {
00829               struct berval bv;
00830 
00831               ber_str2bv( name, 0, 0, &bv );
00832 
00833               /* remove iff undef == name or undef == name;tag */
00834               if ( (*u_ad)->ad_cname.bv_len >= bv.bv_len
00835                      && strncasecmp( (*u_ad)->ad_cname.bv_val, bv.bv_val, bv.bv_len ) == 0
00836                      && ( (*u_ad)->ad_cname.bv_val[ bv.bv_len ] == '\0'
00837                             || (*u_ad)->ad_cname.bv_val[ bv.bv_len ] == ';' ) )
00838               {
00839                      AttributeDescription *tmp = *u_ad;
00840 
00841                      *u_ad = (*u_ad)->ad_next;
00842 
00843                      tmp->ad_type = nat;
00844                      tmp->ad_next = NULL;
00845                      /* ad_cname was contiguous, no leak here */
00846                      tmp->ad_cname = nat->sat_cname;
00847                      *n_ad = tmp;
00848                      n_ad = &tmp->ad_next;
00849               } else {
00850                      u_ad = &(*u_ad)->ad_next;
00851               }
00852        }
00853 
00854        return 0;
00855 }
00856 
00857 int
00858 slap_ad_undef_promote(
00859        char *name,
00860        AttributeType *at )
00861 {
00862        int    rc;
00863 
00864        ldap_pvt_thread_mutex_lock( &ad_undef_mutex );
00865 
00866        rc = undef_promote( slap_schema.si_at_undefined, name, at );
00867        if ( rc == 0 ) {
00868               rc = undef_promote( slap_schema.si_at_proxied, name, at );
00869        }
00870 
00871        ldap_pvt_thread_mutex_unlock( &ad_undef_mutex );
00872 
00873        return rc;
00874 }
00875 
00876 int
00877 an_find(
00878     AttributeName *a,
00879     struct berval *s
00880 )
00881 {
00882        if( a == NULL ) return 0;
00883 
00884        for ( ; a->an_name.bv_val; a++ ) {
00885               if ( a->an_name.bv_len != s->bv_len) continue;
00886               if ( strcasecmp( s->bv_val, a->an_name.bv_val ) == 0 ) {
00887                      return( 1 );
00888               }
00889        }
00890 
00891        return( 0 );
00892 }
00893 
00894 /*
00895  * Convert a delimited string into a list of AttributeNames; add
00896  * on to an existing list if it was given.  If the string is not
00897  * a valid attribute name, if a '-' is prepended it is skipped
00898  * and the remaining name is tried again; if a '@' (or '+') is
00899  * prepended, an objectclass name is searched instead; if a '!'
00900  * is prepended, the objectclass name is negated.
00901  * 
00902  * NOTE: currently, if a valid attribute name is not found, the
00903  * same string is also checked as valid objectclass name; however,
00904  * this behavior is deprecated.
00905  */
00906 AttributeName *
00907 str2anlist( AttributeName *an, char *in, const char *brkstr )
00908 {
00909        char   *str;
00910        char   *s;
00911        char   *lasts;
00912        int    i, j;
00913        const char *text;
00914        AttributeName *anew;
00915 
00916        /* find last element in list */
00917        i = 0;
00918        if ( an != NULL ) {
00919               for ( i = 0; !BER_BVISNULL( &an[ i ].an_name ) ; i++)
00920                      ;
00921        }
00922        
00923        /* protect the input string from strtok */
00924        str = ch_strdup( in );
00925 
00926        /* Count words in string */
00927        j = 1;
00928        for ( s = str; *s; s++ ) {
00929               if ( strchr( brkstr, *s ) != NULL ) {
00930                      j++;
00931               }
00932        }
00933 
00934        an = ch_realloc( an, ( i + j + 1 ) * sizeof( AttributeName ) );
00935        anew = an + i;
00936        for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
00937               s != NULL;
00938               s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
00939        {
00940               /* put a stop mark */
00941               BER_BVZERO( &anew[1].an_name );
00942 
00943               anew->an_desc = NULL;
00944               anew->an_oc = NULL;
00945               anew->an_flags = 0;
00946               ber_str2bv(s, 0, 1, &anew->an_name);
00947               slap_bv2ad(&anew->an_name, &anew->an_desc, &text);
00948               if ( !anew->an_desc ) {
00949                      switch( anew->an_name.bv_val[0] ) {
00950                      case '-': {
00951                                    struct berval adname;
00952                                    adname.bv_len = anew->an_name.bv_len - 1;
00953                                    adname.bv_val = &anew->an_name.bv_val[1];
00954                                    slap_bv2ad(&adname, &anew->an_desc, &text);
00955                                    if ( !anew->an_desc ) {
00956                                           goto reterr;
00957                                    }
00958                             } break;
00959 
00960                      case '@':
00961                      case '+': /* (deprecated) */
00962                      case '!': {
00963                                    struct berval ocname;
00964                                    ocname.bv_len = anew->an_name.bv_len - 1;
00965                                    ocname.bv_val = &anew->an_name.bv_val[1];
00966                                    anew->an_oc = oc_bvfind( &ocname );
00967                                    if ( !anew->an_oc ) {
00968                                           goto reterr;
00969                                    }
00970 
00971                                    if ( anew->an_name.bv_val[0] == '!' ) {
00972                                           anew->an_flags |= SLAP_AN_OCEXCLUDE;
00973                                    }
00974                             } break;
00975 
00976                      default:
00977                             /* old (deprecated) way */
00978                             anew->an_oc = oc_bvfind( &anew->an_name );
00979                             if ( !anew->an_oc ) {
00980                                    goto reterr;
00981                             }
00982                      }
00983               }
00984               anew->an_flags |= SLAP_AN_OCINITED;
00985               anew++;
00986        }
00987 
00988        BER_BVZERO( &anew->an_name );
00989        free( str );
00990        return( an );
00991 
00992 reterr:
00993        anlist_free( an, 1, NULL );
00994 
00995        /*
00996         * overwrites input string
00997         * on error!
00998         */
00999        strcpy( in, s );
01000        free( str );
01001        return NULL;
01002 }
01003 
01004 void
01005 anlist_free( AttributeName *an, int freename, void *ctx )
01006 {
01007        if ( an == NULL ) {
01008               return;
01009        }
01010 
01011        if ( freename ) {
01012               int    i;
01013 
01014               for ( i = 0; an[i].an_name.bv_val; i++ ) {
01015                      ber_memfree_x( an[i].an_name.bv_val, ctx );
01016               }
01017        }
01018 
01019        ber_memfree_x( an, ctx );
01020 }
01021 
01022 char **anlist2charray_x( AttributeName *an, int dup, void *ctx )
01023 {
01024     char **attrs;
01025     int i;
01026                                                                                 
01027     if ( an != NULL ) {
01028         for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ )
01029             ;
01030               attrs = (char **) slap_sl_malloc( (i + 1) * sizeof(char *), ctx );
01031         for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
01032                      if ( dup )
01033                    attrs[i] = ch_strdup( an[i].an_name.bv_val );
01034                      else
01035                    attrs[i] = an[i].an_name.bv_val;
01036         }
01037         attrs[i] = NULL;
01038     } else {
01039         attrs = NULL;
01040     }
01041                                                                                 
01042     return attrs;
01043 }
01044 
01045 char **anlist2charray( AttributeName *an, int dup )
01046 {
01047        return anlist2charray_x( an, dup, NULL );
01048 }
01049 
01050 char**
01051 anlist2attrs( AttributeName * anlist )
01052 {
01053        int i, j, k = 0;
01054        int n;
01055        char **attrs;
01056        ObjectClass *oc;
01057 
01058        if ( anlist == NULL )
01059               return NULL;
01060 
01061        for ( i = 0; anlist[i].an_name.bv_val; i++ ) {
01062               if ( ( oc = anlist[i].an_oc ) ) {
01063                      for ( j = 0; oc->soc_required && oc->soc_required[j]; j++ ) ;
01064                      k += j;
01065                      for ( j = 0; oc->soc_allowed && oc->soc_allowed[j]; j++ ) ;
01066                      k += j;
01067               }
01068        }
01069 
01070        if ( i == 0 )
01071               return NULL;
01072                                                                                 
01073        attrs = anlist2charray( anlist, 1 );
01074                                                                                 
01075        n = i;
01076                                                                                 
01077        if ( k )
01078               attrs = (char **) ch_realloc( attrs, (i + k + 1) * sizeof( char * ));
01079 
01080        for ( i = 0; anlist[i].an_name.bv_val; i++ ) {
01081               if ( ( oc = anlist[i].an_oc ) ) {
01082                      for ( j = 0; oc->soc_required && oc->soc_required[j]; j++ ) {
01083                             attrs[n++] = ch_strdup(
01084                                                         oc->soc_required[j]->sat_cname.bv_val );
01085                      }
01086                      for ( j = 0; oc->soc_allowed && oc->soc_allowed[j]; j++ ) {
01087                             attrs[n++] = ch_strdup(
01088                                                         oc->soc_allowed[j]->sat_cname.bv_val );
01089                      }
01090               }
01091        }
01092        
01093        if ( attrs )
01094               attrs[n] = NULL;
01095 
01096        i = 0;
01097        while ( attrs && attrs[i] ) {
01098               if ( *attrs[i] == '@' ) {
01099                      ch_free( attrs[i] );
01100                      for ( j = i; attrs[j]; j++ ) {
01101                             attrs[j] = attrs[j+1];
01102                      }
01103               } else {
01104                      i++;
01105               }
01106        }
01107 
01108        for ( i = 0; attrs && attrs[i]; i++ ) {
01109               j = i + 1;
01110               while ( attrs && attrs[j] ) {
01111                      if ( !strcmp( attrs[i], attrs[j] )) {
01112                             ch_free( attrs[j] );
01113                             for ( k = j; attrs && attrs[k]; k++ ) {
01114                                    attrs[k] = attrs[k+1];
01115                             }
01116                      } else {
01117                             j++;
01118                      }
01119               }
01120        }
01121 
01122        if ( i != n )
01123               attrs = (char **) ch_realloc( attrs, (i+1) * sizeof( char * ));
01124 
01125        return attrs;
01126 }
01127 
01128 #define LBUFSIZ      80
01129 AttributeName*
01130 file2anlist( AttributeName *an, const char *fname, const char *brkstr )
01131 {
01132        FILE   *fp;
01133        char   *line = NULL;
01134        char   *lcur = NULL;
01135        char   *c;
01136        size_t lmax = LBUFSIZ;
01137 
01138        fp = fopen( fname, "r" );
01139        if ( fp == NULL ) {
01140               Debug( LDAP_DEBUG_ANY,
01141                      "get_attrs_from_file: failed to open attribute list file "
01142                      "\"%s\": %s\n", fname, strerror(errno), 0 );
01143               return NULL;
01144        }
01145 
01146        lcur = line = (char *) ch_malloc( lmax );
01147        if ( !line ) {
01148               Debug( LDAP_DEBUG_ANY,
01149                      "get_attrs_from_file: could not allocate memory\n",
01150                      0, 0, 0 );
01151               fclose(fp);
01152               return NULL;
01153        }
01154 
01155        while ( fgets( lcur, LBUFSIZ, fp ) != NULL ) {
01156               if ( ( c = strchr( lcur, '\n' ) ) ) {
01157                      if ( c == line ) {
01158                             *c = '\0';
01159                      } else if ( *(c-1) == '\r' ) {
01160                             *(c-1) = '\0';
01161                      } else {
01162                             *c = '\0';
01163                      }
01164               } else {
01165                      lmax += LBUFSIZ;
01166                      line = (char *) ch_realloc( line, lmax );
01167                      if ( !line ) {
01168                             Debug( LDAP_DEBUG_ANY,
01169                                    "get_attrs_from_file: could not allocate memory\n",
01170                                    0, 0, 0 );
01171                             fclose(fp);
01172                             return NULL;
01173                      }
01174                      lcur = line + strlen( line );
01175                      continue;
01176               }
01177               an = str2anlist( an, line, brkstr );
01178               if ( an == NULL )
01179                      break;
01180               lcur = line;
01181        }
01182        ch_free( line );
01183        fclose(fp);
01184        return an;
01185 }
01186 #undef LBUFSIZ
01187 
01188 /* Define an attribute option. */
01189 int
01190 ad_define_option( const char *name, const char *fname, int lineno )
01191 {
01192        int i;
01193        unsigned int optlen;
01194 
01195        if ( options == &lang_option ) {
01196               options = NULL;
01197               option_count = 0;
01198        }
01199        if ( name == NULL )
01200               return 0;
01201 
01202        optlen = 0;
01203        do {
01204               if ( !DESC_CHAR( name[optlen] ) ) {
01205                      /* allow trailing '=', same as '-' */
01206                      if ( name[optlen] == '=' && !name[optlen+1] ) {
01207                             msad_range_hack = 1;
01208                             continue;
01209                      }
01210                      Debug( LDAP_DEBUG_ANY,
01211                             "%s: line %d: illegal option name \"%s\"\n",
01212                                 fname, lineno, name );
01213                      return 1;
01214               }
01215        } while ( name[++optlen] );
01216 
01217        options = ch_realloc( options,
01218               (option_count+1) * sizeof(Attr_option) );
01219 
01220        if ( strcasecmp( name, "binary" ) == 0
01221             || ad_find_option_definition( name, optlen ) ) {
01222               Debug( LDAP_DEBUG_ANY,
01223                      "%s: line %d: option \"%s\" is already defined\n",
01224                      fname, lineno, name );
01225               return 1;
01226        }
01227 
01228        for ( i = option_count; i; --i ) {
01229               if ( strcasecmp( name, options[i-1].name.bv_val ) >= 0 )
01230                      break;
01231               options[i] = options[i-1];
01232        }
01233 
01234        options[i].name.bv_val = ch_strdup( name );
01235        options[i].name.bv_len = optlen;
01236        options[i].prefix = (name[optlen-1] == '-') ||
01237               (name[optlen-1] == '=');
01238 
01239        if ( i != option_count &&
01240             options[i].prefix &&
01241             optlen < options[i+1].name.bv_len &&
01242             strncasecmp( name, options[i+1].name.bv_val, optlen ) == 0 ) {
01243                      Debug( LDAP_DEBUG_ANY,
01244                             "%s: line %d: option \"%s\" overrides previous option\n",
01245                                 fname, lineno, name );
01246                      return 1;
01247        }
01248 
01249        option_count++;
01250        return 0;
01251 }
01252 
01253 void
01254 ad_unparse_options( BerVarray *res )
01255 {
01256        int i;
01257        for ( i = 0; i < option_count; i++ ) {
01258               value_add_one( res, &options[i].name );
01259        }
01260 }
01261 
01262 /* Find the definition of the option name or prefix matching the arguments */
01263 static Attr_option *
01264 ad_find_option_definition( const char *opt, int optlen )
01265 {
01266        int top = 0, bot = option_count;
01267        while ( top < bot ) {
01268               int mid = (top + bot) / 2;
01269               int mlen = options[mid].name.bv_len;
01270               char *mname = options[mid].name.bv_val;
01271               int j;
01272               if ( optlen < mlen ) {
01273                      j = strncasecmp( opt, mname, optlen ) - 1;
01274               } else {
01275                      j = strncasecmp( opt, mname, mlen );
01276                      if ( j==0 && (optlen==mlen || options[mid].prefix) )
01277                             return &options[mid];
01278               }
01279               if ( j < 0 )
01280                      bot = mid;
01281               else
01282                      top = mid + 1;
01283        }
01284        return NULL;
01285 }
01286 
01287 MatchingRule *ad_mr(
01288        AttributeDescription *ad,
01289        unsigned usage )
01290 {
01291        switch( usage & SLAP_MR_TYPE_MASK ) {
01292        case SLAP_MR_NONE:
01293        case SLAP_MR_EQUALITY:
01294               return ad->ad_type->sat_equality;
01295               break;
01296        case SLAP_MR_ORDERING:
01297               return ad->ad_type->sat_ordering;
01298               break;
01299        case SLAP_MR_SUBSTR:
01300               return ad->ad_type->sat_substr;
01301               break;
01302        case SLAP_MR_EXT:
01303        default:
01304               assert( 0 /* ad_mr: bad usage */);
01305        }
01306        return NULL;
01307 }