1/* mr.c - routines to manage matching rule definitions */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2011 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 27struct mindexrec { 28 struct berval mir_name; 29 MatchingRule *mir_mr; 30}; 31 32static Avlnode *mr_index = NULL; 33static LDAP_SLIST_HEAD(MRList, MatchingRule) mr_list 34 = LDAP_SLIST_HEAD_INITIALIZER(&mr_list); 35static LDAP_SLIST_HEAD(MRUList, MatchingRuleUse) mru_list 36 = LDAP_SLIST_HEAD_INITIALIZER(&mru_list); 37 38static int 39mr_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 51static int 52mr_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 64MatchingRule * 65mr_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 74MatchingRule * 75mr_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 85void 86mr_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 100static int 101mr_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 148int 149mr_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 180int 181mr_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 209int 210mr_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 275int 276register_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 347void 348mru_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 370int 371matching_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 459int 460mr_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 484int 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 520int 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