]> git.sur5r.net Git - openldap/blob - servers/slapd/mr.c
ad00a1ece3497a41ae2ba1b21c6a1d5baf0aa24b
[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                 ldap_matchingrule_free((LDAPMatchingRule *)m);
88         }
89 }
90
91 static int
92 mr_insert(
93     MatchingRule        *smr,
94     const char          **err
95 )
96 {
97         struct mindexrec        *mir;
98         char                    **names;
99
100         LDAP_SLIST_INSERT_HEAD(&mr_list, smr, smr_next);
101
102         if ( smr->smr_oid ) {
103                 mir = (struct mindexrec *)
104                         ch_calloc( 1, sizeof(struct mindexrec) );
105                 mir->mir_name.bv_val = smr->smr_oid;
106                 mir->mir_name.bv_len = strlen( smr->smr_oid );
107                 mir->mir_mr = smr;
108                 if ( avl_insert( &mr_index, (caddr_t) mir,
109                                  mr_index_cmp, avl_dup_error ) ) {
110                         *err = smr->smr_oid;
111                         ldap_memfree(mir);
112                         return SLAP_SCHERR_MR_DUP;
113                 }
114                 /* FIX: temporal consistency check */
115                 mr_bvfind(&mir->mir_name);
116         }
117         if ( (names = smr->smr_names) ) {
118                 while ( *names ) {
119                         mir = (struct mindexrec *)
120                                 ch_calloc( 1, sizeof(struct mindexrec) );
121                         mir->mir_name.bv_val = *names;
122                         mir->mir_name.bv_len = strlen( *names );
123                         mir->mir_mr = smr;
124                         if ( avl_insert( &mr_index, (caddr_t) mir,
125                                          mr_index_cmp, avl_dup_error ) ) {
126                                 *err = *names;
127                                 ldap_memfree(mir);
128                                 return SLAP_SCHERR_MR_DUP;
129                         }
130                         /* FIX: temporal consistency check */
131                         mr_bvfind(&mir->mir_name);
132                         names++;
133                 }
134         }
135         return 0;
136 }
137
138 int
139 mr_add(
140     LDAPMatchingRule            *mr,
141     slap_mrule_defs_rec *def,
142         MatchingRule    *amr,
143     const char          **err
144 )
145 {
146         MatchingRule    *smr;
147         Syntax          *syn;
148         Syntax          **compat_syn = NULL;
149         int             code;
150
151         if( def->mrd_compat_syntaxes ) {
152                 int i;
153                 for( i=0; def->mrd_compat_syntaxes[i]; i++ ) {
154                         /* just count em */
155                 }
156
157                 compat_syn = ch_malloc( sizeof(Syntax *) * (i+1) );
158
159                 for( i=0; def->mrd_compat_syntaxes[i]; i++ ) {
160                         compat_syn[i] = syn_find( def->mrd_compat_syntaxes[i] );
161                         if( compat_syn[i] == NULL ) {
162                                 return SLAP_SCHERR_SYN_NOT_FOUND;
163                         }
164                 }
165
166                 compat_syn[i] = NULL;
167         }
168
169         smr = (MatchingRule *) ch_calloc( 1, sizeof(MatchingRule) );
170         AC_MEMCPY( &smr->smr_mrule, mr, sizeof(LDAPMatchingRule));
171
172         /*
173          * note: smr_bvoid uses the same memory of smr_mrule.mr_oid;
174          * smr_oidlen is #defined as smr_bvoid.bv_len
175          */
176         smr->smr_bvoid.bv_val = smr->smr_mrule.mr_oid;
177         smr->smr_oidlen = strlen( mr->mr_oid );
178         smr->smr_usage = def->mrd_usage;
179         smr->smr_compat_syntaxes = compat_syn;
180         smr->smr_convert = def->mrd_convert;
181         smr->smr_normalize = def->mrd_normalize;
182         smr->smr_match = def->mrd_match;
183         smr->smr_indexer = def->mrd_indexer;
184         smr->smr_filter = def->mrd_filter;
185         smr->smr_associated = amr;
186
187         if ( smr->smr_syntax_oid ) {
188                 if ( (syn = syn_find(smr->smr_syntax_oid)) ) {
189                         smr->smr_syntax = syn;
190                 } else {
191                         *err = smr->smr_syntax_oid;
192                         return SLAP_SCHERR_SYN_NOT_FOUND;
193                 }
194         } else {
195                 *err = "";
196                 return SLAP_SCHERR_MR_INCOMPLETE;
197         }
198         code = mr_insert(smr,err);
199         return code;
200 }
201
202 int
203 register_matching_rule(
204         slap_mrule_defs_rec *def )
205 {
206         LDAPMatchingRule *mr;
207         MatchingRule *amr = NULL;
208         int             code;
209         const char      *err;
210
211         if( def->mrd_usage == SLAP_MR_NONE &&
212                 def->mrd_compat_syntaxes == NULL )
213         {
214 #ifdef NEW_LOGGING
215                 LDAP_LOG( OPERATION, ERR, 
216                         "register_matching_rule: %s not usable\n", def->mrd_desc, 0, 0 );
217 #else
218                 Debug( LDAP_DEBUG_ANY, "register_matching_rule: not usable %s\n",
219                     def->mrd_desc, 0, 0 );
220 #endif
221
222                 return -1;
223         }
224
225         if( def->mrd_associated != NULL ) {
226                 amr = mr_find( def->mrd_associated );
227
228 #if 0
229                 /* ignore for now */
230
231                 if( amr == NULL ) {
232 #ifdef NEW_LOGGING
233                         LDAP_LOG( OPERATION, ERR,
234                            "register_matching_rule: could not locate associated "
235                            "matching rule %s for %s\n",
236                                 def->mrd_associated, def->mrd_desc, 0 );
237 #else
238                         Debug( LDAP_DEBUG_ANY, "register_matching_rule: could not locate "
239                                 "associated matching rule %s for %s\n",
240                                 def->mrd_associated, def->mrd_desc, 0 );
241 #endif
242
243                         return -1;
244                 }
245 #endif
246         }
247
248         mr = ldap_str2matchingrule( def->mrd_desc, &code, &err,
249                 LDAP_SCHEMA_ALLOW_ALL );
250         if ( !mr ) {
251 #ifdef NEW_LOGGING
252                 LDAP_LOG( OPERATION, ERR, 
253                         "register_matching_rule: %s before %s in %s.\n",
254                         ldap_scherr2str(code), err, def->mrd_desc );
255 #else
256                 Debug( LDAP_DEBUG_ANY,
257                         "Error in register_matching_rule: %s before %s in %s\n",
258                     ldap_scherr2str(code), err, def->mrd_desc );
259 #endif
260
261                 return( -1 );
262         }
263
264         code = mr_add( mr, def, amr, &err );
265
266         ldap_memfree( mr );
267
268         if ( code ) {
269 #ifdef NEW_LOGGING
270                 LDAP_LOG( OPERATION, ERR, 
271                         "register_matching_rule: %s for %s in %s.\n",
272                         scherr2str(code), err, def->mrd_desc );
273 #else
274                 Debug( LDAP_DEBUG_ANY,
275                         "Error in register_matching_rule: %s for %s in %s\n",
276                     scherr2str(code), err, def->mrd_desc );
277 #endif
278
279                 return( -1 );
280         }
281
282         return( 0 );
283 }
284
285 void
286 mru_destroy( void )
287 {
288         MatchingRuleUse *m;
289
290         while( !LDAP_SLIST_EMPTY(&mru_list) ) {
291                 m = LDAP_SLIST_FIRST(&mru_list);
292                 LDAP_SLIST_REMOVE_HEAD(&mru_list, smru_next);
293
294                 if ( m->smru_str.bv_val ) {
295                         ch_free( m->smru_str.bv_val );
296                 }
297                 /* memory borrowed from m->smru_mr */
298                 m->smru_oid = NULL;
299                 m->smru_names = NULL;
300                 m->smru_desc = NULL;
301
302                 /* free what's left (basically 
303                  * smru_mruleuse.mru_applies_oids) */
304                 ldap_matchingruleuse_free((LDAPMatchingRuleUse *)m);
305         }
306 }
307
308 int
309 matching_rule_use_init( void )
310 {
311         MatchingRule    *mr;
312         MatchingRuleUse **mru_ptr = &LDAP_SLIST_FIRST(&mru_list);
313
314 #ifdef NEW_LOGGING
315         LDAP_LOG( OPERATION, INFO, "matching_rule_use_init\n", 0, 0, 0 );
316 #else
317         Debug( LDAP_DEBUG_TRACE, "matching_rule_use_init\n", 0, 0, 0 );
318 #endif
319
320         LDAP_SLIST_FOREACH( mr, &mr_list, smr_next ) {
321                 AttributeType   *at;
322                 MatchingRuleUse mru_storage, *mru = &mru_storage;
323
324                 char            **applies_oids = NULL;
325
326                 mr->smr_mru = NULL;
327
328                 /* hide rules marked as HIDE */
329                 if ( mr->smr_usage & SLAP_MR_HIDE ) {
330                         continue;
331                 }
332
333                 /* hide rules not marked as designed for extensibility */
334                 /* MR_EXT means can be used any attribute type whose
335                  * syntax is same as the assertion syntax.
336                  * Another mechanism is needed where rule can be used
337                  * with attribute of other syntaxes.
338                  * Framework doesn't support this (yet).
339                  */
340
341                 if (!( ( mr->smr_usage & SLAP_MR_EXT )
342                         || mr->smr_compat_syntaxes ) )
343                 {
344                         continue;
345                 }
346
347                 memset( mru, 0, sizeof( MatchingRuleUse ) );
348
349                 /*
350                  * Note: we're using the same values of the corresponding 
351                  * MatchingRule structure; maybe we'd copy them ...
352                  */
353                 mru->smru_mr = mr;
354                 mru->smru_obsolete = mr->smr_obsolete;
355                 mru->smru_applies_oids = NULL;
356                 LDAP_SLIST_NEXT(mru, smru_next) = NULL;
357                 mru->smru_oid = mr->smr_oid;
358                 mru->smru_names = mr->smr_names;
359                 mru->smru_desc = mr->smr_desc;
360
361 #ifdef NEW_LOGGING
362                 LDAP_LOG( OPERATION, INFO, "    %s (%s): ", 
363                                 mru->smru_oid, 
364                                 mru->smru_names ? mru->smru_names[ 0 ] : "", 0 );
365 #else
366                 Debug( LDAP_DEBUG_TRACE, "    %s (%s): ", 
367                                 mru->smru_oid, 
368                                 mru->smru_names ? mru->smru_names[ 0 ] : "", 0 );
369 #endif
370
371                 at = NULL;
372                 for ( at_start( &at ); at; at_next( &at ) ) {
373                         if( at->sat_flags & SLAP_AT_HIDE ) continue;
374
375                         if( mr_usable_with_at( mr, at )) {
376                                 ldap_charray_add( &applies_oids, at->sat_cname.bv_val );
377                         }
378                 }
379
380                 /*
381                  * Note: the matchingRules that are not used
382                  * by any attributeType are not listed as
383                  * matchingRuleUse
384                  */
385                 if ( applies_oids != NULL ) {
386                         mru->smru_applies_oids = applies_oids;
387 #ifdef NEW_LOGGING
388                         {
389                                 char *str = ldap_matchingruleuse2str( &mru->smru_mruleuse );
390                                 LDAP_LOG( OPERATION, INFO, "matchingRuleUse: %s\n", str, 0, 0 );
391                                 ldap_memfree( str );
392                         }
393 #else
394                         {
395                                 char *str = ldap_matchingruleuse2str( &mru->smru_mruleuse );
396                                 Debug( LDAP_DEBUG_TRACE, "matchingRuleUse: %s\n", str, 0, 0 );
397                                 ldap_memfree( str );
398                         }
399 #endif
400
401                         mru = (MatchingRuleUse *)ber_memalloc( sizeof( MatchingRuleUse ) );
402                         /* call-forward from MatchingRule to MatchingRuleUse */
403                         mr->smr_mru = mru;
404                         /* copy static data to newly allocated struct */
405                         *mru = mru_storage;
406                         /* append the struct pointer to the end of the list */
407                         *mru_ptr = mru;
408                         /* update the list head pointer */
409                         mru_ptr = &LDAP_SLIST_NEXT(mru,smru_next);
410                 }
411         }
412
413         return( 0 );
414 }
415
416 int mr_usable_with_at(
417         MatchingRule *mr,
418         AttributeType *at )
419 {
420         if( mr->smr_usage & SLAP_MR_EXT && ( 
421                 mr->smr_syntax == at->sat_syntax ||
422                 mr == at->sat_equality || mr == at->sat_approx ) )
423         {
424                 return 1;
425         }
426
427         if ( mr->smr_compat_syntaxes ) {
428                 int i;
429                 for( i=0; mr->smr_compat_syntaxes[i]; i++ ) {
430                         if( at->sat_syntax == mr->smr_compat_syntaxes[i] ) {
431                                 return 1;
432                         }
433                 }
434         }
435         return 0;
436 }
437
438 int mr_schema_info( Entry *e )
439 {
440         MatchingRule *mr;
441
442         AttributeDescription *ad_matchingRules = slap_schema.si_ad_matchingRules;
443
444         LDAP_SLIST_FOREACH(mr, &mr_list, smr_next ) {
445                 if ( mr->smr_usage & SLAP_MR_HIDE ) {
446                         /* skip hidden rules */
447                         continue;
448                 }
449
450                 if ( ! mr->smr_match ) {
451                         /* skip rules without matching functions */
452                         continue;
453                 }
454
455                 if ( mr->smr_str.bv_val == NULL ) {
456                         if ( ldap_matchingrule2bv( &mr->smr_mrule, &mr->smr_str ) == NULL ) {
457                                 return -1;
458                         }
459                 }
460 #if 0
461                 Debug( LDAP_DEBUG_TRACE, "Merging mr [%lu] %s\n",
462                         mr->smr_str.bv_len, mr->smr_str.bv_val, 0 );
463 #endif
464                 if( attr_merge_one( e, ad_matchingRules, &mr->smr_str ) )
465                         return -1;
466         }
467         return 0;
468 }
469
470 int mru_schema_info( Entry *e )
471 {
472         MatchingRuleUse *mru;
473
474         AttributeDescription *ad_matchingRuleUse 
475                 = slap_schema.si_ad_matchingRuleUse;
476
477         LDAP_SLIST_FOREACH( mru, &mru_list, smru_next ) {
478
479                 assert( !( mru->smru_usage & SLAP_MR_HIDE ) );
480
481                 if ( mru->smru_str.bv_val == NULL ) {
482                         if ( ldap_matchingruleuse2bv( &mru->smru_mruleuse, &mru->smru_str )
483                                         == NULL ) {
484                                 return -1;
485                         }
486                 }
487
488 #if 0
489                 Debug( LDAP_DEBUG_TRACE, "Merging mru [%lu] %s\n",
490                         mru->smru_str.bv_len, mru->smru_str.bv_val, 0 );
491 #endif
492                 if( attr_merge_one( e, ad_matchingRuleUse, &mru->smru_str ) )
493                         return -1;
494         }
495         return 0;
496 }