mr.c revision 1.1.1.2 1 /* $NetBSD: mr.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $ */
2
3 /* mr.c - routines to manage matching rule definitions */
4 /* OpenLDAP: pkg/ldap/servers/slapd/mr.c,v 1.64.2.5 2009/01/22 00:01:01 kurt Exp */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 1998-2009 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