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