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