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