]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
Memory context tweaks for Bind
[openldap] / servers / slapd / schema_init.c
1 /* schema_init.c - init builtin schema */
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 #include <limits.h>
12
13 #include <ac/ctype.h>
14 #include <ac/errno.h>
15 #include <ac/string.h>
16 #include <ac/socket.h>
17
18 #include "slap.h"
19 #include "ldap_pvt.h"
20 #include "lber_pvt.h"
21
22 #include "ldap_utf8.h"
23
24 #include "lutil_hash.h"
25 #define HASH_BYTES                              LUTIL_HASH_BYTES
26 #define HASH_CONTEXT                    lutil_HASH_CTX
27 #define HASH_Init(c)                    lutil_HASHInit(c)
28 #define HASH_Update(c,buf,len)  lutil_HASHUpdate(c,buf,len)
29 #define HASH_Final(d,c)                 lutil_HASHFinal(d,c)
30
31 #define SLAP_NVALUES 1
32
33 /* not yet implemented */
34 #define objectIdentifierNormalize NULL
35 #define integerOrderingMatch NULL
36 #define uniqueMemberMatch NULL
37 #define integerFirstComponentNormalize NULL
38 #define objectIdentifierFirstComponentNormalize NULL
39
40 #define OpenLDAPaciMatch                        NULL
41
42 /* approx matching rules */
43 #ifdef SLAP_NVALUES
44 #define directoryStringApproxMatchOID   NULL
45 #define IA5StringApproxMatchOID                 NULL
46 #else
47 #define directoryStringApproxMatchOID   "1.3.6.1.4.1.4203.666.4.4"
48 #define directoryStringApproxMatch      approxMatch
49 #define directoryStringApproxIndexer    approxIndexer
50 #define directoryStringApproxFilter     approxFilter
51 #define IA5StringApproxMatchOID                 "1.3.6.1.4.1.4203.666.4.5"
52 #define IA5StringApproxMatch                    approxMatch
53 #define IA5StringApproxIndexer                  approxIndexer
54 #define IA5StringApproxFilter                   approxFilter
55 #endif
56
57 static int
58 inValidate(
59         Syntax *syntax,
60         struct berval *in )
61 {
62         /* no value allowed */
63         return LDAP_INVALID_SYNTAX;
64 }
65
66 static int
67 blobValidate(
68         Syntax *syntax,
69         struct berval *in )
70 {
71         /* any value allowed */
72         return LDAP_SUCCESS;
73 }
74
75 #define berValidate blobValidate
76
77 static int
78 octetStringMatch(
79         int *matchp,
80         slap_mask_t flags,
81         Syntax *syntax,
82         MatchingRule *mr,
83         struct berval *value,
84         void *assertedValue )
85 {
86         struct berval *asserted = (struct berval *) assertedValue;
87         int match = value->bv_len - asserted->bv_len;
88
89         if( match == 0 ) {
90                 match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
91         }
92
93         *matchp = match;
94         return LDAP_SUCCESS;
95 }
96
97 static int
98 octetStringOrderingMatch(
99         int *matchp,
100         slap_mask_t flags,
101         Syntax *syntax,
102         MatchingRule *mr,
103         struct berval *value,
104         void *assertedValue )
105 {
106         struct berval *asserted = (struct berval *) assertedValue;
107         ber_len_t v_len  = value->bv_len;
108         ber_len_t av_len = asserted->bv_len;
109
110         int match = memcmp( value->bv_val, asserted->bv_val,
111                 (v_len < av_len ? v_len : av_len) );
112
113         if( match == 0 ) match = v_len - av_len;
114
115         *matchp = match;
116         return LDAP_SUCCESS;
117 }
118
119 /* Index generation function */
120 int octetStringIndexer(
121         slap_mask_t use,
122         slap_mask_t flags,
123         Syntax *syntax,
124         MatchingRule *mr,
125         struct berval *prefix,
126         BerVarray values,
127         BerVarray *keysp,
128         void *ctx )
129 {
130         int i;
131         size_t slen, mlen;
132         BerVarray keys;
133         HASH_CONTEXT HASHcontext;
134         unsigned char HASHdigest[HASH_BYTES];
135         struct berval digest;
136         digest.bv_val = HASHdigest;
137         digest.bv_len = sizeof(HASHdigest);
138
139         for( i=0; values[i].bv_val != NULL; i++ ) {
140                 /* just count them */
141         }
142
143         /* we should have at least one value at this point */
144         assert( i > 0 );
145
146         keys = sl_malloc( sizeof( struct berval ) * (i+1), ctx );
147
148         slen = syntax->ssyn_oidlen;
149         mlen = mr->smr_oidlen;
150
151         for( i=0; values[i].bv_val != NULL; i++ ) {
152                 HASH_Init( &HASHcontext );
153                 if( prefix != NULL && prefix->bv_len > 0 ) {
154                         HASH_Update( &HASHcontext,
155                                 prefix->bv_val, prefix->bv_len );
156                 }
157                 HASH_Update( &HASHcontext,
158                         syntax->ssyn_oid, slen );
159                 HASH_Update( &HASHcontext,
160                         mr->smr_oid, mlen );
161                 HASH_Update( &HASHcontext,
162                         values[i].bv_val, values[i].bv_len );
163                 HASH_Final( HASHdigest, &HASHcontext );
164
165                 ber_dupbv_x( &keys[i], &digest, ctx );
166         }
167
168         keys[i].bv_val = NULL;
169         keys[i].bv_len = 0;
170
171         *keysp = keys;
172
173         return LDAP_SUCCESS;
174 }
175
176 /* Index generation function */
177 int octetStringFilter(
178         slap_mask_t use,
179         slap_mask_t flags,
180         Syntax *syntax,
181         MatchingRule *mr,
182         struct berval *prefix,
183         void * assertedValue,
184         BerVarray *keysp,
185         void *ctx )
186 {
187         size_t slen, mlen;
188         BerVarray keys;
189         HASH_CONTEXT HASHcontext;
190         unsigned char HASHdigest[HASH_BYTES];
191         struct berval *value = (struct berval *) assertedValue;
192         struct berval digest;
193         digest.bv_val = HASHdigest;
194         digest.bv_len = sizeof(HASHdigest);
195
196         slen = syntax->ssyn_oidlen;
197         mlen = mr->smr_oidlen;
198
199         keys = sl_malloc( sizeof( struct berval ) * 2, ctx );
200
201         HASH_Init( &HASHcontext );
202         if( prefix != NULL && prefix->bv_len > 0 ) {
203                 HASH_Update( &HASHcontext,
204                         prefix->bv_val, prefix->bv_len );
205         }
206         HASH_Update( &HASHcontext,
207                 syntax->ssyn_oid, slen );
208         HASH_Update( &HASHcontext,
209                 mr->smr_oid, mlen );
210         HASH_Update( &HASHcontext,
211                 value->bv_val, value->bv_len );
212         HASH_Final( HASHdigest, &HASHcontext );
213
214         ber_dupbv_x( keys, &digest, ctx );
215         keys[1].bv_val = NULL;
216         keys[1].bv_len = 0;
217
218         *keysp = keys;
219
220         return LDAP_SUCCESS;
221 }
222
223 static int
224 octetStringSubstringsMatch(
225         int *matchp,
226         slap_mask_t flags,
227         Syntax *syntax,
228         MatchingRule *mr,
229         struct berval *value,
230         void *assertedValue )
231 {
232         int match = 0;
233         SubstringsAssertion *sub = assertedValue;
234         struct berval left = *value;
235         int i;
236         ber_len_t inlen = 0;
237
238         /* Add up asserted input length */
239         if( sub->sa_initial.bv_val ) {
240                 inlen += sub->sa_initial.bv_len;
241         }
242         if( sub->sa_any ) {
243                 for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
244                         inlen += sub->sa_any[i].bv_len;
245                 }
246         }
247         if( sub->sa_final.bv_val ) {
248                 inlen += sub->sa_final.bv_len;
249         }
250
251         if( sub->sa_initial.bv_val ) {
252                 if( inlen > left.bv_len ) {
253                         match = 1;
254                         goto done;
255                 }
256
257                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
258                         sub->sa_initial.bv_len );
259
260                 if( match != 0 ) {
261                         goto done;
262                 }
263
264                 left.bv_val += sub->sa_initial.bv_len;
265                 left.bv_len -= sub->sa_initial.bv_len;
266                 inlen -= sub->sa_initial.bv_len;
267         }
268
269         if( sub->sa_final.bv_val ) {
270                 if( inlen > left.bv_len ) {
271                         match = 1;
272                         goto done;
273                 }
274
275                 match = memcmp( sub->sa_final.bv_val,
276                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
277                         sub->sa_final.bv_len );
278
279                 if( match != 0 ) {
280                         goto done;
281                 }
282
283                 left.bv_len -= sub->sa_final.bv_len;
284                 inlen -= sub->sa_final.bv_len;
285         }
286
287         if( sub->sa_any ) {
288                 for(i=0; sub->sa_any[i].bv_val; i++) {
289                         ber_len_t idx;
290                         char *p;
291
292 retry:
293                         if( inlen > left.bv_len ) {
294                                 /* not enough length */
295                                 match = 1;
296                                 goto done;
297                         }
298
299                         if( sub->sa_any[i].bv_len == 0 ) {
300                                 continue;
301                         }
302
303                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
304
305                         if( p == NULL ) {
306                                 match = 1;
307                                 goto done;
308                         }
309
310                         idx = p - left.bv_val;
311
312                         if( idx >= left.bv_len ) {
313                                 /* this shouldn't happen */
314                                 return LDAP_OTHER;
315                         }
316
317                         left.bv_val = p;
318                         left.bv_len -= idx;
319
320                         if( sub->sa_any[i].bv_len > left.bv_len ) {
321                                 /* not enough left */
322                                 match = 1;
323                                 goto done;
324                         }
325
326                         match = memcmp( left.bv_val,
327                                 sub->sa_any[i].bv_val,
328                                 sub->sa_any[i].bv_len );
329
330                         if( match != 0 ) {
331                                 left.bv_val++;
332                                 left.bv_len--;
333                                 goto retry;
334                         }
335
336                         left.bv_val += sub->sa_any[i].bv_len;
337                         left.bv_len -= sub->sa_any[i].bv_len;
338                         inlen -= sub->sa_any[i].bv_len;
339                 }
340         }
341
342 done:
343         *matchp = match;
344         return LDAP_SUCCESS;
345 }
346
347 /* Substrings Index generation function */
348 static int
349 octetStringSubstringsIndexer(
350         slap_mask_t use,
351         slap_mask_t flags,
352         Syntax *syntax,
353         MatchingRule *mr,
354         struct berval *prefix,
355         BerVarray values,
356         BerVarray *keysp,
357         void *ctx )
358 {
359         ber_len_t i, j, nkeys;
360         size_t slen, mlen;
361         BerVarray keys;
362
363         HASH_CONTEXT HASHcontext;
364         unsigned char HASHdigest[HASH_BYTES];
365         struct berval digest;
366         digest.bv_val = HASHdigest;
367         digest.bv_len = sizeof(HASHdigest);
368
369         nkeys=0;
370
371         for( i=0; values[i].bv_val != NULL; i++ ) {
372                 /* count number of indices to generate */
373                 if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
374                         continue;
375                 }
376
377                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
378                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
379                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
380                                         (SLAP_INDEX_SUBSTR_MINLEN - 1);
381                         } else {
382                                 nkeys += values[i].bv_len - (SLAP_INDEX_SUBSTR_MINLEN - 1);
383                         }
384                 }
385
386                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
387                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
388                                 nkeys += values[i].bv_len - (SLAP_INDEX_SUBSTR_MAXLEN - 1);
389                         }
390                 }
391
392                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
393                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
394                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
395                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
396                         } else {
397                                 nkeys += values[i].bv_len - (SLAP_INDEX_SUBSTR_MINLEN - 1);
398                         }
399                 }
400         }
401
402         if( nkeys == 0 ) {
403                 /* no keys to generate */
404                 *keysp = NULL;
405                 return LDAP_SUCCESS;
406         }
407
408         keys = sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
409
410         slen = syntax->ssyn_oidlen;
411         mlen = mr->smr_oidlen;
412
413         nkeys=0;
414         for( i=0; values[i].bv_val != NULL; i++ ) {
415                 ber_len_t j,max;
416
417                 if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
418
419                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
420                         ( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
421                 {
422                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
423                         max = values[i].bv_len - (SLAP_INDEX_SUBSTR_MAXLEN - 1);
424
425                         for( j=0; j<max; j++ ) {
426                                 HASH_Init( &HASHcontext );
427                                 if( prefix != NULL && prefix->bv_len > 0 ) {
428                                         HASH_Update( &HASHcontext,
429                                                 prefix->bv_val, prefix->bv_len );
430                                 }
431
432                                 HASH_Update( &HASHcontext,
433                                         &pre, sizeof( pre ) );
434                                 HASH_Update( &HASHcontext,
435                                         syntax->ssyn_oid, slen );
436                                 HASH_Update( &HASHcontext,
437                                         mr->smr_oid, mlen );
438                                 HASH_Update( &HASHcontext,
439                                         &values[i].bv_val[j],
440                                         SLAP_INDEX_SUBSTR_MAXLEN );
441                                 HASH_Final( HASHdigest, &HASHcontext );
442
443                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
444                         }
445                 }
446
447                 max = SLAP_INDEX_SUBSTR_MAXLEN < values[i].bv_len
448                         ? SLAP_INDEX_SUBSTR_MAXLEN : values[i].bv_len;
449
450                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
451                         char pre;
452
453                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
454                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
455                                 HASH_Init( &HASHcontext );
456                                 if( prefix != NULL && prefix->bv_len > 0 ) {
457                                         HASH_Update( &HASHcontext,
458                                                 prefix->bv_val, prefix->bv_len );
459                                 }
460                                 HASH_Update( &HASHcontext,
461                                         &pre, sizeof( pre ) );
462                                 HASH_Update( &HASHcontext,
463                                         syntax->ssyn_oid, slen );
464                                 HASH_Update( &HASHcontext,
465                                         mr->smr_oid, mlen );
466                                 HASH_Update( &HASHcontext,
467                                         values[i].bv_val, j );
468                                 HASH_Final( HASHdigest, &HASHcontext );
469
470                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
471                         }
472
473                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
474                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
475                                 HASH_Init( &HASHcontext );
476                                 if( prefix != NULL && prefix->bv_len > 0 ) {
477                                         HASH_Update( &HASHcontext,
478                                                 prefix->bv_val, prefix->bv_len );
479                                 }
480                                 HASH_Update( &HASHcontext,
481                                         &pre, sizeof( pre ) );
482                                 HASH_Update( &HASHcontext,
483                                         syntax->ssyn_oid, slen );
484                                 HASH_Update( &HASHcontext,
485                                         mr->smr_oid, mlen );
486                                 HASH_Update( &HASHcontext,
487                                         &values[i].bv_val[values[i].bv_len-j], j );
488                                 HASH_Final( HASHdigest, &HASHcontext );
489
490                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
491                         }
492
493                 }
494
495         }
496
497         if( nkeys > 0 ) {
498                 keys[nkeys].bv_val = NULL;
499                 *keysp = keys;
500         } else {
501                 ch_free( keys );
502                 *keysp = NULL;
503         }
504
505         return LDAP_SUCCESS;
506 }
507
508 static int
509 octetStringSubstringsFilter (
510         slap_mask_t use,
511         slap_mask_t flags,
512         Syntax *syntax,
513         MatchingRule *mr,
514         struct berval *prefix,
515         void * assertedValue,
516         BerVarray *keysp,
517         void *ctx)
518 {
519         SubstringsAssertion *sa;
520         char pre;
521         unsigned casefold;
522         ber_len_t nkeys = 0;
523         size_t slen, mlen, klen;
524         BerVarray keys;
525         HASH_CONTEXT HASHcontext;
526         unsigned char HASHdigest[HASH_BYTES];
527         struct berval *value;
528         struct berval digest;
529
530         sa = (SubstringsAssertion *) assertedValue;
531
532         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL
533                 && sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
534         {
535                 nkeys++;
536         }
537
538         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
539                 ber_len_t i;
540                 for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
541                         if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
542                                 /* don't bother accounting for stepping */
543                                 nkeys += sa->sa_any[i].bv_len -
544                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
545                         }
546                 }
547         }
548
549         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
550                 sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
551         {
552                 nkeys++;
553         }
554
555         if( nkeys == 0 ) {
556                 *keysp = NULL;
557                 return LDAP_SUCCESS;
558         }
559
560         digest.bv_val = HASHdigest;
561         digest.bv_len = sizeof(HASHdigest);
562
563         slen = syntax->ssyn_oidlen;
564         mlen = mr->smr_oidlen;
565
566         keys = sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
567         nkeys = 0;
568
569         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
570                 sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
571         {
572                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
573                 value = &sa->sa_initial;
574
575                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
576                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
577
578                 HASH_Init( &HASHcontext );
579                 if( prefix != NULL && prefix->bv_len > 0 ) {
580                         HASH_Update( &HASHcontext,
581                                 prefix->bv_val, prefix->bv_len );
582                 }
583                 HASH_Update( &HASHcontext,
584                         &pre, sizeof( pre ) );
585                 HASH_Update( &HASHcontext,
586                         syntax->ssyn_oid, slen );
587                 HASH_Update( &HASHcontext,
588                         mr->smr_oid, mlen );
589                 HASH_Update( &HASHcontext,
590                         value->bv_val, klen );
591                 HASH_Final( HASHdigest, &HASHcontext );
592
593                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
594         }
595
596         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
597                 ber_len_t i, j;
598                 pre = SLAP_INDEX_SUBSTR_PREFIX;
599                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
600
601                 for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
602                         if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
603                                 continue;
604                         }
605
606                         value = &sa->sa_any[i];
607
608                         for(j=0;
609                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
610                                 j += SLAP_INDEX_SUBSTR_STEP )
611                         {
612                                 HASH_Init( &HASHcontext );
613                                 if( prefix != NULL && prefix->bv_len > 0 ) {
614                                         HASH_Update( &HASHcontext,
615                                                 prefix->bv_val, prefix->bv_len );
616                                 }
617                                 HASH_Update( &HASHcontext,
618                                         &pre, sizeof( pre ) );
619                                 HASH_Update( &HASHcontext,
620                                         syntax->ssyn_oid, slen );
621                                 HASH_Update( &HASHcontext,
622                                         mr->smr_oid, mlen );
623                                 HASH_Update( &HASHcontext,
624                                         &value->bv_val[j], klen ); 
625                                 HASH_Final( HASHdigest, &HASHcontext );
626
627                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
628                         }
629                 }
630         }
631
632         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
633                 sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
634         {
635                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
636                 value = &sa->sa_final;
637
638                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
639                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
640
641                 HASH_Init( &HASHcontext );
642                 if( prefix != NULL && prefix->bv_len > 0 ) {
643                         HASH_Update( &HASHcontext,
644                                 prefix->bv_val, prefix->bv_len );
645                 }
646                 HASH_Update( &HASHcontext,
647                         &pre, sizeof( pre ) );
648                 HASH_Update( &HASHcontext,
649                         syntax->ssyn_oid, slen );
650                 HASH_Update( &HASHcontext,
651                         mr->smr_oid, mlen );
652                 HASH_Update( &HASHcontext,
653                         &value->bv_val[value->bv_len-klen], klen );
654                 HASH_Final( HASHdigest, &HASHcontext );
655
656                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
657         }
658
659         if( nkeys > 0 ) {
660                 keys[nkeys].bv_val = NULL;
661                 *keysp = keys;
662         } else {
663                 ch_free( keys );
664                 *keysp = NULL;
665         }
666
667         return LDAP_SUCCESS;
668 }
669
670 static int
671 bitStringValidate(
672         Syntax *syntax,
673         struct berval *in )
674 {
675         ber_len_t i;
676
677         /* very unforgiving validation, requires no normalization
678          * before simplistic matching
679          */
680         if( in->bv_len < 3 ) {
681                 return LDAP_INVALID_SYNTAX;
682         }
683
684         /*
685          * RFC 2252 section 6.3 Bit String
686          *      bitstring = "'" *binary-digit "'B"
687          *      binary-digit = "0" / "1"
688          * example: '0101111101'B
689          */
690         
691         if( in->bv_val[0] != '\'' ||
692                 in->bv_val[in->bv_len-2] != '\'' ||
693                 in->bv_val[in->bv_len-1] != 'B' )
694         {
695                 return LDAP_INVALID_SYNTAX;
696         }
697
698         for( i=in->bv_len-3; i>0; i-- ) {
699                 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
700                         return LDAP_INVALID_SYNTAX;
701                 }
702         }
703
704         return LDAP_SUCCESS;
705 }
706
707 static int
708 nameUIDValidate(
709         Syntax *syntax,
710         struct berval *in )
711 {
712         int rc;
713         struct berval dn;
714
715         if( in->bv_len == 0 ) return LDAP_SUCCESS;
716
717         ber_dupbv( &dn, in );
718         if( !dn.bv_val ) return LDAP_OTHER;
719
720         if( dn.bv_val[dn.bv_len-1] == 'B'
721                 && dn.bv_val[dn.bv_len-2] == '\'' )
722         {
723                 /* assume presence of optional UID */
724                 ber_len_t i;
725
726                 for(i=dn.bv_len-3; i>1; i--) {
727                         if( dn.bv_val[i] != '0' && dn.bv_val[i] != '1' ) {
728                                 break;
729                         }
730                 }
731                 if( dn.bv_val[i] != '\'' || dn.bv_val[i-1] != '#' ) {
732                         ber_memfree( dn.bv_val );
733                         return LDAP_INVALID_SYNTAX;
734                 }
735
736                 /* trim the UID to allow use of dnValidate */
737                 dn.bv_val[i-1] = '\0';
738                 dn.bv_len = i-1;
739         }
740
741         rc = dnValidate( NULL, &dn );
742
743         ber_memfree( dn.bv_val );
744         return rc;
745 }
746
747 static int
748 uniqueMemberNormalize(
749         slap_mask_t usage,
750         Syntax *syntax,
751         MatchingRule *mr,
752         struct berval *val,
753         struct berval *normalized,
754         void *ctx )
755 {
756         struct berval out;
757         int rc;
758
759         ber_dupbv( &out, val );
760         if( out.bv_len != 0 ) {
761                 struct berval uid = { 0, NULL };
762
763                 if( out.bv_val[out.bv_len-1] == 'B'
764                         && out.bv_val[out.bv_len-2] == '\'' )
765                 {
766                         /* assume presence of optional UID */
767                         uid.bv_val = strrchr( out.bv_val, '#' );
768
769                         if( uid.bv_val == NULL ) {
770                                 free( out.bv_val );
771                                 return LDAP_INVALID_SYNTAX;
772                         }
773
774                         uid.bv_len = out.bv_len - (uid.bv_val - out.bv_val);
775                         out.bv_len -= uid.bv_len--;
776
777                         /* temporarily trim the UID */
778                         *(uid.bv_val++) = '\0';
779                 }
780
781                 rc = dnNormalize2( NULL, &out, normalized, ctx );
782
783                 if( rc != LDAP_SUCCESS ) {
784                         free( out.bv_val );
785                         return LDAP_INVALID_SYNTAX;
786                 }
787
788                 if( uid.bv_len ) {
789                         normalized->bv_val = ch_realloc( normalized->bv_val,
790                                 normalized->bv_len + uid.bv_len + sizeof("#") );
791
792                         /* insert the separator */
793                         normalized->bv_val[normalized->bv_len++] = '#';
794
795                         /* append the UID */
796                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
797                                 uid.bv_val, uid.bv_len );
798                         normalized->bv_len += uid.bv_len;
799
800                         /* terminate */
801                         normalized->bv_val[normalized->bv_len] = '\0';
802                 }
803
804                 free( out.bv_val );
805         }
806
807         return LDAP_SUCCESS;
808 }
809
810 /*
811  * Handling boolean syntax and matching is quite rigid.
812  * A more flexible approach would be to allow a variety
813  * of strings to be normalized and prettied into TRUE
814  * and FALSE.
815  */
816 static int
817 booleanValidate(
818         Syntax *syntax,
819         struct berval *in )
820 {
821         /* very unforgiving validation, requires no normalization
822          * before simplistic matching
823          */
824
825         if( in->bv_len == 4 ) {
826                 if( !memcmp( in->bv_val, "TRUE", 4 ) ) {
827                         return LDAP_SUCCESS;
828                 }
829         } else if( in->bv_len == 5 ) {
830                 if( !memcmp( in->bv_val, "FALSE", 5 ) ) {
831                         return LDAP_SUCCESS;
832                 }
833         }
834
835         return LDAP_INVALID_SYNTAX;
836 }
837
838 static int
839 booleanMatch(
840         int *matchp,
841         slap_mask_t flags,
842         Syntax *syntax,
843         MatchingRule *mr,
844         struct berval *value,
845         void *assertedValue )
846 {
847         /* simplistic matching allowed by rigid validation */
848         struct berval *asserted = (struct berval *) assertedValue;
849         *matchp = value->bv_len != asserted->bv_len;
850         return LDAP_SUCCESS;
851 }
852
853 /*-------------------------------------------------------------------
854 LDAP/X.500 string syntax / matching rules have a few oddities.  This
855 comment attempts to detail how slapd(8) treats them.
856
857 Summary:
858   StringSyntax          X.500   LDAP    Matching/Comments
859   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
860   PrintableString       subset  subset  i/e + ignore insignificant spaces
861   PrintableString       subset  subset  i/e + ignore insignificant spaces
862   NumericString         subset  subset  ignore all spaces
863   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
864   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
865
866   TelephoneNumber       subset  subset  i + ignore all spaces and "-"
867
868   See draft-ietf-ldapbis-strpro for details (once published).
869
870
871 Directory String -
872   In X.500(93), a directory string can be either a PrintableString,
873   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
874   In later versions, more CHOICEs were added.  In all cases the string
875   must be non-empty.
876
877   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
878   A directory string cannot be zero length.
879
880   For matching, there are both case ignore and exact rules.  Both
881   also require that "insignificant" spaces be ignored.
882         spaces before the first non-space are ignored;
883         spaces after the last non-space are ignored;
884         spaces after a space are ignored.
885   Note: by these rules (and as clarified in X.520), a string of only
886   spaces is to be treated as if held one space, not empty (which
887   would be a syntax error).
888
889 NumericString
890   In ASN.1, numeric string is just a string of digits and spaces
891   and could be empty.  However, in X.500, all attribute values of
892   numeric string carry a non-empty constraint.  For example:
893
894         internationalISDNNumber ATTRIBUTE ::= {
895                 WITH SYNTAX InternationalISDNNumber
896                 EQUALITY MATCHING RULE numericStringMatch
897                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
898                 ID id-at-internationalISDNNumber }
899         InternationalISDNNumber ::=
900             NumericString (SIZE(1..ub-international-isdn-number))
901
902   Unforunately, some assertion values are don't carry the same
903   constraint (but its unclear how such an assertion could ever
904   be true). In LDAP, there is one syntax (numericString) not two
905   (numericString with constraint, numericString without constraint).
906   This should be treated as numericString with non-empty constraint.
907   Note that while someone may have no ISDN number, there are no ISDN
908   numbers which are zero length.
909
910   In matching, spaces are ignored.
911
912 PrintableString
913   In ASN.1, Printable string is just a string of printable characters
914   and can be empty.  In X.500, semantics much like NumericString (see
915   serialNumber for a like example) excepting uses insignificant space
916   handling instead of ignore all spaces.  
917
918 IA5String
919   Basically same as PrintableString.  There are no examples in X.500,
920   but same logic applies.  So we require them to be non-empty as
921   well.
922
923 -------------------------------------------------------------------*/
924
925 static int
926 UTF8StringValidate(
927         Syntax *syntax,
928         struct berval *in )
929 {
930         ber_len_t count;
931         int len;
932         unsigned char *u = in->bv_val;
933
934         if( in->bv_len == 0 && syntax == slap_schema.si_syn_directoryString ) {
935                 /* directory strings cannot be empty */
936                 return LDAP_INVALID_SYNTAX;
937         }
938
939         for( count = in->bv_len; count > 0; count-=len, u+=len ) {
940                 /* get the length indicated by the first byte */
941                 len = LDAP_UTF8_CHARLEN2( u, len );
942
943                 /* very basic checks */
944                 switch( len ) {
945                         case 6:
946                                 if( (u[5] & 0xC0) != 0x80 ) {
947                                         return LDAP_INVALID_SYNTAX;
948                                 }
949                         case 5:
950                                 if( (u[4] & 0xC0) != 0x80 ) {
951                                         return LDAP_INVALID_SYNTAX;
952                                 }
953                         case 4:
954                                 if( (u[3] & 0xC0) != 0x80 ) {
955                                         return LDAP_INVALID_SYNTAX;
956                                 }
957                         case 3:
958                                 if( (u[2] & 0xC0 )!= 0x80 ) {
959                                         return LDAP_INVALID_SYNTAX;
960                                 }
961                         case 2:
962                                 if( (u[1] & 0xC0) != 0x80 ) {
963                                         return LDAP_INVALID_SYNTAX;
964                                 }
965                         case 1:
966                                 /* CHARLEN already validated it */
967                                 break;
968                         default:
969                                 return LDAP_INVALID_SYNTAX;
970                 }
971
972                 /* make sure len corresponds with the offset
973                         to the next character */
974                 if( LDAP_UTF8_OFFSET( u ) != len ) return LDAP_INVALID_SYNTAX;
975         }
976
977         if( count != 0 ) {
978                 return LDAP_INVALID_SYNTAX;
979         }
980
981         return LDAP_SUCCESS;
982 }
983
984 static int
985 UTF8StringNormalize(
986         slap_mask_t use,
987         Syntax *syntax,
988         MatchingRule *mr,
989         struct berval *val,
990         struct berval *normalized,
991         void *ctx )
992 {
993         struct berval tmp, nvalue;
994         int flags;
995         int i, wasspace;
996
997         if( val->bv_val == NULL ) {
998                 /* assume we're dealing with a syntax (e.g., UTF8String)
999                  * which allows empty strings
1000                  */
1001                 normalized->bv_len = 0;
1002                 normalized->bv_val = NULL;
1003                 return LDAP_SUCCESS;
1004         }
1005
1006         flags = (mr == slap_schema.si_mr_caseExactMatch)
1007                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1008         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1009                 ? LDAP_UTF8_APPROX : 0;
1010
1011         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1012         if( val == NULL ) {
1013                 return LDAP_OTHER;
1014         }
1015         
1016         /* collapse spaces (in place) */
1017         nvalue.bv_len = 0;
1018         nvalue.bv_val = tmp.bv_val;
1019
1020         wasspace=1; /* trim leading spaces */
1021         for( i=0; i<tmp.bv_len; i++) {
1022                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1023                         if( wasspace++ == 0 ) {
1024                                 /* trim repeated spaces */
1025                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1026                         }
1027                 } else {
1028                         wasspace = 0;
1029                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1030                 }
1031         }
1032
1033         if( nvalue.bv_len ) {
1034                 if( wasspace ) {
1035                         /* last character was a space, trim it */
1036                         --nvalue.bv_len;
1037                 }
1038                 nvalue.bv_val[nvalue.bv_len] = '\0';
1039
1040         } else {
1041                 /* string of all spaces is treated as one space */
1042                 nvalue.bv_val[0] = ' ';
1043                 nvalue.bv_val[1] = '\0';
1044                 nvalue.bv_len = 1;
1045         }
1046
1047         *normalized = nvalue;
1048         return LDAP_SUCCESS;
1049 }
1050
1051 #ifndef SLAP_NVALUES
1052
1053 #ifndef SLAPD_APPROX_OLDSINGLESTRING
1054 #if defined(SLAPD_APPROX_INITIALS)
1055 #define SLAPD_APPROX_DELIMITER "._ "
1056 #define SLAPD_APPROX_WORDLEN 2
1057 #else
1058 #define SLAPD_APPROX_DELIMITER " "
1059 #define SLAPD_APPROX_WORDLEN 1
1060 #endif
1061
1062 static int
1063 approxMatch(
1064         int *matchp,
1065         slap_mask_t flags,
1066         Syntax *syntax,
1067         MatchingRule *mr,
1068         struct berval *value,
1069         void *assertedValue )
1070 {
1071         struct berval *nval, *assertv;
1072         char *val, **values, **words, *c;
1073         int i, count, len, nextchunk=0, nextavail=0;
1074
1075         /* Yes, this is necessary */
1076         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX );
1077         if( nval == NULL ) {
1078                 *matchp = 1;
1079                 return LDAP_SUCCESS;
1080         }
1081
1082         /* Yes, this is necessary */
1083         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1084                 NULL, LDAP_UTF8_APPROX );
1085         if( assertv == NULL ) {
1086                 ber_bvfree( nval );
1087                 *matchp = 1;
1088                 return LDAP_SUCCESS;
1089         }
1090
1091         /* Isolate how many words there are */
1092         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1093                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1094                 if ( c == NULL ) break;
1095                 *c = '\0';
1096                 count++;
1097         }
1098
1099         /* Get a phonetic copy of each word */
1100         words = (char **)ch_malloc( count * sizeof(char *) );
1101         values = (char **)ch_malloc( count * sizeof(char *) );
1102         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1103                 words[i] = c;
1104                 values[i] = phonetic(c);
1105         }
1106
1107         /* Work through the asserted value's words, to see if at least some
1108            of the words are there, in the same order. */
1109         len = 0;
1110         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1111                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1112                 if( len == 0 ) {
1113                         nextchunk++;
1114                         continue;
1115                 }
1116 #if defined(SLAPD_APPROX_INITIALS)
1117                 else if( len == 1 ) {
1118                         /* Single letter words need to at least match one word's initial */
1119                         for( i=nextavail; i<count; i++ )
1120                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1121                                         nextavail=i+1;
1122                                         break;
1123                                 }
1124                 }
1125 #endif
1126                 else {
1127                         /* Isolate the next word in the asserted value and phonetic it */
1128                         assertv->bv_val[nextchunk+len] = '\0';
1129                         val = phonetic( assertv->bv_val + nextchunk );
1130
1131                         /* See if this phonetic chunk is in the remaining words of *value */
1132                         for( i=nextavail; i<count; i++ ){
1133                                 if( !strcmp( val, values[i] ) ){
1134                                         nextavail = i+1;
1135                                         break;
1136                                 }
1137                         }
1138                         ch_free( val );
1139                 }
1140
1141                 /* This chunk in the asserted value was NOT within the *value. */
1142                 if( i >= count ) {
1143                         nextavail=-1;
1144                         break;
1145                 }
1146
1147                 /* Go on to the next word in the asserted value */
1148                 nextchunk += len+1;
1149         }
1150
1151         /* If some of the words were seen, call it a match */
1152         if( nextavail > 0 ) {
1153                 *matchp = 0;
1154         }
1155         else {
1156                 *matchp = 1;
1157         }
1158
1159         /* Cleanup allocs */
1160         ber_bvfree( assertv );
1161         for( i=0; i<count; i++ ) {
1162                 ch_free( values[i] );
1163         }
1164         ch_free( values );
1165         ch_free( words );
1166         ber_bvfree( nval );
1167
1168         return LDAP_SUCCESS;
1169 }
1170
1171 static int 
1172 approxIndexer(
1173         slap_mask_t use,
1174         slap_mask_t flags,
1175         Syntax *syntax,
1176         MatchingRule *mr,
1177         struct berval *prefix,
1178         BerVarray values,
1179         BerVarray *keysp )
1180 {
1181         char *c;
1182         int i,j, len, wordcount, keycount=0;
1183         struct berval *newkeys;
1184         BerVarray keys=NULL;
1185
1186         for( j=0; values[j].bv_val != NULL; j++ ) {
1187                 struct berval val = { 0, NULL };
1188                 /* Yes, this is necessary */
1189                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX );
1190                 assert( val.bv_val != NULL );
1191
1192                 /* Isolate how many words there are. There will be a key for each */
1193                 for( wordcount = 0, c = val.bv_val; *c; c++) {
1194                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
1195                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1196                         c+= len;
1197                         if (*c == '\0') break;
1198                         *c = '\0';
1199                 }
1200
1201                 /* Allocate/increase storage to account for new keys */
1202                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
1203                         * sizeof(struct berval) );
1204                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1205                 if( keys ) ch_free( keys );
1206                 keys = newkeys;
1207
1208                 /* Get a phonetic copy of each word */
1209                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1210                         len = strlen( c );
1211                         if( len < SLAPD_APPROX_WORDLEN ) continue;
1212                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1213                         keycount++;
1214                         i++;
1215                 }
1216
1217                 ber_memfree( val.bv_val );
1218         }
1219         keys[keycount].bv_val = NULL;
1220         *keysp = keys;
1221
1222         return LDAP_SUCCESS;
1223 }
1224
1225 static int 
1226 approxFilter(
1227         slap_mask_t use,
1228         slap_mask_t flags,
1229         Syntax *syntax,
1230         MatchingRule *mr,
1231         struct berval *prefix,
1232         void * assertedValue,
1233         BerVarray *keysp )
1234 {
1235         char *c;
1236         int i, count, len;
1237         struct berval *val;
1238         BerVarray keys;
1239
1240         /* Yes, this is necessary */
1241         val = UTF8bvnormalize( ((struct berval *)assertedValue),
1242                 NULL, LDAP_UTF8_APPROX );
1243         if( val == NULL || val->bv_val == NULL ) {
1244                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1245                 keys[0].bv_val = NULL;
1246                 *keysp = keys;
1247                 ber_bvfree( val );
1248                 return LDAP_SUCCESS;
1249         }
1250
1251         /* Isolate how many words there are. There will be a key for each */
1252         for( count = 0,c = val->bv_val; *c; c++) {
1253                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1254                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1255                 c+= len;
1256                 if (*c == '\0') break;
1257                 *c = '\0';
1258         }
1259
1260         /* Allocate storage for new keys */
1261         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1262
1263         /* Get a phonetic copy of each word */
1264         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1265                 len = strlen(c);
1266                 if( len < SLAPD_APPROX_WORDLEN ) continue;
1267                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1268                 i++;
1269         }
1270
1271         ber_bvfree( val );
1272
1273         keys[count].bv_val = NULL;
1274         *keysp = keys;
1275
1276         return LDAP_SUCCESS;
1277 }
1278
1279 #else
1280 /* No other form of Approximate Matching is defined */
1281
1282 static int
1283 approxMatch(
1284         int *matchp,
1285         slap_mask_t flags,
1286         Syntax *syntax,
1287         MatchingRule *mr,
1288         struct berval *value,
1289         void *assertedValue )
1290 {
1291         char *vapprox, *avapprox;
1292         char *s, *t;
1293
1294         /* Yes, this is necessary */
1295         s = UTF8normalize( value, UTF8_NOCASEFOLD );
1296         if( s == NULL ) {
1297                 *matchp = 1;
1298                 return LDAP_SUCCESS;
1299         }
1300
1301         /* Yes, this is necessary */
1302         t = UTF8normalize( ((struct berval *)assertedValue),
1303                            UTF8_NOCASEFOLD );
1304         if( t == NULL ) {
1305                 free( s );
1306                 *matchp = -1;
1307                 return LDAP_SUCCESS;
1308         }
1309
1310         vapprox = phonetic( strip8bitChars( s ) );
1311         avapprox = phonetic( strip8bitChars( t ) );
1312
1313         free( s );
1314         free( t );
1315
1316         *matchp = strcmp( vapprox, avapprox );
1317
1318         ch_free( vapprox );
1319         ch_free( avapprox );
1320
1321         return LDAP_SUCCESS;
1322 }
1323
1324 static int 
1325 approxIndexer(
1326         slap_mask_t use,
1327         slap_mask_t flags,
1328         Syntax *syntax,
1329         MatchingRule *mr,
1330         struct berval *prefix,
1331         BerVarray values,
1332         BerVarray *keysp )
1333 {
1334         int i;
1335         BerVarray *keys;
1336         char *s;
1337
1338         for( i=0; values[i].bv_val != NULL; i++ ) {
1339                 /* empty - just count them */
1340         }
1341
1342         /* we should have at least one value at this point */
1343         assert( i > 0 );
1344
1345         keys = (struct berval *)ch_malloc( sizeof( struct berval ) * (i+1) );
1346
1347         /* Copy each value and run it through phonetic() */
1348         for( i=0; values[i].bv_val != NULL; i++ ) {
1349                 /* Yes, this is necessary */
1350                 s = UTF8normalize( &values[i], UTF8_NOCASEFOLD );
1351
1352                 /* strip 8-bit chars and run through phonetic() */
1353                 ber_str2bv( phonetic( strip8bitChars( s ) ), 0, 0, &keys[i] );
1354                 free( s );
1355         }
1356         keys[i].bv_val = NULL;
1357
1358         *keysp = keys;
1359         return LDAP_SUCCESS;
1360 }
1361
1362 static int 
1363 approxFilter(
1364         slap_mask_t use,
1365         slap_mask_t flags,
1366         Syntax *syntax,
1367         MatchingRule *mr,
1368         struct berval *prefix,
1369         void * assertedValue,
1370         BerVarray *keysp )
1371 {
1372         BerVarray keys;
1373         char *s;
1374
1375         keys = (struct berval *)ch_malloc( sizeof( struct berval * ) * 2 );
1376
1377         /* Yes, this is necessary */
1378         s = UTF8normalize( ((struct berval *)assertedValue),
1379                              UTF8_NOCASEFOLD );
1380         if( s == NULL ) {
1381                 keys[0] = NULL;
1382         } else {
1383                 /* strip 8-bit chars and run through phonetic() */
1384                 keys[0] = ber_bvstr( phonetic( strip8bitChars( s ) ) );
1385                 free( s );
1386                 keys[1] = NULL;
1387         }
1388
1389         *keysp = keys;
1390         return LDAP_SUCCESS;
1391 }
1392 #endif
1393 #endif /* !SLAP_NVALUES */
1394
1395 /* Remove all spaces and '-' characters */
1396 static int
1397 telephoneNumberNormalize(
1398         slap_mask_t usage,
1399         Syntax *syntax,
1400         MatchingRule *mr,
1401         struct berval *val,
1402         struct berval *normalized,
1403         void *ctx )
1404 {
1405         char *p, *q;
1406
1407         /* validator should have refused an empty string */
1408         assert( val->bv_len );
1409
1410         q = normalized->bv_val = sl_malloc( val->bv_len + 1, ctx );
1411
1412         for( p = val->bv_val; *p; p++ ) {
1413                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1414                         *q++ = *p;
1415                 }
1416         }
1417         *q = '\0';
1418
1419         normalized->bv_len = q - normalized->bv_val;
1420
1421         if( normalized->bv_len == 0 ) {
1422                 sl_free( normalized->bv_val, ctx );
1423                 return LDAP_INVALID_SYNTAX;
1424         }
1425
1426         return LDAP_SUCCESS;
1427 }
1428
1429 static int
1430 oidValidate(
1431         Syntax *syntax,
1432         struct berval *val )
1433 {
1434         ber_len_t i;
1435
1436         if( val->bv_len == 0 ) {
1437                 /* disallow empty strings */
1438                 return LDAP_INVALID_SYNTAX;
1439         }
1440
1441         if( OID_LEADCHAR(val->bv_val[0]) ) {
1442                 int dot = 0;
1443                 for(i=1; i < val->bv_len; i++) {
1444                         if( OID_SEPARATOR( val->bv_val[i] ) ) {
1445                                 if( dot++ ) return 1;
1446                         } else if ( OID_CHAR( val->bv_val[i] ) ) {
1447                                 dot = 0;
1448                         } else {
1449                                 return LDAP_INVALID_SYNTAX;
1450                         }
1451                 }
1452
1453                 return !dot ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
1454
1455         } else if( DESC_LEADCHAR(val->bv_val[0]) ) {
1456                 for(i=1; i < val->bv_len; i++) {
1457                         if( !DESC_CHAR(val->bv_val[i] ) ) {
1458                                 return LDAP_INVALID_SYNTAX;
1459                         }
1460                 }
1461
1462                 return LDAP_SUCCESS;
1463         }
1464         
1465         return LDAP_INVALID_SYNTAX;
1466 }
1467
1468 static int
1469 integerMatch(
1470         int *matchp,
1471         slap_mask_t flags,
1472         Syntax *syntax,
1473         MatchingRule *mr,
1474         struct berval *value,
1475         void *assertedValue )
1476 {
1477         char *v, *av;
1478         int vsign = 1, avsign = 1;      /* default sign = '+' */
1479         struct berval *asserted;
1480         ber_len_t vlen, avlen;
1481         int match;
1482
1483         /* Skip leading space/sign/zeroes, and get the sign of the *value number */
1484         v = value->bv_val;
1485         vlen = value->bv_len;
1486
1487 #ifndef SLAP_NVALUES
1488         if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
1489                 char *tmp = memchr( v, '$', vlen );
1490                 if( tmp ) vlen = tmp - v;
1491                 while( vlen && ASCII_SPACE( v[vlen-1] )) vlen--;
1492         }
1493 #endif
1494
1495         for( ; vlen && ( *v < '1' || '9' < *v ); v++, vlen-- ) { /* ANSI 2.2.1 */
1496                 if( *v == '-' ) vsign = -1;
1497         }
1498
1499         if( vlen == 0 ) vsign = 0;
1500
1501         /* Do the same with the *assertedValue number */
1502         asserted = (struct berval *) assertedValue;
1503         av = asserted->bv_val;
1504         avlen = asserted->bv_len;
1505         for( ; avlen && ( *av < '1' || '9' < *av ); av++, avlen-- )
1506                 if( *av == '-' )
1507                         avsign = -1;
1508         if( avlen == 0 )
1509                 avsign = 0;
1510
1511         match = vsign - avsign;
1512         if( match == 0 ) {
1513                 match = (vlen != avlen
1514                         ? ( vlen < avlen ? -1 : 1 )
1515                         : memcmp( v, av, vlen ));
1516                 if( vsign < 0 ) match = -match;
1517         }
1518
1519         *matchp = match;
1520         return LDAP_SUCCESS;
1521 }
1522         
1523 static int
1524 integerValidate(
1525         Syntax *syntax,
1526         struct berval *val )
1527 {
1528         ber_len_t i;
1529
1530         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
1531
1532         if(( val->bv_val[0] == '+' ) || ( val->bv_val[0] == '-' )) {
1533                 if( val->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
1534
1535         } else if( !ASCII_DIGIT(val->bv_val[0]) ) {
1536                 return LDAP_INVALID_SYNTAX;
1537         }
1538
1539         for( i=1; i < val->bv_len; i++ ) {
1540                 if( !ASCII_DIGIT(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
1541         }
1542
1543         return LDAP_SUCCESS;
1544 }
1545
1546 static int
1547 integerNormalize(
1548         slap_mask_t use,
1549         Syntax *syntax,
1550         MatchingRule *mr,
1551         struct berval *val,
1552         struct berval *normalized,
1553         void *ctx )
1554 {
1555         char *p;
1556         int negative=0;
1557         ber_len_t len;
1558
1559         p = val->bv_val;
1560         len = val->bv_len;
1561
1562         /* Ignore leading spaces */
1563         while ( len && ( *p == ' ' )) {
1564                 p++;
1565                 len--;
1566         }
1567
1568         /* save sign */
1569         if( len ) {
1570                 negative = ( *p == '-' );
1571                 if(( *p == '-' ) || ( *p == '+' )) {
1572                         p++;
1573                         len--;
1574                 }
1575         }
1576
1577         /* Ignore leading zeros */
1578         while ( len && ( *p == '0' )) {
1579                 p++;
1580                 len--;
1581         }
1582
1583         /* If there are no non-zero digits left, the number is zero, otherwise
1584            allocate space for the number and copy it into the buffer */
1585         if( len == 0 ) {
1586                 normalized->bv_val = ber_strdup_x("0", ctx);
1587                 normalized->bv_len = 1;
1588
1589         } else {
1590                 normalized->bv_len = len+negative;
1591                 normalized->bv_val = sl_malloc( normalized->bv_len + 1, ctx );
1592                 if( negative ) normalized->bv_val[0] = '-';
1593                 AC_MEMCPY( normalized->bv_val + negative, p, len );
1594                 normalized->bv_val[len+negative] = '\0';
1595         }
1596
1597         return LDAP_SUCCESS;
1598 }
1599
1600 static int
1601 countryStringValidate(
1602         Syntax *syntax,
1603         struct berval *val )
1604 {
1605         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
1606
1607         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
1608                 return LDAP_INVALID_SYNTAX;
1609         }
1610         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
1611                 return LDAP_INVALID_SYNTAX;
1612         }
1613
1614         return LDAP_SUCCESS;
1615 }
1616
1617 static int
1618 printableStringValidate(
1619         Syntax *syntax,
1620         struct berval *val )
1621 {
1622         ber_len_t i;
1623
1624         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1625
1626         for(i=0; i < val->bv_len; i++) {
1627                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
1628                         return LDAP_INVALID_SYNTAX;
1629                 }
1630         }
1631
1632         return LDAP_SUCCESS;
1633 }
1634
1635 static int
1636 printablesStringValidate(
1637         Syntax *syntax,
1638         struct berval *val )
1639 {
1640         ber_len_t i, len;
1641
1642         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1643
1644         for(i=0,len=0; i < val->bv_len; i++) {
1645                 int c = val->bv_val[i];
1646
1647                 if( c == '$' ) {
1648                         if( len == 0 ) {
1649                                 return LDAP_INVALID_SYNTAX;
1650                         }
1651                         len = 0;
1652
1653                 } else if ( SLAP_PRINTABLE(c) ) {
1654                         len++;
1655                 } else {
1656                         return LDAP_INVALID_SYNTAX;
1657                 }
1658         }
1659
1660         if( len == 0 ) {
1661                 return LDAP_INVALID_SYNTAX;
1662         }
1663
1664         return LDAP_SUCCESS;
1665 }
1666
1667 static int
1668 IA5StringValidate(
1669         Syntax *syntax,
1670         struct berval *val )
1671 {
1672         ber_len_t i;
1673
1674         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1675
1676         for(i=0; i < val->bv_len; i++) {
1677                 if( !LDAP_ASCII(val->bv_val[i]) ) {
1678                         return LDAP_INVALID_SYNTAX;
1679                 }
1680         }
1681
1682         return LDAP_SUCCESS;
1683 }
1684
1685 static int
1686 IA5StringNormalize(
1687         slap_mask_t use,
1688         Syntax *syntax,
1689         MatchingRule *mr,
1690         struct berval *val,
1691         struct berval *normalized,
1692         void *ctx )
1693 {
1694         char *p, *q;
1695         int casefold = (mr != slap_schema.si_mr_caseExactIA5Match);
1696
1697         assert( val->bv_len );
1698
1699         p = val->bv_val;
1700
1701         /* Ignore initial whitespace */
1702         while ( ASCII_SPACE( *p ) ) {
1703                 p++;
1704         }
1705
1706         normalized->bv_val = ber_strdup_x( p, ctx );
1707         p = q = normalized->bv_val;
1708
1709         while ( *p ) {
1710                 if ( ASCII_SPACE( *p ) ) {
1711                         *q++ = *p++;
1712
1713                         /* Ignore the extra whitespace */
1714                         while ( ASCII_SPACE( *p ) ) {
1715                                 p++;
1716                         }
1717
1718                 } else if ( casefold ) {
1719                         /* Most IA5 rules require casefolding */
1720                         *q++ = TOLOWER(*p++);
1721
1722                 } else {
1723                         *q++ = *p++;
1724                 }
1725         }
1726
1727         assert( normalized->bv_val <= p );
1728         assert( q <= p );
1729
1730         /*
1731          * If the string ended in space, backup the pointer one
1732          * position.  One is enough because the above loop collapsed
1733          * all whitespace to a single space.
1734          */
1735
1736         if ( ASCII_SPACE( q[-1] ) ) {
1737                 --q;
1738         }
1739
1740         /* null terminate */
1741         *q = '\0';
1742
1743         normalized->bv_len = q - normalized->bv_val;
1744
1745         if( normalized->bv_len == 0 ) {
1746                 normalized->bv_val = sl_realloc( normalized->bv_val, 2, ctx );
1747                 normalized->bv_val[0] = ' ';
1748                 normalized->bv_val[1] = '\0';
1749                 normalized->bv_len = 1;
1750         }
1751
1752         return LDAP_SUCCESS;
1753 }
1754
1755 static int
1756 numericStringValidate(
1757         Syntax *syntax,
1758         struct berval *in )
1759 {
1760         ber_len_t i;
1761
1762         if( in->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1763
1764         for(i=0; i < in->bv_len; i++) {
1765                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
1766                         return LDAP_INVALID_SYNTAX;
1767                 }
1768         }
1769
1770         return LDAP_SUCCESS;
1771 }
1772
1773 static int
1774 numericStringNormalize(
1775         slap_mask_t usage,
1776         Syntax *syntax,
1777         MatchingRule *mr,
1778         struct berval *val,
1779         struct berval *normalized,
1780         void *ctx )
1781 {
1782         /* removal all spaces */
1783         char *p, *q;
1784
1785         assert( val->bv_len );
1786
1787         normalized->bv_val = sl_malloc( val->bv_len + 1, ctx );
1788
1789         p = val->bv_val;
1790         q = normalized->bv_val;
1791
1792         while ( *p ) {
1793                 if ( ASCII_SPACE( *p ) ) {
1794                         /* Ignore whitespace */
1795                         p++;
1796                 } else {
1797                         *q++ = *p++;
1798                 }
1799         }
1800
1801         /* we should have copied no more then is in val */
1802         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
1803
1804         /* null terminate */
1805         *q = '\0';
1806
1807         normalized->bv_len = q - normalized->bv_val;
1808
1809         if( normalized->bv_len == 0 ) {
1810                 normalized->bv_val = sl_realloc( normalized->bv_val, 2, ctx );
1811                 normalized->bv_val[0] = ' ';
1812                 normalized->bv_val[1] = '\0';
1813                 normalized->bv_len = 1;
1814         }
1815
1816         return LDAP_SUCCESS;
1817 }
1818
1819 #ifndef SLAP_NVALUES
1820 static int
1821 objectIdentifierFirstComponentMatch(
1822         int *matchp,
1823         slap_mask_t flags,
1824         Syntax *syntax,
1825         MatchingRule *mr,
1826         struct berval *value,
1827         void *assertedValue )
1828 {
1829         int rc = LDAP_SUCCESS;
1830         int match;
1831         struct berval *asserted = (struct berval *) assertedValue;
1832         ber_len_t i, j;
1833         struct berval oid;
1834
1835         if( value->bv_len == 0 || value->bv_val[0] != '(' /*')'*/ ) {
1836                 return LDAP_INVALID_SYNTAX;
1837         }
1838
1839         /* trim leading white space */
1840         for( i=1; ASCII_SPACE(value->bv_val[i]) && i < value->bv_len; i++ ) {
1841                 /* empty */
1842         }
1843
1844         /* grab next word */
1845         oid.bv_val = &value->bv_val[i];
1846         j = value->bv_len - i;
1847         for( i=0; !ASCII_SPACE(oid.bv_val[i]) && i < j; i++ ) {
1848                 /* empty */
1849         }
1850         oid.bv_len = i;
1851
1852         /* insert attributeTypes, objectclass check here */
1853         if( OID_LEADCHAR(asserted->bv_val[0]) ) {
1854                 rc = objectIdentifierMatch( &match, flags, syntax, mr, &oid, asserted );
1855
1856         } else {
1857                 if ( !strcmp( syntax->ssyn_oid, SLAP_SYNTAX_MATCHINGRULES_OID ) ) {
1858                         MatchingRule *asserted_mr = mr_bvfind( asserted );
1859                         MatchingRule *stored_mr = mr_bvfind( &oid );
1860
1861                         if( asserted_mr == NULL ) {
1862                                 rc = SLAPD_COMPARE_UNDEFINED;
1863                         } else {
1864                                 match = asserted_mr != stored_mr;
1865                         }
1866
1867                 } else if ( !strcmp( syntax->ssyn_oid,
1868                         SLAP_SYNTAX_ATTRIBUTETYPES_OID ) )
1869                 {
1870                         AttributeType *asserted_at = at_bvfind( asserted );
1871                         AttributeType *stored_at = at_bvfind( &oid );
1872
1873                         if( asserted_at == NULL ) {
1874                                 rc = SLAPD_COMPARE_UNDEFINED;
1875                         } else {
1876                                 match = asserted_at != stored_at;
1877                         }
1878
1879                 } else if ( !strcmp( syntax->ssyn_oid,
1880                         SLAP_SYNTAX_OBJECTCLASSES_OID ) )
1881                 {
1882                         ObjectClass *asserted_oc = oc_bvfind( asserted );
1883                         ObjectClass *stored_oc = oc_bvfind( &oid );
1884
1885                         if( asserted_oc == NULL ) {
1886                                 rc = SLAPD_COMPARE_UNDEFINED;
1887                         } else {
1888                                 match = asserted_oc != stored_oc;
1889                         }
1890                 }
1891         }
1892
1893 #ifdef NEW_LOGGING
1894         LDAP_LOG( CONFIG, ENTRY, 
1895                 "objectIdentifierFirstComponentMatch: %d\n %s\n %s\n",
1896                 match, value->bv_val, asserted->bv_val );
1897 #else
1898         Debug( LDAP_DEBUG_ARGS, "objectIdentifierFirstComponentMatch "
1899                 "%d\n\t\"%s\"\n\t\"%s\"\n",
1900                 match, value->bv_val, asserted->bv_val );
1901 #endif
1902
1903         if( rc == LDAP_SUCCESS ) *matchp = match;
1904         return rc;
1905 }
1906 #endif
1907
1908 static int
1909 integerBitAndMatch(
1910         int *matchp,
1911         slap_mask_t flags,
1912         Syntax *syntax,
1913         MatchingRule *mr,
1914         struct berval *value,
1915         void *assertedValue )
1916 {
1917         long lValue, lAssertedValue;
1918
1919         /* safe to assume integers are NUL terminated? */
1920         lValue = strtol(value->bv_val, NULL, 10);
1921         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
1922                 return LDAP_CONSTRAINT_VIOLATION;
1923         }
1924
1925         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
1926         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
1927                 && errno == ERANGE )
1928         {
1929                 return LDAP_CONSTRAINT_VIOLATION;
1930         }
1931
1932         *matchp = (lValue & lAssertedValue) ? 0 : 1;
1933         return LDAP_SUCCESS;
1934 }
1935
1936 static int
1937 integerBitOrMatch(
1938         int *matchp,
1939         slap_mask_t flags,
1940         Syntax *syntax,
1941         MatchingRule *mr,
1942         struct berval *value,
1943         void *assertedValue )
1944 {
1945         long lValue, lAssertedValue;
1946
1947         /* safe to assume integers are NUL terminated? */
1948         lValue = strtol(value->bv_val, NULL, 10);
1949         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
1950                 return LDAP_CONSTRAINT_VIOLATION;
1951         }
1952
1953         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
1954         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
1955                 && errno == ERANGE )
1956         {
1957                 return LDAP_CONSTRAINT_VIOLATION;
1958         }
1959
1960         *matchp = (lValue | lAssertedValue) ? 0 : -1;
1961         return LDAP_SUCCESS;
1962 }
1963
1964 #ifndef SLAP_NVALUES
1965 #ifdef HAVE_TLS
1966 #include <openssl/x509.h>
1967 #include <openssl/err.h>
1968
1969 /*
1970  * Next function returns a string representation of a ASN1_INTEGER.
1971  * It works for unlimited lengths.
1972  */
1973
1974 static struct berval *
1975 asn1_integer2str(ASN1_INTEGER *a, struct berval *bv)
1976 {
1977         char buf[256];
1978         char *p;
1979         static char digit[] = "0123456789";
1980   
1981         /* We work backwards, make it fill from the end of buf */
1982         p = buf + sizeof(buf) - 1;
1983         *p = '\0';
1984
1985         if ( a == NULL || a->length == 0 ) {
1986                 *--p = '0';
1987         } else {
1988                 int i;
1989                 int n = a->length;
1990                 int base = 0;
1991                 unsigned int *copy;
1992
1993                 /* We want to preserve the original */
1994                 copy = ch_malloc(n*sizeof(unsigned int));
1995                 for (i = 0; i<n; i++) {
1996                         copy[i] = a->data[i];
1997                 }
1998
1999                 /* 
2000                  * base indicates the index of the most significant
2001                  * byte that might be nonzero.  When it goes off the
2002                  * end, we now there is nothing left to do.
2003                  */
2004                 while (base < n) {
2005                         unsigned int carry;
2006
2007                         carry = 0;
2008                         for (i = base; i<n; i++ ) {
2009                                 copy[i] += carry*256;
2010                                 carry = copy[i] % 10;
2011                                 copy[i] /= 10;
2012                         }
2013                         if (p <= buf+1) {
2014                                 /*
2015                                  * Way too large, we need to leave
2016                                  * room for sign if negative
2017                                  */
2018                                 free(copy);
2019                                 return NULL;
2020                         }
2021                         *--p = digit[carry];
2022
2023                         if (copy[base] == 0) base++;
2024                 }
2025                 free(copy);
2026         }
2027
2028         if ( a->type == V_ASN1_NEG_INTEGER ) {
2029                 *--p = '-';
2030         }
2031
2032         return ber_str2bv( p, 0, 1, bv );
2033 }
2034
2035 /*
2036  * Given a certificate in DER format, extract the corresponding
2037  * assertion value for certificateExactMatch
2038  */
2039 static int
2040 certificateExactConvert(
2041         struct berval * in,
2042         struct berval * out )
2043 {
2044         X509 *xcert;
2045         unsigned char *p = in->bv_val;
2046         struct berval serial;
2047         struct berval issuer_dn;
2048
2049         xcert = d2i_X509(NULL, &p, in->bv_len);
2050         if ( !xcert ) {
2051 #ifdef NEW_LOGGING
2052                 LDAP_LOG( CONFIG, ENTRY, 
2053                         "certificateExactConvert: error parsing cert: %s\n",
2054                         ERR_error_string(ERR_get_error(),NULL), 0, 0 );
2055 #else
2056                 Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: "
2057                        "error parsing cert: %s\n",
2058                        ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
2059 #endif
2060                 return LDAP_INVALID_SYNTAX;
2061         }
2062
2063         if ( !asn1_integer2str(xcert->cert_info->serialNumber, &serial) ) {
2064                 X509_free(xcert);
2065                 return LDAP_INVALID_SYNTAX;
2066         }
2067         if ( dnX509normalize(X509_get_issuer_name(xcert), &issuer_dn )
2068                 != LDAP_SUCCESS )
2069         {
2070                 X509_free(xcert);
2071                 ber_memfree(serial.bv_val);
2072                 return LDAP_INVALID_SYNTAX;
2073         }
2074
2075         X509_free(xcert);
2076
2077         out->bv_len = serial.bv_len + issuer_dn.bv_len + sizeof(" $ ");
2078         out->bv_val = ch_malloc(out->bv_len);
2079         p = out->bv_val;
2080         AC_MEMCPY(p, serial.bv_val, serial.bv_len);
2081         p += serial.bv_len;
2082         AC_MEMCPY(p, " $ ", sizeof(" $ ")-1);
2083         p += 3;
2084         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2085         p += issuer_dn.bv_len;
2086         *p++ = '\0';
2087
2088 #ifdef NEW_LOGGING
2089         LDAP_LOG( CONFIG, ARGS, 
2090                 "certificateExactConvert: \n    %s\n", out->bv_val, 0, 0 );
2091 #else
2092         Debug( LDAP_DEBUG_ARGS, "certificateExactConvert "
2093                 "\n\t\"%s\"\n",
2094                 out->bv_val, NULL, NULL );
2095 #endif
2096
2097         ber_memfree(serial.bv_val);
2098         ber_memfree(issuer_dn.bv_val);
2099
2100         return LDAP_SUCCESS;
2101 }
2102
2103 static int
2104 serial_and_issuer_parse(
2105         struct berval *assertion,
2106         struct berval *serial,
2107         struct berval *issuer_dn )
2108 {
2109         char *begin;
2110         char *end;
2111         char *p;
2112         struct berval bv;
2113
2114         begin = assertion->bv_val;
2115         end = assertion->bv_val+assertion->bv_len-1;
2116         for (p=begin; p<=end && *p != '$'; p++) /* empty */ ;
2117         if ( p > end ) return LDAP_INVALID_SYNTAX;
2118
2119         /* p now points at the $ sign, now use
2120          * begin and end to delimit the serial number
2121          */
2122         while (ASCII_SPACE(*begin)) begin++;
2123         end = p-1;
2124         while (ASCII_SPACE(*end)) end--;
2125
2126         if( end <= begin ) return LDAP_INVALID_SYNTAX;
2127
2128         bv.bv_len = end-begin+1;
2129         bv.bv_val = begin;
2130         ber_dupbv(serial, &bv);
2131
2132         /* now extract the issuer, remember p was at the dollar sign */
2133         begin = p+1;
2134         end = assertion->bv_val+assertion->bv_len-1;
2135         while (ASCII_SPACE(*begin)) begin++;
2136         /* should we trim spaces at the end too? is it safe always? no, no */
2137
2138         if( end <= begin ) return LDAP_INVALID_SYNTAX;
2139
2140         if ( issuer_dn ) {
2141                 bv.bv_len = end-begin+1;
2142                 bv.bv_val = begin;
2143
2144                 dnNormalize2( NULL, &bv, issuer_dn );
2145         }
2146
2147         return LDAP_SUCCESS;
2148 }
2149
2150 static int
2151 certificateExactMatch(
2152         int *matchp,
2153         slap_mask_t flags,
2154         Syntax *syntax,
2155         MatchingRule *mr,
2156         struct berval *value,
2157         void *assertedValue )
2158 {
2159         X509 *xcert;
2160         unsigned char *p = value->bv_val;
2161         struct berval serial;
2162         struct berval issuer_dn;
2163         struct berval asserted_serial;
2164         struct berval asserted_issuer_dn;
2165         int ret;
2166
2167         xcert = d2i_X509(NULL, &p, value->bv_len);
2168         if ( !xcert ) {
2169 #ifdef NEW_LOGGING
2170                 LDAP_LOG( CONFIG, ENTRY, 
2171                         "certificateExactMatch: error parsing cert: %s\n",
2172                         ERR_error_string(ERR_get_error(),NULL), 0, 0 );
2173 #else
2174                 Debug( LDAP_DEBUG_ARGS, "certificateExactMatch: "
2175                        "error parsing cert: %s\n",
2176                        ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
2177 #endif
2178                 return LDAP_INVALID_SYNTAX;
2179         }
2180
2181         asn1_integer2str(xcert->cert_info->serialNumber, &serial);
2182         dnX509normalize(X509_get_issuer_name(xcert), &issuer_dn);
2183
2184         X509_free(xcert);
2185
2186         serial_and_issuer_parse(assertedValue,
2187                 &asserted_serial, &asserted_issuer_dn);
2188
2189         ret = integerMatch(
2190                 matchp,
2191                 flags,
2192                 slap_schema.si_syn_integer,
2193                 slap_schema.si_mr_integerMatch,
2194                 &serial,
2195                 &asserted_serial);
2196         if ( ret == LDAP_SUCCESS ) {
2197                 if ( *matchp == 0 ) {
2198                         /* We need to normalize everything for dnMatch */
2199                         ret = dnMatch(
2200                                 matchp,
2201                                 flags,
2202                                 slap_schema.si_syn_distinguishedName,
2203                                 slap_schema.si_mr_distinguishedNameMatch,
2204                                 &issuer_dn,
2205                                 &asserted_issuer_dn);
2206                 }
2207         }
2208
2209 #ifdef NEW_LOGGING
2210         LDAP_LOG( CONFIG, ARGS, "certificateExactMatch "
2211                 "%d\n\t\"%s $ %s\"\n",
2212                 *matchp, serial.bv_val, issuer_dn.bv_val );
2213         LDAP_LOG( CONFIG, ARGS, "\t\"%s $ %s\"\n",
2214                 asserted_serial.bv_val, asserted_issuer_dn.bv_val,
2215                 0 );
2216 #else
2217         Debug( LDAP_DEBUG_ARGS, "certificateExactMatch "
2218                 "%d\n\t\"%s $ %s\"\n",
2219                 *matchp, serial.bv_val, issuer_dn.bv_val );
2220         Debug( LDAP_DEBUG_ARGS, "\t\"%s $ %s\"\n",
2221                 asserted_serial.bv_val, asserted_issuer_dn.bv_val,
2222                 NULL );
2223 #endif
2224
2225         ber_memfree(serial.bv_val);
2226         ber_memfree(issuer_dn.bv_val);
2227         ber_memfree(asserted_serial.bv_val);
2228         ber_memfree(asserted_issuer_dn.bv_val);
2229
2230         return ret;
2231 }
2232
2233 /* 
2234  * Index generation function
2235  * We just index the serials, in most scenarios the issuer DN is one of
2236  * a very small set of values.
2237  */
2238 static int certificateExactIndexer(
2239         slap_mask_t use,
2240         slap_mask_t flags,
2241         Syntax *syntax,
2242         MatchingRule *mr,
2243         struct berval *prefix,
2244         BerVarray values,
2245         BerVarray *keysp )
2246 {
2247         int i;
2248         BerVarray keys;
2249         X509 *xcert;
2250         unsigned char *p;
2251         struct berval serial;
2252
2253         /* we should have at least one value at this point */
2254         assert( values != NULL && values[0].bv_val != NULL );
2255
2256         for( i=0; values[i].bv_val != NULL; i++ ) {
2257                 /* empty -- just count them */
2258         }
2259
2260         keys = ch_malloc( sizeof( struct berval ) * (i+1) );
2261
2262         for( i=0; values[i].bv_val != NULL; i++ ) {
2263                 p = values[i].bv_val;
2264                 xcert = d2i_X509(NULL, &p, values[i].bv_len);
2265                 if ( !xcert ) {
2266 #ifdef NEW_LOGGING
2267                         LDAP_LOG( CONFIG, ENTRY, 
2268                                 "certificateExactIndexer: error parsing cert: %s\n",
2269                                 ERR_error_string(ERR_get_error(),NULL), 0, 0);
2270 #else
2271                         Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
2272                                "error parsing cert: %s\n",
2273                                ERR_error_string(ERR_get_error(),NULL),
2274                                NULL, NULL );
2275 #endif
2276                         /* Do we leak keys on error? */
2277                         return LDAP_INVALID_SYNTAX;
2278                 }
2279
2280                 asn1_integer2str(xcert->cert_info->serialNumber, &serial);
2281                 X509_free(xcert);
2282                 xintegerNormalize( slap_schema.si_syn_integer,
2283                         &serial, &keys[i] );
2284                 ber_memfree(serial.bv_val);
2285 #ifdef NEW_LOGGING
2286                 LDAP_LOG( CONFIG, ENTRY, 
2287                         "certificateExactIndexer: returning: %s\n", keys[i].bv_val, 0, 0);
2288 #else
2289                 Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
2290                        "returning: %s\n",
2291                        keys[i].bv_val,
2292                        NULL, NULL );
2293 #endif
2294         }
2295
2296         keys[i].bv_val = NULL;
2297         *keysp = keys;
2298         return LDAP_SUCCESS;
2299 }
2300
2301 /* Index generation function */
2302 /* We think this is always called with a value in matching rule syntax */
2303 static int certificateExactFilter(
2304         slap_mask_t use,
2305         slap_mask_t flags,
2306         Syntax *syntax,
2307         MatchingRule *mr,
2308         struct berval *prefix,
2309         void * assertedValue,
2310         BerVarray *keysp )
2311 {
2312         BerVarray keys;
2313         struct berval asserted_serial;
2314         int ret;
2315
2316         ret = serial_and_issuer_parse( assertedValue, &asserted_serial, NULL );
2317         if( ret != LDAP_SUCCESS ) return ret;
2318
2319         keys = ch_malloc( sizeof( struct berval ) * 2 );
2320         xintegerNormalize( syntax, &asserted_serial, &keys[0] );
2321         keys[1].bv_val = NULL;
2322         *keysp = keys;
2323
2324         ber_memfree(asserted_serial.bv_val);
2325         return LDAP_SUCCESS;
2326 }
2327 #endif
2328 #endif
2329
2330 static int
2331 check_time_syntax (struct berval *val,
2332         int start,
2333         int *parts)
2334 {
2335         static int ceiling[9] = { 99, 99, 11, 30, 23, 59, 59, 12, 59 };
2336         static int mdays[2][12] = {
2337                 /* non-leap years */
2338                 { 30, 27, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 },
2339                 /* leap years */
2340                 { 30, 28, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 }
2341         };
2342         char *p, *e;
2343         int part, c, tzoffset, leapyear = 0 ;
2344
2345         if( val->bv_len == 0 ) {
2346                 return LDAP_INVALID_SYNTAX;
2347         }
2348
2349         p = (char *)val->bv_val;
2350         e = p + val->bv_len;
2351
2352         /* Ignore initial whitespace */
2353         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
2354                 p++;
2355         }
2356
2357         if (e - p < 13 - (2 * start)) {
2358                 return LDAP_INVALID_SYNTAX;
2359         }
2360
2361         for (part = 0; part < 9; part++) {
2362                 parts[part] = 0;
2363         }
2364
2365         for (part = start; part < 7; part++) {
2366                 c = *p;
2367                 if ((part == 6) && (c == 'Z' || c == '+' || c == '-')) {
2368                         part++;
2369                         break;
2370                 }
2371                 p++;
2372                 c -= '0';
2373                 if (p == e) {
2374                         return LDAP_INVALID_SYNTAX;
2375                 }
2376                 if (c < 0 || c > 9) {
2377                         return LDAP_INVALID_SYNTAX;
2378                 }
2379                 parts[part] = c;
2380
2381                 c = *p++ - '0';
2382                 if (p == e) {
2383                         return LDAP_INVALID_SYNTAX;
2384                 }
2385                 if (c < 0 || c > 9) {
2386                         return LDAP_INVALID_SYNTAX;
2387                 }
2388                 parts[part] *= 10;
2389                 parts[part] += c;
2390
2391                 if (part == 2 || part == 3) {
2392                         parts[part]--;
2393                 }
2394                 if (parts[part] < 0) {
2395                         return LDAP_INVALID_SYNTAX;
2396                 }
2397                 if (parts[part] > ceiling[part]) {
2398                         return LDAP_INVALID_SYNTAX;
2399                 }
2400         }
2401
2402         /* leapyear check for the Gregorian calendar (year>1581) */
2403         if (((parts[1] % 4 == 0) && (parts[1] != 0)) ||
2404                 ((parts[0] % 4 == 0) && (parts[1] == 0)))
2405         {
2406                 leapyear = 1;
2407         }
2408
2409         if (parts[3] > mdays[leapyear][parts[2]]) {
2410                 return LDAP_INVALID_SYNTAX;
2411         }
2412         
2413         c = *p++;
2414         if (c == 'Z') {
2415                 tzoffset = 0; /* UTC */
2416         } else if (c != '+' && c != '-') {
2417                 return LDAP_INVALID_SYNTAX;
2418         } else {
2419                 if (c == '-') {
2420                         tzoffset = -1;
2421                 } else /* c == '+' */ {
2422                         tzoffset = 1;
2423                 }
2424
2425                 if (p > e - 4) {
2426                         return LDAP_INVALID_SYNTAX;
2427                 }
2428
2429                 for (part = 7; part < 9; part++) {
2430                         c = *p++ - '0';
2431                         if (c < 0 || c > 9) {
2432                                 return LDAP_INVALID_SYNTAX;
2433                         }
2434                         parts[part] = c;
2435
2436                         c = *p++ - '0';
2437                         if (c < 0 || c > 9) {
2438                                 return LDAP_INVALID_SYNTAX;
2439                         }
2440                         parts[part] *= 10;
2441                         parts[part] += c;
2442                         if (parts[part] < 0 || parts[part] > ceiling[part]) {
2443                                 return LDAP_INVALID_SYNTAX;
2444                         }
2445                 }
2446         }
2447
2448         /* Ignore trailing whitespace */
2449         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
2450                 p++;
2451         }
2452         if (p != e) {
2453                 return LDAP_INVALID_SYNTAX;
2454         }
2455
2456         switch ( tzoffset ) {
2457         case -1: /* negativ offset to UTC, ie west of Greenwich  */
2458                 parts[4] += parts[7];
2459                 parts[5] += parts[8];
2460                 for (part = 6; --part > 0; ) { /* offset is just hhmm, no seconds */
2461                         if (part != 3) {
2462                                 c = ceiling[part];
2463                         } else {
2464                                 c = mdays[leapyear][parts[2]];
2465                         }
2466                         if (parts[part] > c) {
2467                                 parts[part] -= c + 1;
2468                                 parts[part - 1]++;
2469                         }
2470                 }
2471                 break;
2472         case 1: /* positive offset to UTC, ie east of Greenwich */
2473                 parts[4] -= parts[7];
2474                 parts[5] -= parts[8];
2475                 for (part = 6; --part > 0; ) {
2476                         if (part != 3) {
2477                                 c = ceiling[part];
2478                         } else {
2479                                 /* first arg to % needs to be non negativ */
2480                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2481                         }
2482                         if (parts[part] < 0) {
2483                                 parts[part] += c + 1;
2484                                 parts[part - 1]--;
2485                         }
2486                 }
2487                 break;
2488         case 0: /* already UTC */
2489                 break;
2490         }
2491
2492         return LDAP_SUCCESS;
2493 }
2494
2495 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2496 static int
2497 xutcTimeNormalize(
2498         Syntax *syntax,
2499         struct berval *val,
2500         struct berval *normalized )
2501 {
2502         int parts[9], rc;
2503
2504         rc = check_time_syntax(val, 1, parts);
2505         if (rc != LDAP_SUCCESS) {
2506                 return rc;
2507         }
2508
2509         normalized->bv_val = ch_malloc( 14 );
2510         if ( normalized->bv_val == NULL ) {
2511                 return LBER_ERROR_MEMORY;
2512         }
2513
2514         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2515                 parts[1], parts[2] + 1, parts[3] + 1,
2516                 parts[4], parts[5], parts[6] );
2517         normalized->bv_len = 13;
2518
2519         return LDAP_SUCCESS;
2520 }
2521
2522 static int
2523 utcTimeValidate(
2524         Syntax *syntax,
2525         struct berval *in )
2526 {
2527         int parts[9];
2528         return check_time_syntax(in, 1, parts);
2529 }
2530 #endif
2531
2532 static int
2533 generalizedTimeValidate(
2534         Syntax *syntax,
2535         struct berval *in )
2536 {
2537         int parts[9];
2538         return check_time_syntax(in, 0, parts);
2539 }
2540
2541 static int
2542 generalizedTimeNormalize(
2543         slap_mask_t usage,
2544         Syntax *syntax,
2545         MatchingRule *mr,
2546         struct berval *val,
2547         struct berval *normalized,
2548         void *ctx )
2549 {
2550         int parts[9], rc;
2551
2552         rc = check_time_syntax(val, 0, parts);
2553         if (rc != LDAP_SUCCESS) {
2554                 return rc;
2555         }
2556
2557         normalized->bv_val = sl_malloc( 16, ctx );
2558         if ( normalized->bv_val == NULL ) {
2559                 return LBER_ERROR_MEMORY;
2560         }
2561
2562         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02dZ",
2563                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2564                 parts[4], parts[5], parts[6] );
2565         normalized->bv_len = 15;
2566
2567         return LDAP_SUCCESS;
2568 }
2569
2570 static int
2571 nisNetgroupTripleValidate(
2572         Syntax *syntax,
2573         struct berval *val )
2574 {
2575         char *p, *e;
2576         int commas = 0;
2577
2578         if ( val->bv_len == 0 ) {
2579                 return LDAP_INVALID_SYNTAX;
2580         }
2581
2582         p = (char *)val->bv_val;
2583         e = p + val->bv_len;
2584
2585         if ( *p != '(' /*')'*/ ) {
2586                 return LDAP_INVALID_SYNTAX;
2587         }
2588
2589         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
2590                 if ( *p == ',' ) {
2591                         commas++;
2592                         if ( commas > 2 ) {
2593                                 return LDAP_INVALID_SYNTAX;
2594                         }
2595
2596                 } else if ( !AD_CHAR( *p ) ) {
2597                         return LDAP_INVALID_SYNTAX;
2598                 }
2599         }
2600
2601         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
2602                 return LDAP_INVALID_SYNTAX;
2603         }
2604
2605         p++;
2606
2607         if (p != e) {
2608                 return LDAP_INVALID_SYNTAX;
2609         }
2610
2611         return LDAP_SUCCESS;
2612 }
2613
2614 static int
2615 bootParameterValidate(
2616         Syntax *syntax,
2617         struct berval *val )
2618 {
2619         char *p, *e;
2620
2621         if ( val->bv_len == 0 ) {
2622                 return LDAP_INVALID_SYNTAX;
2623         }
2624
2625         p = (char *)val->bv_val;
2626         e = p + val->bv_len;
2627
2628         /* key */
2629         for (; ( p < e ) && ( *p != '=' ); p++ ) {
2630                 if ( !AD_CHAR( *p ) ) {
2631                         return LDAP_INVALID_SYNTAX;
2632                 }
2633         }
2634
2635         if ( *p != '=' ) {
2636                 return LDAP_INVALID_SYNTAX;
2637         }
2638
2639         /* server */
2640         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
2641                 if ( !AD_CHAR( *p ) ) {
2642                         return LDAP_INVALID_SYNTAX;
2643                 }
2644         }
2645
2646         if ( *p != ':' ) {
2647                 return LDAP_INVALID_SYNTAX;
2648         }
2649
2650         /* path */
2651         for ( p++; p < e; p++ ) {
2652                 if ( !SLAP_PRINTABLE( *p ) ) {
2653                         return LDAP_INVALID_SYNTAX;
2654                 }
2655         }
2656
2657         return LDAP_SUCCESS;
2658 }
2659
2660 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
2661 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
2662
2663 static slap_syntax_defs_rec syntax_defs[] = {
2664         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
2665                 X_BINARY X_NOT_H_R ")",
2666                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
2667         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
2668                 0, NULL, NULL},
2669         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
2670                 0, NULL, NULL},
2671         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
2672                 X_NOT_H_R ")",
2673                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
2674         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
2675                 X_NOT_H_R ")",
2676                 SLAP_SYNTAX_BER, berValidate, NULL},
2677         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
2678                 0, bitStringValidate, NULL },
2679         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
2680                 0, booleanValidate, NULL},
2681         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
2682                 X_BINARY X_NOT_H_R ")",
2683                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2684         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
2685                 X_BINARY X_NOT_H_R ")",
2686                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2687         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
2688                 X_BINARY X_NOT_H_R ")",
2689                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2690         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
2691                 0, countryStringValidate, NULL},
2692         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
2693                 0, dnValidate, dnPretty2},
2694         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
2695                 0, NULL, NULL},
2696         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
2697                 0, NULL, NULL},
2698         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
2699                 0, UTF8StringValidate, NULL},
2700         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
2701                 0, NULL, NULL},
2702         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
2703                 0, NULL, NULL},
2704         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
2705                 0, NULL, NULL},
2706         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
2707                 0, NULL, NULL},
2708         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
2709                 0, NULL, NULL},
2710         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
2711                 0, printablesStringValidate, NULL},
2712         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
2713                 SLAP_SYNTAX_BLOB, NULL, NULL},
2714         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
2715                 0, generalizedTimeValidate, NULL},
2716         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
2717                 0, NULL, NULL},
2718         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
2719                 0, IA5StringValidate, NULL},
2720         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
2721                 0, integerValidate, NULL},
2722         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
2723                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
2724         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
2725                 0, NULL, NULL},
2726         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
2727                 0, NULL, NULL},
2728         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
2729                 0, NULL, NULL},
2730         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
2731                 0, NULL, NULL},
2732         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
2733                 0, NULL, NULL},
2734         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
2735                 0, nameUIDValidate, NULL},
2736         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
2737                 0, NULL, NULL},
2738         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
2739                 0, numericStringValidate, NULL},
2740         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
2741                 0, NULL, NULL},
2742         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
2743                 0, oidValidate, NULL},
2744         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
2745                 0, IA5StringValidate, NULL},
2746         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
2747                 0, blobValidate, NULL},
2748         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
2749                 0, UTF8StringValidate, NULL},
2750         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
2751                 0, NULL, NULL},
2752         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
2753                 0, NULL, NULL},
2754         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
2755                 0, printableStringValidate, NULL},
2756         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' "
2757                 X_BINARY X_NOT_H_R ")",
2758                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
2759         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
2760                 X_BINARY X_NOT_H_R ")",
2761                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2762         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
2763                 0, printableStringValidate, NULL},
2764         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
2765                 0, NULL, NULL},
2766         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
2767                 0, printablesStringValidate, NULL},
2768 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2769         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
2770                 0, utcTimeValidate, NULL},
2771 #endif
2772         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
2773                 0, NULL, NULL},
2774         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
2775                 0, NULL, NULL},
2776         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
2777                 0, NULL, NULL},
2778         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
2779                 0, NULL, NULL},
2780         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
2781                 0, NULL, NULL},
2782
2783         /* RFC 2307 NIS Syntaxes */
2784         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
2785                 0, nisNetgroupTripleValidate, NULL},
2786         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
2787                 0, bootParameterValidate, NULL},
2788
2789 #ifdef HAVE_TLS
2790         /* From PKIX */
2791         /* These OIDs are not published yet, but will be in the next
2792          * I-D for PKIX LDAPv3 schema as have been advanced by David
2793          * Chadwick in private mail.
2794          */
2795         {"( 1.2.826.0.1.3344810.7.1 DESC 'Serial Number and Issuer' )",
2796                 0, UTF8StringValidate, NULL},
2797 #endif
2798
2799         /* OpenLDAP Experimental Syntaxes */
2800 #ifdef SLAPD_ACI_ENABLED
2801         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
2802                 SLAP_SYNTAX_HIDE,
2803                 UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
2804                 NULL},
2805 #endif
2806
2807 #ifdef SLAPD_AUTHPASSWD
2808         /* needs updating */
2809         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
2810                 SLAP_SYNTAX_HIDE, NULL, NULL},
2811 #endif
2812
2813         /* OpenLDAP Void Syntax */
2814         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
2815                 SLAP_SYNTAX_HIDE, inValidate, NULL},
2816         {NULL, 0, NULL, NULL}
2817 };
2818
2819 #ifdef HAVE_TLS
2820 char *certificateExactMatchSyntaxes[] = {
2821         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
2822         NULL
2823 };
2824 #endif
2825 char *directoryStringSyntaxes[] = {
2826         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
2827         NULL
2828 };
2829 char *integerFirstComponentMatchSyntaxes[] = {
2830         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
2831         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
2832         NULL
2833 };
2834 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
2835         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
2836         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
2837         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
2838         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
2839         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
2840         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
2841         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
2842         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
2843         NULL
2844 };
2845
2846 /*
2847  * Other matching rules in X.520 that we do not use (yet):
2848  *
2849  * 2.5.13.9             numericStringOrderingMatch
2850  * 2.5.13.25    uTCTimeMatch
2851  * 2.5.13.26    uTCTimeOrderingMatch
2852  * 2.5.13.31    directoryStringFirstComponentMatch
2853  * 2.5.13.32    wordMatch
2854  * 2.5.13.33    keywordMatch
2855  * 2.5.13.35    certificateMatch
2856  * 2.5.13.36    certificatePairExactMatch
2857  * 2.5.13.37    certificatePairMatch
2858  * 2.5.13.38    certificateListExactMatch
2859  * 2.5.13.39    certificateListMatch
2860  * 2.5.13.40    algorithmIdentifierMatch
2861  * 2.5.13.41    storedPrefixMatch
2862  * 2.5.13.42    attributeCertificateMatch
2863  * 2.5.13.43    readerAndKeyIDMatch
2864  * 2.5.13.44    attributeIntegrityMatch
2865  */
2866 static slap_mrule_defs_rec mrule_defs[] = {
2867         /*
2868          * EQUALITY matching rules must be listed after associated APPROX
2869          * matching rules.  So, we list all APPROX matching rules first.
2870          */
2871 #ifndef SLAP_NVALUES
2872         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
2873                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2874                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
2875                 NULL, NULL, directoryStringApproxMatch,
2876                 directoryStringApproxIndexer, directoryStringApproxFilter,
2877                 NULL},
2878
2879         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
2880                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
2881                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
2882                 NULL, NULL, IA5StringApproxMatch,
2883                 IA5StringApproxIndexer, IA5StringApproxFilter,
2884                 NULL},
2885 #endif
2886
2887         /*
2888          * Other matching rules
2889          */
2890         
2891         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
2892                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
2893                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2894                 NULL, objectIdentifierNormalize, octetStringMatch,
2895                 octetStringIndexer, octetStringFilter,
2896                 NULL},
2897
2898         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
2899                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
2900                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2901                 NULL, dnNormalize, dnMatch,
2902                 octetStringIndexer, octetStringFilter,
2903                 NULL},
2904
2905         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
2906                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2907                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
2908                 NULL, UTF8StringNormalize, octetStringMatch,
2909                 octetStringIndexer, octetStringFilter,
2910                 directoryStringApproxMatchOID },
2911
2912         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
2913                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2914                 SLAP_MR_ORDERING, directoryStringSyntaxes,
2915                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
2916                 NULL, NULL,
2917                 NULL},
2918
2919         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
2920                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2921                 SLAP_MR_SUBSTR, NULL,
2922                 NULL, UTF8StringNormalize, octetStringSubstringsMatch,
2923                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2924                 NULL},
2925
2926         {"( 2.5.13.5 NAME 'caseExactMatch' "
2927                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2928                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
2929                 NULL, UTF8StringNormalize, octetStringMatch,
2930                 octetStringIndexer, octetStringFilter,
2931                 directoryStringApproxMatchOID },
2932
2933         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
2934                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2935                 SLAP_MR_ORDERING, directoryStringSyntaxes,
2936                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
2937                 NULL, NULL,
2938                 NULL},
2939
2940         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
2941                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2942                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
2943                 NULL, UTF8StringNormalize, octetStringSubstringsMatch,
2944                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2945                 NULL},
2946
2947         {"( 2.5.13.8 NAME 'numericStringMatch' "
2948                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
2949                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2950                 NULL, numericStringNormalize, octetStringSubstringsMatch,
2951                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2952                 NULL},
2953
2954         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
2955                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2956                 SLAP_MR_SUBSTR, NULL,
2957                 NULL, numericStringNormalize, octetStringSubstringsMatch,
2958                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2959                 NULL},
2960
2961         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
2962                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
2963                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2964                 NULL, NULL, NULL, NULL, NULL, NULL},
2965
2966         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
2967                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2968                 SLAP_MR_SUBSTR, NULL,
2969                 NULL, NULL, NULL, NULL, NULL, NULL},
2970
2971         {"( 2.5.13.13 NAME 'booleanMatch' "
2972                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
2973                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2974                 NULL, NULL, booleanMatch,
2975                 octetStringIndexer, octetStringFilter,
2976                 NULL},
2977
2978         {"( 2.5.13.14 NAME 'integerMatch' "
2979                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
2980                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2981                 NULL, integerNormalize, integerMatch,
2982                 octetStringIndexer, octetStringFilter,
2983                 NULL},
2984
2985         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
2986                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
2987                 SLAP_MR_ORDERING, NULL,
2988                 NULL, integerNormalize, integerOrderingMatch,
2989                 NULL, NULL,
2990                 NULL},
2991
2992         {"( 2.5.13.16 NAME 'bitStringMatch' "
2993                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
2994                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2995                 NULL, NULL, octetStringMatch,
2996                 octetStringIndexer, octetStringFilter,
2997                 NULL},
2998
2999         {"( 2.5.13.17 NAME 'octetStringMatch' "
3000                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3001                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3002                 NULL, NULL, octetStringMatch,
3003                 octetStringIndexer, octetStringFilter,
3004                 NULL},
3005
3006         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
3007                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3008                 SLAP_MR_ORDERING, NULL,
3009                 NULL, NULL, octetStringOrderingMatch,
3010                 NULL, NULL,
3011                 NULL},
3012
3013         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
3014                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3015                 SLAP_MR_SUBSTR, NULL,
3016                 NULL, NULL, octetStringSubstringsMatch,
3017                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3018                 NULL},
3019
3020         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
3021                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
3022                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3023                 NULL,
3024                 telephoneNumberNormalize, octetStringMatch,
3025                 octetStringIndexer, octetStringFilter,
3026                 NULL},
3027
3028         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
3029                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3030                 SLAP_MR_SUBSTR, NULL,
3031                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
3032                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3033                 NULL},
3034
3035         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
3036                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
3037                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3038                 NULL, NULL, NULL, NULL, NULL, NULL},
3039
3040         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
3041                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
3042                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3043                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
3044                 NULL, NULL,
3045                 NULL},
3046
3047         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
3048                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
3049                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3050                 NULL, NULL, NULL, NULL, NULL, NULL},
3051
3052         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
3053                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3054                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3055                 NULL, generalizedTimeNormalize, octetStringMatch,
3056                 NULL, NULL,
3057                 NULL},
3058
3059         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
3060                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3061                 SLAP_MR_ORDERING, NULL,
3062                 NULL, generalizedTimeNormalize, octetStringOrderingMatch,
3063                 NULL, NULL,
3064                 NULL},
3065
3066         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
3067                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3068                 SLAP_MR_EQUALITY | SLAP_MR_EXT, integerFirstComponentMatchSyntaxes,
3069                 NULL, integerFirstComponentNormalize, integerMatch,
3070                 NULL, NULL,
3071                 NULL},
3072
3073         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
3074                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3075                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3076                         objectIdentifierFirstComponentMatchSyntaxes,
3077                 NULL, objectIdentifierFirstComponentNormalize, octetStringMatch,
3078                 octetStringIndexer, octetStringFilter,
3079                 NULL},
3080
3081 #ifndef SLAP_NVALUES
3082 #ifdef HAVE_TLS
3083         {"( 2.5.13.34 NAME 'certificateExactMatch' "
3084                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
3085                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
3086                 certificateExactConvert, NULL, certificateExactMatch,
3087                 certificateExactIndexer, certificateExactFilter,
3088                 NULL},
3089 #endif
3090 #endif
3091
3092         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3093                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3094                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3095                 NULL, IA5StringNormalize, octetStringMatch,
3096                 octetStringIndexer, octetStringFilter,
3097                 IA5StringApproxMatchOID },
3098
3099         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3100                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3101                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3102                 NULL, IA5StringNormalize, octetStringMatch,
3103                 octetStringIndexer, octetStringFilter,
3104                 IA5StringApproxMatchOID },
3105
3106         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3107                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3108                 SLAP_MR_SUBSTR, NULL,
3109                 NULL, IA5StringNormalize, octetStringSubstringsMatch,
3110                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3111                 NULL},
3112
3113         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3114                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3115                 SLAP_MR_SUBSTR, NULL,
3116                 NULL, IA5StringNormalize, octetStringSubstringsMatch,
3117                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3118                 NULL},
3119
3120 #ifdef SLAPD_AUTHPASSWD
3121         /* needs updating */
3122         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3123                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3124                 SLAP_MR_EQUALITY, NULL,
3125                 NULL, NULL, authPasswordMatch,
3126                 NULL, NULL,
3127                 NULL},
3128 #endif
3129
3130 #ifdef SLAPD_ACI_ENABLED
3131         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
3132                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
3133                 SLAP_MR_EQUALITY, NULL,
3134                 NULL, NULL, OpenLDAPaciMatch,
3135                 NULL, NULL,
3136                 NULL},
3137 #endif
3138
3139         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3140                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3141                 SLAP_MR_EXT, NULL,
3142                 NULL, NULL, integerBitAndMatch,
3143                 NULL, NULL,
3144                 NULL},
3145
3146         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3147                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3148                 SLAP_MR_EXT, NULL,
3149                 NULL, NULL, integerBitOrMatch,
3150                 NULL, NULL,
3151                 NULL},
3152
3153         {NULL, SLAP_MR_NONE, NULL,
3154                 NULL, NULL, NULL, NULL, NULL,
3155                 NULL }
3156 };
3157
3158 int
3159 slap_schema_init( void )
3160 {
3161         int             res;
3162         int             i;
3163
3164         /* we should only be called once (from main) */
3165         assert( schema_init_done == 0 );
3166
3167         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3168                 res = register_syntax( &syntax_defs[i] );
3169
3170                 if ( res ) {
3171                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3172                                  syntax_defs[i].sd_desc );
3173                         return LDAP_OTHER;
3174                 }
3175         }
3176
3177         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3178                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3179                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3180                 {
3181                         fprintf( stderr,
3182                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3183                                  mrule_defs[i].mrd_desc );
3184                         continue;
3185                 }
3186
3187                 res = register_matching_rule( &mrule_defs[i] );
3188
3189                 if ( res ) {
3190                         fprintf( stderr,
3191                                 "slap_schema_init: Error registering matching rule %s\n",
3192                                  mrule_defs[i].mrd_desc );
3193                         return LDAP_OTHER;
3194                 }
3195         }
3196
3197         res = slap_schema_load();
3198         schema_init_done = 1;
3199         return res;
3200 }
3201
3202 void
3203 schema_destroy( void )
3204 {
3205         oidm_destroy();
3206         oc_destroy();
3207         at_destroy();
3208         mr_destroy();
3209         mru_destroy();
3210         syn_destroy();
3211 }