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