1 /* $NetBSD: mr.c,v 1.1.1.4 2014/05/28 09:58:47 tron 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