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