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