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