Back to index

openldap  2.4.31
mr.c
Go to the documentation of this file.
00001 /* mr.c - routines to manage matching rule definitions */
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/string.h>
00023 #include <ac/socket.h>
00024 
00025 #include "slap.h"
00026 
00027 struct mindexrec {
00028        struct berval mir_name;
00029        MatchingRule  *mir_mr;
00030 };
00031 
00032 static Avlnode       *mr_index = NULL;
00033 static LDAP_SLIST_HEAD(MRList, MatchingRule) mr_list
00034        = LDAP_SLIST_HEAD_INITIALIZER(&mr_list);
00035 static LDAP_SLIST_HEAD(MRUList, MatchingRuleUse) mru_list
00036        = LDAP_SLIST_HEAD_INITIALIZER(&mru_list);
00037 
00038 static int
00039 mr_index_cmp(
00040     const void       *v_mir1,
00041     const void       *v_mir2
00042 )
00043 {
00044        const struct mindexrec      *mir1 = v_mir1;
00045        const struct mindexrec      *mir2 = v_mir2;
00046        int i = mir1->mir_name.bv_len - mir2->mir_name.bv_len;
00047        if (i) return i;
00048        return (strcasecmp( mir1->mir_name.bv_val, mir2->mir_name.bv_val ));
00049 }
00050 
00051 static int
00052 mr_index_name_cmp(
00053     const void       *v_name,
00054     const void       *v_mir
00055 )
00056 {
00057        const struct berval    *name = v_name;
00058        const struct mindexrec *mir  = v_mir;
00059        int i = name->bv_len - mir->mir_name.bv_len;
00060        if (i) return i;
00061        return (strncasecmp( name->bv_val, mir->mir_name.bv_val, name->bv_len ));
00062 }
00063 
00064 MatchingRule *
00065 mr_find( const char *mrname )
00066 {
00067        struct berval bv;
00068 
00069        bv.bv_val = (char *)mrname;
00070        bv.bv_len = strlen( mrname );
00071        return mr_bvfind( &bv );
00072 }
00073 
00074 MatchingRule *
00075 mr_bvfind( struct berval *mrname )
00076 {
00077        struct mindexrec     *mir = NULL;
00078 
00079        if ( (mir = avl_find( mr_index, mrname, mr_index_name_cmp )) != NULL ) {
00080               return( mir->mir_mr );
00081        }
00082        return( NULL );
00083 }
00084 
00085 void
00086 mr_destroy( void )
00087 {
00088        MatchingRule *m;
00089 
00090        avl_free(mr_index, ldap_memfree);
00091        while( !LDAP_SLIST_EMPTY(&mr_list) ) {
00092               m = LDAP_SLIST_FIRST(&mr_list);
00093               LDAP_SLIST_REMOVE_HEAD(&mr_list, smr_next);
00094               ch_free( m->smr_str.bv_val );
00095               ch_free( m->smr_compat_syntaxes );
00096               ldap_matchingrule_free((LDAPMatchingRule *)m);
00097        }
00098 }
00099 
00100 static int
00101 mr_insert(
00102     MatchingRule     *smr,
00103     const char              **err
00104 )
00105 {
00106        struct mindexrec     *mir;
00107        char                 **names;
00108 
00109        LDAP_SLIST_NEXT( smr, smr_next ) = NULL;
00110        LDAP_SLIST_INSERT_HEAD(&mr_list, smr, smr_next);
00111 
00112        if ( smr->smr_oid ) {
00113               mir = (struct mindexrec *)
00114                      ch_calloc( 1, sizeof(struct mindexrec) );
00115               mir->mir_name.bv_val = smr->smr_oid;
00116               mir->mir_name.bv_len = strlen( smr->smr_oid );
00117               mir->mir_mr = smr;
00118               if ( avl_insert( &mr_index, (caddr_t) mir,
00119                                mr_index_cmp, avl_dup_error ) ) {
00120                      *err = smr->smr_oid;
00121                      ldap_memfree(mir);
00122                      return SLAP_SCHERR_MR_DUP;
00123               }
00124               /* FIX: temporal consistency check */
00125               mr_bvfind(&mir->mir_name);
00126        }
00127        if ( (names = smr->smr_names) ) {
00128               while ( *names ) {
00129                      mir = (struct mindexrec *)
00130                             ch_calloc( 1, sizeof(struct mindexrec) );
00131                      mir->mir_name.bv_val = *names;
00132                      mir->mir_name.bv_len = strlen( *names );
00133                      mir->mir_mr = smr;
00134                      if ( avl_insert( &mr_index, (caddr_t) mir,
00135                                       mr_index_cmp, avl_dup_error ) ) {
00136                             *err = *names;
00137                             ldap_memfree(mir);
00138                             return SLAP_SCHERR_MR_DUP;
00139                      }
00140                      /* FIX: temporal consistency check */
00141                      mr_bvfind(&mir->mir_name);
00142                      names++;
00143               }
00144        }
00145        return 0;
00146 }
00147 
00148 int
00149 mr_make_syntax_compat_with_mr(
00150        Syntax        *syn,
00151        MatchingRule  *mr )
00152 {
00153        int           n = 0;
00154 
00155        assert( syn != NULL );
00156        assert( mr != NULL );
00157 
00158        if ( mr->smr_compat_syntaxes ) {
00159               /* count esisting */
00160               for ( n = 0;
00161                      mr->smr_compat_syntaxes[ n ];
00162                      n++ )
00163               {
00164                      if ( mr->smr_compat_syntaxes[ n ] == syn ) {
00165                             /* already compatible; mmmmh... */
00166                             return 1;
00167                      }
00168               }
00169        }
00170 
00171        mr->smr_compat_syntaxes = ch_realloc(
00172               mr->smr_compat_syntaxes,
00173               sizeof( Syntax * )*(n + 2) );
00174        mr->smr_compat_syntaxes[ n ] = syn;
00175        mr->smr_compat_syntaxes[ n + 1 ] = NULL;
00176 
00177        return 0;
00178 }
00179 
00180 int
00181 mr_make_syntax_compat_with_mrs(
00182        const char *syntax,
00183        char *const *mrs )
00184 {
00185        int    r, rc = 0;
00186        Syntax *syn;
00187 
00188        assert( syntax != NULL );
00189        assert( mrs != NULL );
00190 
00191        syn = syn_find( syntax );
00192        if ( syn == NULL ) {
00193               return -1;
00194        }
00195 
00196        for ( r = 0; mrs[ r ] != NULL; r++ ) {
00197               MatchingRule  *mr = mr_find( mrs[ r ] );
00198               if ( mr == NULL ) {
00199                      /* matchingRule not found -- ignore by now */
00200                      continue;
00201               }
00202 
00203               rc += mr_make_syntax_compat_with_mr( syn, mr );
00204        }
00205 
00206        return rc;
00207 }
00208 
00209 int
00210 mr_add(
00211     LDAPMatchingRule        *mr,
00212     slap_mrule_defs_rec     *def,
00213        MatchingRule  *amr,
00214     const char              **err
00215 )
00216 {
00217        MatchingRule  *smr;
00218        Syntax        *syn;
00219        Syntax        **compat_syn = NULL;
00220        int           code;
00221 
00222        if( def->mrd_compat_syntaxes ) {
00223               int i;
00224               for( i=0; def->mrd_compat_syntaxes[i]; i++ ) {
00225                      /* just count em */
00226               }
00227 
00228               compat_syn = ch_malloc( sizeof(Syntax *) * (i+1) );
00229 
00230               for( i=0; def->mrd_compat_syntaxes[i]; i++ ) {
00231                      compat_syn[i] = syn_find( def->mrd_compat_syntaxes[i] );
00232                      if( compat_syn[i] == NULL ) {
00233                             ch_free( compat_syn );
00234                             return SLAP_SCHERR_SYN_NOT_FOUND;
00235                      }
00236               }
00237 
00238               compat_syn[i] = NULL;
00239        }
00240 
00241        smr = (MatchingRule *) ch_calloc( 1, sizeof(MatchingRule) );
00242        AC_MEMCPY( &smr->smr_mrule, mr, sizeof(LDAPMatchingRule));
00243 
00244        /*
00245         * note: smr_bvoid uses the same memory of smr_mrule.mr_oid;
00246         * smr_oidlen is #defined as smr_bvoid.bv_len
00247         */
00248        smr->smr_bvoid.bv_val = smr->smr_mrule.mr_oid;
00249        smr->smr_oidlen = strlen( mr->mr_oid );
00250        smr->smr_usage = def->mrd_usage;
00251        smr->smr_compat_syntaxes = compat_syn;
00252        smr->smr_normalize = def->mrd_normalize;
00253        smr->smr_match = def->mrd_match;
00254        smr->smr_indexer = def->mrd_indexer;
00255        smr->smr_filter = def->mrd_filter;
00256        smr->smr_associated = amr;
00257 
00258        if ( smr->smr_syntax_oid ) {
00259               if ( (syn = syn_find(smr->smr_syntax_oid)) ) {
00260                      smr->smr_syntax = syn;
00261               } else {
00262                      *err = smr->smr_syntax_oid;
00263                      ch_free( smr );
00264                      return SLAP_SCHERR_SYN_NOT_FOUND;
00265               }
00266        } else {
00267               *err = "";
00268               ch_free( smr );
00269               return SLAP_SCHERR_MR_INCOMPLETE;
00270        }
00271        code = mr_insert(smr,err);
00272        return code;
00273 }
00274 
00275 int
00276 register_matching_rule(
00277        slap_mrule_defs_rec *def )
00278 {
00279        LDAPMatchingRule *mr;
00280        MatchingRule *amr = NULL;
00281        int           code;
00282        const char    *err;
00283 
00284        if( def->mrd_usage == SLAP_MR_NONE && def->mrd_compat_syntaxes == NULL ) {
00285               Debug( LDAP_DEBUG_ANY, "register_matching_rule: not usable %s\n",
00286                   def->mrd_desc, 0, 0 );
00287 
00288               return -1;
00289        }
00290 
00291        if( def->mrd_associated != NULL ) {
00292               amr = mr_find( def->mrd_associated );
00293               if( amr == NULL ) {
00294                      Debug( LDAP_DEBUG_ANY, "register_matching_rule: "
00295                             "could not locate associated matching rule %s for %s\n",
00296                             def->mrd_associated, def->mrd_desc, 0 );
00297 
00298                      return -1;
00299               }
00300 
00301               if (( def->mrd_usage & SLAP_MR_EQUALITY ) &&
00302                      (( def->mrd_usage & SLAP_MR_SUBTYPE_MASK ) == SLAP_MR_NONE ))
00303               {
00304                      if (( def->mrd_usage & SLAP_MR_EQUALITY ) &&
00305                             (( def->mrd_usage & SLAP_MR_SUBTYPE_MASK ) != SLAP_MR_NONE ))
00306                      {
00307                             Debug( LDAP_DEBUG_ANY, "register_matching_rule: "
00308                                           "inappropriate (approx) association %s for %s\n",
00309                                    def->mrd_associated, def->mrd_desc, 0 );
00310                             return -1;
00311                      }
00312 
00313               } else if (!( amr->smr_usage & SLAP_MR_EQUALITY )) {
00314                             Debug( LDAP_DEBUG_ANY, "register_matching_rule: "
00315                                    "inappropriate (equalilty) association %s for %s\n",
00316                                    def->mrd_associated, def->mrd_desc, 0 );
00317                             return -1;
00318               }
00319        }
00320 
00321        mr = ldap_str2matchingrule( def->mrd_desc, &code, &err,
00322               LDAP_SCHEMA_ALLOW_ALL );
00323        if ( !mr ) {
00324               Debug( LDAP_DEBUG_ANY,
00325                      "Error in register_matching_rule: %s before %s in %s\n",
00326                   ldap_scherr2str(code), err, def->mrd_desc );
00327 
00328               return -1;
00329        }
00330 
00331 
00332        code = mr_add( mr, def, amr, &err );
00333 
00334        ldap_memfree( mr );
00335 
00336        if ( code ) {
00337               Debug( LDAP_DEBUG_ANY,
00338                      "Error in register_matching_rule: %s for %s in %s\n",
00339                   scherr2str(code), err, def->mrd_desc );
00340 
00341               return -1;
00342        }
00343 
00344        return 0;
00345 }
00346 
00347 void
00348 mru_destroy( void )
00349 {
00350        MatchingRuleUse *m;
00351 
00352        while( !LDAP_SLIST_EMPTY(&mru_list) ) {
00353               m = LDAP_SLIST_FIRST(&mru_list);
00354               LDAP_SLIST_REMOVE_HEAD(&mru_list, smru_next);
00355 
00356               if ( m->smru_str.bv_val ) {
00357                      ch_free( m->smru_str.bv_val );
00358                      m->smru_str.bv_val = NULL;
00359               }
00360               /* memory borrowed from m->smru_mr */
00361               m->smru_oid = NULL;
00362               m->smru_names = NULL;
00363               m->smru_desc = NULL;
00364 
00365               /* free what's left (basically smru_mruleuse.mru_applies_oids) */
00366               ldap_matchingruleuse_free((LDAPMatchingRuleUse *)m);
00367        }
00368 }
00369 
00370 int
00371 matching_rule_use_init( void )
00372 {
00373        MatchingRule  *mr;
00374        MatchingRuleUse      **mru_ptr = &LDAP_SLIST_FIRST(&mru_list);
00375 
00376        Debug( LDAP_DEBUG_TRACE, "matching_rule_use_init\n", 0, 0, 0 );
00377 
00378        LDAP_SLIST_FOREACH( mr, &mr_list, smr_next ) {
00379               AttributeType *at;
00380               MatchingRuleUse      mru_storage = {{ 0 }},
00381                             *mru = &mru_storage;
00382 
00383               char          **applies_oids = NULL;
00384 
00385               mr->smr_mru = NULL;
00386 
00387               /* hide rules marked as HIDE */
00388               if ( mr->smr_usage & SLAP_MR_HIDE ) {
00389                      continue;
00390               }
00391 
00392               /* hide rules not marked as designed for extensibility */
00393               /* MR_EXT means can be used any attribute type whose
00394                * syntax is same as the assertion syntax.
00395                * Another mechanism is needed where rule can be used
00396                * with attribute of other syntaxes.
00397                * Framework doesn't support this (yet).
00398                */
00399 
00400               if (!( ( mr->smr_usage & SLAP_MR_EXT )
00401                      || mr->smr_compat_syntaxes ) )
00402               {
00403                      continue;
00404               }
00405 
00406               /*
00407                * Note: we're using the same values of the corresponding 
00408                * MatchingRule structure; maybe we'd copy them ...
00409                */
00410               mru->smru_mr = mr;
00411               mru->smru_obsolete = mr->smr_obsolete;
00412               mru->smru_applies_oids = NULL;
00413               LDAP_SLIST_NEXT(mru, smru_next) = NULL;
00414               mru->smru_oid = mr->smr_oid;
00415               mru->smru_names = mr->smr_names;
00416               mru->smru_desc = mr->smr_desc;
00417 
00418               Debug( LDAP_DEBUG_TRACE, "    %s (%s): ", 
00419                             mru->smru_oid, 
00420                             mru->smru_names ? mru->smru_names[ 0 ] : "", 0 );
00421 
00422               at = NULL;
00423               for ( at_start( &at ); at; at_next( &at ) ) {
00424                      if( at->sat_flags & SLAP_AT_HIDE ) continue;
00425 
00426                      if( mr_usable_with_at( mr, at )) {
00427                             ldap_charray_add( &applies_oids, at->sat_cname.bv_val );
00428                      }
00429               }
00430 
00431               /*
00432                * Note: the matchingRules that are not used
00433                * by any attributeType are not listed as
00434                * matchingRuleUse
00435                */
00436               if ( applies_oids != NULL ) {
00437                      mru->smru_applies_oids = applies_oids;
00438                      {
00439                             char *str = ldap_matchingruleuse2str( &mru->smru_mruleuse );
00440                             Debug( LDAP_DEBUG_TRACE, "matchingRuleUse: %s\n", str, 0, 0 );
00441                             ldap_memfree( str );
00442                      }
00443 
00444                      mru = (MatchingRuleUse *)ber_memalloc( sizeof( MatchingRuleUse ) );
00445                      /* call-forward from MatchingRule to MatchingRuleUse */
00446                      mr->smr_mru = mru;
00447                      /* copy static data to newly allocated struct */
00448                      *mru = mru_storage;
00449                      /* append the struct pointer to the end of the list */
00450                      *mru_ptr = mru;
00451                      /* update the list head pointer */
00452                      mru_ptr = &LDAP_SLIST_NEXT(mru,smru_next);
00453               }
00454        }
00455 
00456        return( 0 );
00457 }
00458 
00459 int
00460 mr_usable_with_at(
00461        MatchingRule  *mr,
00462        AttributeType *at )
00463 {
00464        if ( ( mr->smr_usage & SLAP_MR_EXT ) && (
00465               mr->smr_syntax == at->sat_syntax ||
00466               mr == at->sat_equality ||
00467               mr == at->sat_approx ||
00468               syn_is_sup( at->sat_syntax, mr->smr_syntax ) ) )
00469        {
00470               return 1;
00471        }
00472 
00473        if ( mr->smr_compat_syntaxes ) {
00474               int i;
00475               for( i=0; mr->smr_compat_syntaxes[i]; i++ ) {
00476                      if( at->sat_syntax == mr->smr_compat_syntaxes[i] ) {
00477                             return 1;
00478                      }
00479               }
00480        }
00481        return 0;
00482 }
00483 
00484 int mr_schema_info( Entry *e )
00485 {
00486        AttributeDescription *ad_matchingRules = slap_schema.si_ad_matchingRules;
00487        MatchingRule *mr;
00488        struct berval nval;
00489 
00490        LDAP_SLIST_FOREACH(mr, &mr_list, smr_next ) {
00491               if ( mr->smr_usage & SLAP_MR_HIDE ) {
00492                      /* skip hidden rules */
00493                      continue;
00494               }
00495 
00496               if ( ! mr->smr_match ) {
00497                      /* skip rules without matching functions */
00498                      continue;
00499               }
00500 
00501               if ( mr->smr_str.bv_val == NULL ) {
00502                      if ( ldap_matchingrule2bv( &mr->smr_mrule, &mr->smr_str ) == NULL ) {
00503                             return -1;
00504                      }
00505               }
00506 #if 0
00507               Debug( LDAP_DEBUG_TRACE, "Merging mr [%lu] %s\n",
00508                      mr->smr_str.bv_len, mr->smr_str.bv_val, 0 );
00509 #endif
00510 
00511               nval.bv_val = mr->smr_oid;
00512               nval.bv_len = strlen(mr->smr_oid);
00513               if( attr_merge_one( e, ad_matchingRules, &mr->smr_str, &nval ) ) {
00514                      return -1;
00515               }
00516        }
00517        return 0;
00518 }
00519 
00520 int mru_schema_info( Entry *e )
00521 {
00522        AttributeDescription *ad_matchingRuleUse 
00523               = slap_schema.si_ad_matchingRuleUse;
00524        MatchingRuleUse      *mru;
00525        struct berval nval;
00526 
00527        LDAP_SLIST_FOREACH( mru, &mru_list, smru_next ) {
00528               assert( !( mru->smru_usage & SLAP_MR_HIDE ) );
00529 
00530               if ( mru->smru_str.bv_val == NULL ) {
00531                      if ( ldap_matchingruleuse2bv( &mru->smru_mruleuse, &mru->smru_str )
00532                                    == NULL ) {
00533                             return -1;
00534                      }
00535               }
00536 
00537 #if 0
00538               Debug( LDAP_DEBUG_TRACE, "Merging mru [%lu] %s\n",
00539                      mru->smru_str.bv_len, mru->smru_str.bv_val, 0 );
00540 #endif
00541 
00542               nval.bv_val = mru->smru_oid;
00543               nval.bv_len = strlen(mru->smru_oid);
00544               if( attr_merge_one( e, ad_matchingRuleUse, &mru->smru_str, &nval ) ) {
00545                      return -1;
00546               }
00547        }
00548        return 0;
00549 }