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