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