Home | History | Annotate | Line # | Download | only in slapd
mr.c revision 1.1.1.1
      1 /* mr.c - routines to manage matching rule definitions */
      2 /* $OpenLDAP: pkg/ldap/servers/slapd/mr.c,v 1.64.2.3 2008/02/11 23:26:44 kurt Exp $ */
      3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      4  *
      5  * Copyright 1998-2008 The OpenLDAP Foundation.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted only as authorized by the OpenLDAP
     10  * Public License.
     11  *
     12  * A copy of this license is available in the file LICENSE in the
     13  * top-level directory of the distribution or, alternatively, at
     14  * <http://www.OpenLDAP.org/license.html>.
     15  */
     16 
     17 #include "portable.h"
     18 
     19 #include <stdio.h>
     20 
     21 #include <ac/ctype.h>
     22 #include <ac/string.h>
     23 #include <ac/socket.h>
     24 
     25 #include "slap.h"
     26 
     27 struct mindexrec {
     28 	struct berval	mir_name;
     29 	MatchingRule	*mir_mr;
     30 };
     31 
     32 static Avlnode	*mr_index = NULL;
     33 static LDAP_SLIST_HEAD(MRList, MatchingRule) mr_list
     34 	= LDAP_SLIST_HEAD_INITIALIZER(&mr_list);
     35 static LDAP_SLIST_HEAD(MRUList, MatchingRuleUse) mru_list
     36 	= LDAP_SLIST_HEAD_INITIALIZER(&mru_list);
     37 
     38 static int
     39 mr_index_cmp(
     40     const void	*v_mir1,
     41     const void	*v_mir2
     42 )
     43 {
     44 	const struct mindexrec	*mir1 = v_mir1;
     45 	const struct mindexrec	*mir2 = v_mir2;
     46 	int i = mir1->mir_name.bv_len - mir2->mir_name.bv_len;
     47 	if (i) return i;
     48 	return (strcasecmp( mir1->mir_name.bv_val, mir2->mir_name.bv_val ));
     49 }
     50 
     51 static int
     52 mr_index_name_cmp(
     53     const void	*v_name,
     54     const void	*v_mir
     55 )
     56 {
     57 	const struct berval    *name = v_name;
     58 	const struct mindexrec *mir  = v_mir;
     59 	int i = name->bv_len - mir->mir_name.bv_len;
     60 	if (i) return i;
     61 	return (strncasecmp( name->bv_val, mir->mir_name.bv_val, name->bv_len ));
     62 }
     63 
     64 MatchingRule *
     65 mr_find( const char *mrname )
     66 {
     67 	struct berval bv;
     68 
     69 	bv.bv_val = (char *)mrname;
     70 	bv.bv_len = strlen( mrname );
     71 	return mr_bvfind( &bv );
     72 }
     73 
     74 MatchingRule *
     75 mr_bvfind( struct berval *mrname )
     76 {
     77 	struct mindexrec	*mir = NULL;
     78 
     79 	if ( (mir = avl_find( mr_index, mrname, mr_index_name_cmp )) != NULL ) {
     80 		return( mir->mir_mr );
     81 	}
     82 	return( NULL );
     83 }
     84 
     85 void
     86 mr_destroy( void )
     87 {
     88 	MatchingRule *m;
     89 
     90 	avl_free(mr_index, ldap_memfree);
     91 	while( !LDAP_SLIST_EMPTY(&mr_list) ) {
     92 		m = LDAP_SLIST_FIRST(&mr_list);
     93 		LDAP_SLIST_REMOVE_HEAD(&mr_list, smr_next);
     94 		ch_free( m->smr_str.bv_val );
     95 		ch_free( m->smr_compat_syntaxes );
     96 		ldap_matchingrule_free((LDAPMatchingRule *)m);
     97 	}
     98 }
     99 
    100 static int
    101 mr_insert(
    102     MatchingRule	*smr,
    103     const char		**err
    104 )
    105 {
    106 	struct mindexrec	*mir;
    107 	char			**names;
    108 
    109 	LDAP_SLIST_NEXT( smr, smr_next ) = NULL;
    110 	LDAP_SLIST_INSERT_HEAD(&mr_list, smr, smr_next);
    111 
    112 	if ( smr->smr_oid ) {
    113 		mir = (struct mindexrec *)
    114 			ch_calloc( 1, sizeof(struct mindexrec) );
    115 		mir->mir_name.bv_val = smr->smr_oid;
    116 		mir->mir_name.bv_len = strlen( smr->smr_oid );
    117 		mir->mir_mr = smr;
    118 		if ( avl_insert( &mr_index, (caddr_t) mir,
    119 		                 mr_index_cmp, avl_dup_error ) ) {
    120 			*err = smr->smr_oid;
    121 			ldap_memfree(mir);
    122 			return SLAP_SCHERR_MR_DUP;
    123 		}
    124 		/* FIX: temporal consistency check */
    125 		mr_bvfind(&mir->mir_name);
    126 	}
    127 	if ( (names = smr->smr_names) ) {
    128 		while ( *names ) {
    129 			mir = (struct mindexrec *)
    130 				ch_calloc( 1, sizeof(struct mindexrec) );
    131 			mir->mir_name.bv_val = *names;
    132 			mir->mir_name.bv_len = strlen( *names );
    133 			mir->mir_mr = smr;
    134 			if ( avl_insert( &mr_index, (caddr_t) mir,
    135 			                 mr_index_cmp, avl_dup_error ) ) {
    136 				*err = *names;
    137 				ldap_memfree(mir);
    138 				return SLAP_SCHERR_MR_DUP;
    139 			}
    140 			/* FIX: temporal consistency check */
    141 			mr_bvfind(&mir->mir_name);
    142 			names++;
    143 		}
    144 	}
    145 	return 0;
    146 }
    147 
    148 int
    149 mr_make_syntax_compat_with_mr(
    150 	Syntax		*syn,
    151 	MatchingRule	*mr )
    152 {
    153 	int		n = 0;
    154 
    155 	assert( syn != NULL );
    156 	assert( mr != NULL );
    157 
    158 	if ( mr->smr_compat_syntaxes ) {
    159 		/* count esisting */
    160 		for ( n = 0;
    161 			mr->smr_compat_syntaxes[ n ];
    162 			n++ )
    163 		{
    164 			if ( mr->smr_compat_syntaxes[ n ] == syn ) {
    165 				/* already compatible; mmmmh... */
    166 				return 1;
    167 			}
    168 		}
    169 	}
    170 
    171 	mr->smr_compat_syntaxes = ch_realloc(
    172 		mr->smr_compat_syntaxes,
    173 		sizeof( Syntax * )*(n + 2) );
    174 	mr->smr_compat_syntaxes[ n ] = syn;
    175 	mr->smr_compat_syntaxes[ n + 1 ] = NULL;
    176 
    177 	return 0;
    178 }
    179 
    180 int
    181 mr_make_syntax_compat_with_mrs(
    182 	const char *syntax,
    183 	char *const *mrs )
    184 {
    185 	int	r, rc = 0;
    186 	Syntax	*syn;
    187 
    188 	assert( syntax != NULL );
    189 	assert( mrs != NULL );
    190 
    191 	syn = syn_find( syntax );
    192 	if ( syn == NULL ) {
    193 		return -1;
    194 	}
    195 
    196 	for ( r = 0; mrs[ r ] != NULL; r++ ) {
    197 		MatchingRule	*mr = mr_find( mrs[ r ] );
    198 		if ( mr == NULL ) {
    199 			/* matchingRule not found -- ignore by now */
    200 			continue;
    201 		}
    202 
    203 		rc += mr_make_syntax_compat_with_mr( syn, mr );
    204 	}
    205 
    206 	return rc;
    207 }
    208 
    209 int
    210 mr_add(
    211     LDAPMatchingRule		*mr,
    212     slap_mrule_defs_rec	*def,
    213 	MatchingRule	*amr,
    214     const char		**err
    215 )
    216 {
    217 	MatchingRule	*smr;
    218 	Syntax		*syn;
    219 	Syntax		**compat_syn = NULL;
    220 	int		code;
    221 
    222 	if( def->mrd_compat_syntaxes ) {
    223 		int i;
    224 		for( i=0; def->mrd_compat_syntaxes[i]; i++ ) {
    225 			/* just count em */
    226 		}
    227 
    228 		compat_syn = ch_malloc( sizeof(Syntax *) * (i+1) );
    229 
    230 		for( i=0; def->mrd_compat_syntaxes[i]; i++ ) {
    231 			compat_syn[i] = syn_find( def->mrd_compat_syntaxes[i] );
    232 			if( compat_syn[i] == NULL ) {
    233 				ch_free( compat_syn );
    234 				return SLAP_SCHERR_SYN_NOT_FOUND;
    235 			}
    236 		}
    237 
    238 		compat_syn[i] = NULL;
    239 	}
    240 
    241 	smr = (MatchingRule *) ch_calloc( 1, sizeof(MatchingRule) );
    242 	AC_MEMCPY( &smr->smr_mrule, mr, sizeof(LDAPMatchingRule));
    243 
    244 	/*
    245 	 * note: smr_bvoid uses the same memory of smr_mrule.mr_oid;
    246 	 * smr_oidlen is #defined as smr_bvoid.bv_len
    247 	 */
    248 	smr->smr_bvoid.bv_val = smr->smr_mrule.mr_oid;
    249 	smr->smr_oidlen = strlen( mr->mr_oid );
    250 	smr->smr_usage = def->mrd_usage;
    251 	smr->smr_compat_syntaxes = compat_syn;
    252 	smr->smr_normalize = def->mrd_normalize;
    253 	smr->smr_match = def->mrd_match;
    254 	smr->smr_indexer = def->mrd_indexer;
    255 	smr->smr_filter = def->mrd_filter;
    256 	smr->smr_associated = amr;
    257 
    258 	if ( smr->smr_syntax_oid ) {
    259 		if ( (syn = syn_find(smr->smr_syntax_oid)) ) {
    260 			smr->smr_syntax = syn;
    261 		} else {
    262 			*err = smr->smr_syntax_oid;
    263 			ch_free( smr );
    264 			return SLAP_SCHERR_SYN_NOT_FOUND;
    265 		}
    266 	} else {
    267 		*err = "";
    268 		ch_free( smr );
    269 		return SLAP_SCHERR_MR_INCOMPLETE;
    270 	}
    271 	code = mr_insert(smr,err);
    272 	return code;
    273 }
    274 
    275 int
    276 register_matching_rule(
    277 	slap_mrule_defs_rec *def )
    278 {
    279 	LDAPMatchingRule *mr;
    280 	MatchingRule *amr = NULL;
    281 	int		code;
    282 	const char	*err;
    283 
    284 	if( def->mrd_usage == SLAP_MR_NONE && def->mrd_compat_syntaxes == NULL ) {
    285 		Debug( LDAP_DEBUG_ANY, "register_matching_rule: not usable %s\n",
    286 		    def->mrd_desc, 0, 0 );
    287 
    288 		return -1;
    289 	}
    290 
    291 	if( def->mrd_associated != NULL ) {
    292 		amr = mr_find( def->mrd_associated );
    293 		if( amr == NULL ) {
    294 			Debug( LDAP_DEBUG_ANY, "register_matching_rule: "
    295 				"could not locate associated matching rule %s for %s\n",
    296 				def->mrd_associated, def->mrd_desc, 0 );
    297 
    298 			return -1;
    299 		}
    300 
    301 		if (( def->mrd_usage & SLAP_MR_EQUALITY ) &&
    302 			(( def->mrd_usage & SLAP_MR_SUBTYPE_MASK ) == SLAP_MR_NONE ))
    303 		{
    304 			if (( def->mrd_usage & SLAP_MR_EQUALITY ) &&
    305 				(( def->mrd_usage & SLAP_MR_SUBTYPE_MASK ) != SLAP_MR_NONE ))
    306 			{
    307 				Debug( LDAP_DEBUG_ANY, "register_matching_rule: "
    308 						"inappropriate (approx) association %s for %s\n",
    309 					def->mrd_associated, def->mrd_desc, 0 );
    310 				return -1;
    311 			}
    312 
    313 		} else if (!( amr->smr_usage & SLAP_MR_EQUALITY )) {
    314 				Debug( LDAP_DEBUG_ANY, "register_matching_rule: "
    315 					"inappropriate (equalilty) association %s for %s\n",
    316 					def->mrd_associated, def->mrd_desc, 0 );
    317 				return -1;
    318 		}
    319 	}
    320 
    321 	mr = ldap_str2matchingrule( def->mrd_desc, &code, &err,
    322 		LDAP_SCHEMA_ALLOW_ALL );
    323 	if ( !mr ) {
    324 		Debug( LDAP_DEBUG_ANY,
    325 			"Error in register_matching_rule: %s before %s in %s\n",
    326 		    ldap_scherr2str(code), err, def->mrd_desc );
    327 
    328 		return -1;
    329 	}
    330 
    331 
    332 	code = mr_add( mr, def, amr, &err );
    333 
    334 	ldap_memfree( mr );
    335 
    336 	if ( code ) {
    337 		Debug( LDAP_DEBUG_ANY,
    338 			"Error in register_matching_rule: %s for %s in %s\n",
    339 		    scherr2str(code), err, def->mrd_desc );
    340 
    341 		return -1;
    342 	}
    343 
    344 	return 0;
    345 }
    346 
    347 void
    348 mru_destroy( void )
    349 {
    350 	MatchingRuleUse *m;
    351 
    352 	while( !LDAP_SLIST_EMPTY(&mru_list) ) {
    353 		m = LDAP_SLIST_FIRST(&mru_list);
    354 		LDAP_SLIST_REMOVE_HEAD(&mru_list, smru_next);
    355 
    356 		if ( m->smru_str.bv_val ) {
    357 			ch_free( m->smru_str.bv_val );
    358 			m->smru_str.bv_val = NULL;
    359 		}
    360 		/* memory borrowed from m->smru_mr */
    361 		m->smru_oid = NULL;
    362 		m->smru_names = NULL;
    363 		m->smru_desc = NULL;
    364 
    365 		/* free what's left (basically smru_mruleuse.mru_applies_oids) */
    366 		ldap_matchingruleuse_free((LDAPMatchingRuleUse *)m);
    367 	}
    368 }
    369 
    370 int
    371 matching_rule_use_init( void )
    372 {
    373 	MatchingRule	*mr;
    374 	MatchingRuleUse	**mru_ptr = &LDAP_SLIST_FIRST(&mru_list);
    375 
    376 	Debug( LDAP_DEBUG_TRACE, "matching_rule_use_init\n", 0, 0, 0 );
    377 
    378 	LDAP_SLIST_FOREACH( mr, &mr_list, smr_next ) {
    379 		AttributeType	*at;
    380 		MatchingRuleUse	mru_storage = { 0 },
    381 				*mru = &mru_storage;
    382 
    383 		char		**applies_oids = NULL;
    384 
    385 		mr->smr_mru = NULL;
    386 
    387 		/* hide rules marked as HIDE */
    388 		if ( mr->smr_usage & SLAP_MR_HIDE ) {
    389 			continue;
    390 		}
    391 
    392 		/* hide rules not marked as designed for extensibility */
    393 		/* MR_EXT means can be used any attribute type whose
    394 		 * syntax is same as the assertion syntax.
    395 		 * Another mechanism is needed where rule can be used
    396 		 * with attribute of other syntaxes.
    397 		 * Framework doesn't support this (yet).
    398 		 */
    399 
    400 		if (!( ( mr->smr_usage & SLAP_MR_EXT )
    401 			|| mr->smr_compat_syntaxes ) )
    402 		{
    403 			continue;
    404 		}
    405 
    406 		/*
    407 		 * Note: we're using the same values of the corresponding
    408 		 * MatchingRule structure; maybe we'd copy them ...
    409 		 */
    410 		mru->smru_mr = mr;
    411 		mru->smru_obsolete = mr->smr_obsolete;
    412 		mru->smru_applies_oids = NULL;
    413 		LDAP_SLIST_NEXT(mru, smru_next) = NULL;
    414 		mru->smru_oid = mr->smr_oid;
    415 		mru->smru_names = mr->smr_names;
    416 		mru->smru_desc = mr->smr_desc;
    417 
    418 		Debug( LDAP_DEBUG_TRACE, "    %s (%s): ",
    419 				mru->smru_oid,
    420 				mru->smru_names ? mru->smru_names[ 0 ] : "", 0 );
    421 
    422 		at = NULL;
    423 		for ( at_start( &at ); at; at_next( &at ) ) {
    424 			if( at->sat_flags & SLAP_AT_HIDE ) continue;
    425 
    426 			if( mr_usable_with_at( mr, at )) {
    427 				ldap_charray_add( &applies_oids, at->sat_cname.bv_val );
    428 			}
    429 		}
    430 
    431 		/*
    432 		 * Note: the matchingRules that are not used
    433 		 * by any attributeType are not listed as
    434 		 * matchingRuleUse
    435 		 */
    436 		if ( applies_oids != NULL ) {
    437 			mru->smru_applies_oids = applies_oids;
    438 			{
    439 				char *str = ldap_matchingruleuse2str( &mru->smru_mruleuse );
    440 				Debug( LDAP_DEBUG_TRACE, "matchingRuleUse: %s\n", str, 0, 0 );
    441 				ldap_memfree( str );
    442 			}
    443 
    444 			mru = (MatchingRuleUse *)ber_memalloc( sizeof( MatchingRuleUse ) );
    445 			/* call-forward from MatchingRule to MatchingRuleUse */
    446 			mr->smr_mru = mru;
    447 			/* copy static data to newly allocated struct */
    448 			*mru = mru_storage;
    449 			/* append the struct pointer to the end of the list */
    450 			*mru_ptr = mru;
    451 			/* update the list head pointer */
    452 			mru_ptr = &LDAP_SLIST_NEXT(mru,smru_next);
    453 		}
    454 	}
    455 
    456 	return( 0 );
    457 }
    458 
    459 int
    460 mr_usable_with_at(
    461 	MatchingRule	*mr,
    462 	AttributeType	*at )
    463 {
    464 	if ( ( mr->smr_usage & SLAP_MR_EXT ) && (
    465 		mr->smr_syntax == at->sat_syntax ||
    466 		mr == at->sat_equality ||
    467 		mr == at->sat_approx ||
    468 		syn_is_sup( at->sat_syntax, mr->smr_syntax ) ) )
    469 	{
    470 		return 1;
    471 	}
    472 
    473 	if ( mr->smr_compat_syntaxes ) {
    474 		int i;
    475 		for( i=0; mr->smr_compat_syntaxes[i]; i++ ) {
    476 			if( at->sat_syntax == mr->smr_compat_syntaxes[i] ) {
    477 				return 1;
    478 			}
    479 		}
    480 	}
    481 	return 0;
    482 }
    483 
    484 int mr_schema_info( Entry *e )
    485 {
    486 	AttributeDescription *ad_matchingRules = slap_schema.si_ad_matchingRules;
    487 	MatchingRule *mr;
    488 	struct berval nval;
    489 
    490 	LDAP_SLIST_FOREACH(mr, &mr_list, smr_next ) {
    491 		if ( mr->smr_usage & SLAP_MR_HIDE ) {
    492 			/* skip hidden rules */
    493 			continue;
    494 		}
    495 
    496 		if ( ! mr->smr_match ) {
    497 			/* skip rules without matching functions */
    498 			continue;
    499 		}
    500 
    501 		if ( mr->smr_str.bv_val == NULL ) {
    502 			if ( ldap_matchingrule2bv( &mr->smr_mrule, &mr->smr_str ) == NULL ) {
    503 				return -1;
    504 			}
    505 		}
    506 #if 0
    507 		Debug( LDAP_DEBUG_TRACE, "Merging mr [%lu] %s\n",
    508 			mr->smr_str.bv_len, mr->smr_str.bv_val, 0 );
    509 #endif
    510 
    511 		nval.bv_val = mr->smr_oid;
    512 		nval.bv_len = strlen(mr->smr_oid);
    513 		if( attr_merge_one( e, ad_matchingRules, &mr->smr_str, &nval ) ) {
    514 			return -1;
    515 		}
    516 	}
    517 	return 0;
    518 }
    519 
    520 int mru_schema_info( Entry *e )
    521 {
    522 	AttributeDescription *ad_matchingRuleUse
    523 		= slap_schema.si_ad_matchingRuleUse;
    524 	MatchingRuleUse	*mru;
    525 	struct berval nval;
    526 
    527 	LDAP_SLIST_FOREACH( mru, &mru_list, smru_next ) {
    528 		assert( !( mru->smru_usage & SLAP_MR_HIDE ) );
    529 
    530 		if ( mru->smru_str.bv_val == NULL ) {
    531 			if ( ldap_matchingruleuse2bv( &mru->smru_mruleuse, &mru->smru_str )
    532 					== NULL ) {
    533 				return -1;
    534 			}
    535 		}
    536 
    537 #if 0
    538 		Debug( LDAP_DEBUG_TRACE, "Merging mru [%lu] %s\n",
    539 			mru->smru_str.bv_len, mru->smru_str.bv_val, 0 );
    540 #endif
    541 
    542 		nval.bv_val = mru->smru_oid;
    543 		nval.bv_len = strlen(mru->smru_oid);
    544 		if( attr_merge_one( e, ad_matchingRuleUse, &mru->smru_str, &nval ) ) {
    545 			return -1;
    546 		}
    547 	}
    548 	return 0;
    549 }
    550