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