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