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