]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
trim listed modules
[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-2007 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 #ifdef HAVE_LIMITS_H
21 #include <limits.h>
22 #endif
23
24 #include <ac/ctype.h>
25 #include <ac/errno.h>
26 #include <ac/string.h>
27 #include <ac/socket.h>
28
29 #include "slap.h"
30
31 #include "ldap_utf8.h"
32
33 #ifdef HAVE_TLS
34 #include <openssl/x509.h>
35 #include <openssl/err.h>
36 #include <openssl/rsa.h>
37 #include <openssl/crypto.h>
38 #include <openssl/pem.h>
39 #include <openssl/bio.h>
40 #include <openssl/asn1.h>
41 #include <openssl/x509v3.h>
42 #include <openssl/ssl.h>
43 #endif
44
45 #include "lutil.h"
46 #include "lutil_hash.h"
47 #define HASH_BYTES                              LUTIL_HASH_BYTES
48 #define HASH_CONTEXT                    lutil_HASH_CTX
49 #define HASH_Init(c)                    lutil_HASHInit(c)
50 #define HASH_Update(c,buf,len)  lutil_HASHUpdate(c,buf,len)
51 #define HASH_Final(d,c)                 lutil_HASHFinal(d,c)
52
53 /* approx matching rules */
54 #define directoryStringApproxMatchOID   "1.3.6.1.4.1.4203.666.4.4"
55 #define directoryStringApproxMatch              approxMatch
56 #define directoryStringApproxIndexer    approxIndexer
57 #define directoryStringApproxFilter             approxFilter
58 #define IA5StringApproxMatchOID                 "1.3.6.1.4.1.4203.666.4.5"
59 #define IA5StringApproxMatch                    approxMatch
60 #define IA5StringApproxIndexer                  approxIndexer
61 #define IA5StringApproxFilter                   approxFilter
62
63 /* Change Sequence Number (CSN) - much of this will change */
64 #define csnValidate                             blobValidate
65 #define csnMatch                                octetStringMatch
66 #define csnOrderingMatch                octetStringOrderingMatch
67 #define csnIndexer                              generalizedTimeIndexer
68 #define csnFilter                               generalizedTimeFilter
69
70 /* FIXME: temporary */
71 #define authzMatch                              octetStringMatch
72
73 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
74 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
75 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
76 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
77
78 ldap_pvt_thread_mutex_t ad_undef_mutex;
79 ldap_pvt_thread_mutex_t oc_undef_mutex;
80
81 static int
82 inValidate(
83         Syntax *syntax,
84         struct berval *in )
85 {
86         /* no value allowed */
87         return LDAP_INVALID_SYNTAX;
88 }
89
90 static int
91 blobValidate(
92         Syntax *syntax,
93         struct berval *in )
94 {
95         /* any value allowed */
96         return LDAP_SUCCESS;
97 }
98
99 #define berValidate blobValidate
100
101 static int
102 sequenceValidate(
103         Syntax *syntax,
104         struct berval *in )
105 {
106         if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
107         if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
108
109         return LDAP_SUCCESS;
110 }
111
112
113 #ifdef HAVE_TLS
114 static int certificateValidate( Syntax *syntax, struct berval *in )
115 {
116         X509 *xcert=NULL;
117         unsigned char *p = (unsigned char *)in->bv_val;
118  
119         xcert = d2i_X509(NULL, &p, in->bv_len);
120         if ( !xcert ) return LDAP_INVALID_SYNTAX;
121         X509_free(xcert);
122         return LDAP_SUCCESS;
123 }
124 #else
125 #define certificateValidate sequenceValidate
126 #endif
127
128 int
129 octetStringMatch(
130         int *matchp,
131         slap_mask_t flags,
132         Syntax *syntax,
133         MatchingRule *mr,
134         struct berval *value,
135         void *assertedValue )
136 {
137         struct berval *asserted = (struct berval *) assertedValue;
138         int match = value->bv_len - asserted->bv_len;
139
140         if( match == 0 ) {
141                 match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
142         }
143
144         *matchp = match;
145         return LDAP_SUCCESS;
146 }
147
148 static int
149 octetStringOrderingMatch(
150         int *matchp,
151         slap_mask_t flags,
152         Syntax *syntax,
153         MatchingRule *mr,
154         struct berval *value,
155         void *assertedValue )
156 {
157         struct berval *asserted = (struct berval *) assertedValue;
158         ber_len_t v_len  = value->bv_len;
159         ber_len_t av_len = asserted->bv_len;
160
161         int match = memcmp( value->bv_val, asserted->bv_val,
162                 (v_len < av_len ? v_len : av_len) );
163
164         if( match == 0 ) match = v_len - av_len;
165
166         *matchp = match;
167         return LDAP_SUCCESS;
168 }
169
170 static void
171 hashPreset(
172         HASH_CONTEXT *HASHcontext,
173         struct berval *prefix,
174         char pre,
175         Syntax *syntax,
176         MatchingRule *mr)
177 {
178         HASH_Init(HASHcontext);
179         if(prefix && prefix->bv_len > 0) {
180                 HASH_Update(HASHcontext,
181                         (unsigned char *)prefix->bv_val, prefix->bv_len);
182         }
183         if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
184         HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
185         HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
186         return;
187 }
188
189 static void
190 hashIter(
191         HASH_CONTEXT *HASHcontext,
192         unsigned char *HASHdigest,
193         unsigned char *value,
194         int len)
195 {
196         HASH_CONTEXT ctx = *HASHcontext;
197         HASH_Update( &ctx, value, len );
198         HASH_Final( HASHdigest, &ctx );
199 }
200
201 /* Index generation function */
202 int octetStringIndexer(
203         slap_mask_t use,
204         slap_mask_t flags,
205         Syntax *syntax,
206         MatchingRule *mr,
207         struct berval *prefix,
208         BerVarray values,
209         BerVarray *keysp,
210         void *ctx )
211 {
212         int i;
213         size_t slen, mlen;
214         BerVarray keys;
215         HASH_CONTEXT HASHcontext;
216         unsigned char HASHdigest[HASH_BYTES];
217         struct berval digest;
218         digest.bv_val = (char *)HASHdigest;
219         digest.bv_len = sizeof(HASHdigest);
220
221         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
222                 /* just count them */
223         }
224
225         /* we should have at least one value at this point */
226         assert( i > 0 );
227
228         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
229
230         slen = syntax->ssyn_oidlen;
231         mlen = mr->smr_oidlen;
232
233         hashPreset( &HASHcontext, prefix, 0, syntax, mr);
234         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
235                 hashIter( &HASHcontext, HASHdigest,
236                         (unsigned char *)values[i].bv_val, values[i].bv_len );
237                 ber_dupbv_x( &keys[i], &digest, ctx );
238         }
239
240         BER_BVZERO( &keys[i] );
241
242         *keysp = keys;
243
244         return LDAP_SUCCESS;
245 }
246
247 /* Index generation function */
248 int octetStringFilter(
249         slap_mask_t use,
250         slap_mask_t flags,
251         Syntax *syntax,
252         MatchingRule *mr,
253         struct berval *prefix,
254         void * assertedValue,
255         BerVarray *keysp,
256         void *ctx )
257 {
258         size_t slen, mlen;
259         BerVarray keys;
260         HASH_CONTEXT HASHcontext;
261         unsigned char HASHdigest[HASH_BYTES];
262         struct berval *value = (struct berval *) assertedValue;
263         struct berval digest;
264         digest.bv_val = (char *)HASHdigest;
265         digest.bv_len = sizeof(HASHdigest);
266
267         slen = syntax->ssyn_oidlen;
268         mlen = mr->smr_oidlen;
269
270         keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
271
272         hashPreset( &HASHcontext, prefix, 0, syntax, mr );
273         hashIter( &HASHcontext, HASHdigest,
274                 (unsigned char *)value->bv_val, value->bv_len );
275
276         ber_dupbv_x( keys, &digest, ctx );
277         BER_BVZERO( &keys[1] );
278
279         *keysp = keys;
280
281         return LDAP_SUCCESS;
282 }
283
284 static int
285 octetStringSubstringsMatch(
286         int *matchp,
287         slap_mask_t flags,
288         Syntax *syntax,
289         MatchingRule *mr,
290         struct berval *value,
291         void *assertedValue )
292 {
293         int match = 0;
294         SubstringsAssertion *sub = assertedValue;
295         struct berval left = *value;
296         int i;
297         ber_len_t inlen = 0;
298
299         /* Add up asserted input length */
300         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
301                 inlen += sub->sa_initial.bv_len;
302         }
303         if ( sub->sa_any ) {
304                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
305                         inlen += sub->sa_any[i].bv_len;
306                 }
307         }
308         if ( !BER_BVISNULL( &sub->sa_final ) ) {
309                 inlen += sub->sa_final.bv_len;
310         }
311
312         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
313                 if ( inlen > left.bv_len ) {
314                         match = 1;
315                         goto done;
316                 }
317
318                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
319                         sub->sa_initial.bv_len );
320
321                 if ( match != 0 ) {
322                         goto done;
323                 }
324
325                 left.bv_val += sub->sa_initial.bv_len;
326                 left.bv_len -= sub->sa_initial.bv_len;
327                 inlen -= sub->sa_initial.bv_len;
328         }
329
330         if ( !BER_BVISNULL( &sub->sa_final ) ) {
331                 if ( inlen > left.bv_len ) {
332                         match = 1;
333                         goto done;
334                 }
335
336                 match = memcmp( sub->sa_final.bv_val,
337                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
338                         sub->sa_final.bv_len );
339
340                 if ( match != 0 ) {
341                         goto done;
342                 }
343
344                 left.bv_len -= sub->sa_final.bv_len;
345                 inlen -= sub->sa_final.bv_len;
346         }
347
348         if ( sub->sa_any ) {
349                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
350                         ber_len_t idx;
351                         char *p;
352
353 retry:
354                         if ( inlen > left.bv_len ) {
355                                 /* not enough length */
356                                 match = 1;
357                                 goto done;
358                         }
359
360                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
361                                 continue;
362                         }
363
364                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
365
366                         if( p == NULL ) {
367                                 match = 1;
368                                 goto done;
369                         }
370
371                         idx = p - left.bv_val;
372
373                         if ( idx >= left.bv_len ) {
374                                 /* this shouldn't happen */
375                                 return LDAP_OTHER;
376                         }
377
378                         left.bv_val = p;
379                         left.bv_len -= idx;
380
381                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
382                                 /* not enough left */
383                                 match = 1;
384                                 goto done;
385                         }
386
387                         match = memcmp( left.bv_val,
388                                 sub->sa_any[i].bv_val,
389                                 sub->sa_any[i].bv_len );
390
391                         if ( match != 0 ) {
392                                 left.bv_val++;
393                                 left.bv_len--;
394                                 goto retry;
395                         }
396
397                         left.bv_val += sub->sa_any[i].bv_len;
398                         left.bv_len -= sub->sa_any[i].bv_len;
399                         inlen -= sub->sa_any[i].bv_len;
400                 }
401         }
402
403 done:
404         *matchp = match;
405         return LDAP_SUCCESS;
406 }
407
408 /* Substrings Index generation function */
409 static int
410 octetStringSubstringsIndexer(
411         slap_mask_t use,
412         slap_mask_t flags,
413         Syntax *syntax,
414         MatchingRule *mr,
415         struct berval *prefix,
416         BerVarray values,
417         BerVarray *keysp,
418         void *ctx )
419 {
420         ber_len_t i, nkeys;
421         size_t slen, mlen;
422         BerVarray keys;
423
424         HASH_CONTEXT HCany, HCini, HCfin;
425         unsigned char HASHdigest[HASH_BYTES];
426         struct berval digest;
427         digest.bv_val = (char *)HASHdigest;
428         digest.bv_len = sizeof(HASHdigest);
429
430         nkeys = 0;
431
432         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
433                 /* count number of indices to generate */
434                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
435                         if( values[i].bv_len >= index_substr_if_maxlen ) {
436                                 nkeys += index_substr_if_maxlen -
437                                         (index_substr_if_minlen - 1);
438                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
439                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
440                         }
441                 }
442
443                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
444                         if( values[i].bv_len >= index_substr_any_len ) {
445                                 nkeys += values[i].bv_len - (index_substr_any_len - 1);
446                         }
447                 }
448
449                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
450                         if( values[i].bv_len >= index_substr_if_maxlen ) {
451                                 nkeys += index_substr_if_maxlen -
452                                         (index_substr_if_minlen - 1);
453                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
454                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
455                         }
456                 }
457         }
458
459         if( nkeys == 0 ) {
460                 /* no keys to generate */
461                 *keysp = NULL;
462                 return LDAP_SUCCESS;
463         }
464
465         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
466
467         slen = syntax->ssyn_oidlen;
468         mlen = mr->smr_oidlen;
469
470         if ( flags & SLAP_INDEX_SUBSTR_ANY )
471                 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
472         if( flags & SLAP_INDEX_SUBSTR_INITIAL )
473                 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
474         if( flags & SLAP_INDEX_SUBSTR_FINAL )
475                 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
476
477         nkeys = 0;
478         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
479                 ber_len_t j,max;
480
481                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
482                         ( values[i].bv_len >= index_substr_any_len ) )
483                 {
484                         max = values[i].bv_len - (index_substr_any_len - 1);
485
486                         for( j=0; j<max; j++ ) {
487                                 hashIter( &HCany, HASHdigest,
488                                         (unsigned char *)&values[i].bv_val[j],
489                                         index_substr_any_len );
490                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
491                         }
492                 }
493
494                 /* skip if too short */ 
495                 if( values[i].bv_len < index_substr_if_minlen ) continue;
496
497                 max = index_substr_if_maxlen < values[i].bv_len
498                         ? index_substr_if_maxlen : values[i].bv_len;
499
500                 for( j=index_substr_if_minlen; j<=max; j++ ) {
501
502                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
503                                 hashIter( &HCini, HASHdigest,
504                                         (unsigned char *)values[i].bv_val, j );
505                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
506                         }
507
508                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
509                                 hashIter( &HCfin, HASHdigest,
510                                         (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
511                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
512                         }
513
514                 }
515         }
516
517         if( nkeys > 0 ) {
518                 BER_BVZERO( &keys[nkeys] );
519                 *keysp = keys;
520         } else {
521                 ch_free( keys );
522                 *keysp = NULL;
523         }
524
525         return LDAP_SUCCESS;
526 }
527
528 static int
529 octetStringSubstringsFilter (
530         slap_mask_t use,
531         slap_mask_t flags,
532         Syntax *syntax,
533         MatchingRule *mr,
534         struct berval *prefix,
535         void * assertedValue,
536         BerVarray *keysp,
537         void *ctx)
538 {
539         SubstringsAssertion *sa;
540         char pre;
541         ber_len_t nkeys = 0;
542         size_t slen, mlen, klen;
543         BerVarray keys;
544         HASH_CONTEXT HASHcontext;
545         unsigned char HASHdigest[HASH_BYTES];
546         struct berval *value;
547         struct berval digest;
548
549         sa = (SubstringsAssertion *) assertedValue;
550
551         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
552                 !BER_BVISNULL( &sa->sa_initial ) &&
553                 sa->sa_initial.bv_len >= index_substr_if_minlen )
554         {
555                 nkeys++;
556                 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
557                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
558                 {
559                         nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
560                 }
561         }
562
563         if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
564                 ber_len_t i;
565                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
566                         if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
567                                 /* don't bother accounting with stepping */
568                                 nkeys += sa->sa_any[i].bv_len -
569                                         ( index_substr_any_len - 1 );
570                         }
571                 }
572         }
573
574         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
575                 !BER_BVISNULL( &sa->sa_final ) &&
576                 sa->sa_final.bv_len >= index_substr_if_minlen )
577         {
578                 nkeys++;
579                 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
580                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
581                 {
582                         nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
583                 }
584         }
585
586         if( nkeys == 0 ) {
587                 *keysp = NULL;
588                 return LDAP_SUCCESS;
589         }
590
591         digest.bv_val = (char *)HASHdigest;
592         digest.bv_len = sizeof(HASHdigest);
593
594         slen = syntax->ssyn_oidlen;
595         mlen = mr->smr_oidlen;
596
597         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
598         nkeys = 0;
599
600         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
601                 !BER_BVISNULL( &sa->sa_initial ) &&
602                 sa->sa_initial.bv_len >= index_substr_if_minlen )
603         {
604                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
605                 value = &sa->sa_initial;
606
607                 klen = index_substr_if_maxlen < value->bv_len
608                         ? index_substr_if_maxlen : value->bv_len;
609
610                 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
611                 hashIter( &HASHcontext, HASHdigest,
612                         (unsigned char *)value->bv_val, klen );
613                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
614
615                 /* If initial is too long and we have subany indexed, use it
616                  * to match the excess...
617                  */
618                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
619                 {
620                         ber_len_t j;
621                         pre = SLAP_INDEX_SUBSTR_PREFIX;
622                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
623                         for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
624                         {
625                                 hashIter( &HASHcontext, HASHdigest,
626                                         (unsigned char *)&value->bv_val[j], index_substr_any_len );
627                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
628                         }
629                 }
630         }
631
632         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
633                 ber_len_t i, j;
634                 pre = SLAP_INDEX_SUBSTR_PREFIX;
635                 klen = index_substr_any_len;
636
637                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
638                         if( sa->sa_any[i].bv_len < index_substr_any_len ) {
639                                 continue;
640                         }
641
642                         value = &sa->sa_any[i];
643
644                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
645                         for(j=0;
646                                 j <= value->bv_len - index_substr_any_len;
647                                 j += index_substr_any_step )
648                         {
649                                 hashIter( &HASHcontext, HASHdigest,
650                                         (unsigned char *)&value->bv_val[j], klen ); 
651                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
652                         }
653                 }
654         }
655
656         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
657                 !BER_BVISNULL( &sa->sa_final ) &&
658                 sa->sa_final.bv_len >= index_substr_if_minlen )
659         {
660                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
661                 value = &sa->sa_final;
662
663                 klen = index_substr_if_maxlen < value->bv_len
664                         ? index_substr_if_maxlen : value->bv_len;
665
666                 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
667                 hashIter( &HASHcontext, HASHdigest,
668                         (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
669                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
670
671                 /* If final is too long and we have subany indexed, use it
672                  * to match the excess...
673                  */
674                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
675                 {
676                         ber_len_t j;
677                         pre = SLAP_INDEX_SUBSTR_PREFIX;
678                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
679                         for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
680                         {
681                                 hashIter( &HASHcontext, HASHdigest,
682                                         (unsigned char *)&value->bv_val[j], index_substr_any_len );
683                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
684                         }
685                 }
686         }
687
688         if( nkeys > 0 ) {
689                 BER_BVZERO( &keys[nkeys] );
690                 *keysp = keys;
691         } else {
692                 ch_free( keys );
693                 *keysp = NULL;
694         }
695
696         return LDAP_SUCCESS;
697 }
698
699 static int
700 bitStringValidate(
701         Syntax *syntax,
702         struct berval *in )
703 {
704         ber_len_t i;
705
706         /* very unforgiving validation, requires no normalization
707          * before simplistic matching
708          */
709         if( in->bv_len < 3 ) {
710                 return LDAP_INVALID_SYNTAX;
711         }
712
713         /* RFC 4517 Section 3.3.2 Bit String:
714      *  BitString    = SQUOTE *binary-digit SQUOTE "B"
715      *  binary-digit = "0" / "1"
716          *
717          * where SQUOTE [RFC4512] is
718          *      SQUOTE  = %x27 ; single quote ("'")
719          *
720          * Example: '0101111101'B
721          */
722         
723         if( in->bv_val[0] != '\'' ||
724                 in->bv_val[in->bv_len - 2] != '\'' ||
725                 in->bv_val[in->bv_len - 1] != 'B' )
726         {
727                 return LDAP_INVALID_SYNTAX;
728         }
729
730         for( i = in->bv_len - 3; i > 0; i-- ) {
731                 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
732                         return LDAP_INVALID_SYNTAX;
733                 }
734         }
735
736         return LDAP_SUCCESS;
737 }
738
739 /*
740  * Syntaxes from RFC 4517
741  *
742
743 3.3.2.  Bit String
744
745    A value of the Bit String syntax is a sequence of binary digits.  The
746    LDAP-specific encoding of a value of this syntax is defined by the
747    following ABNF:
748
749       BitString    = SQUOTE *binary-digit SQUOTE "B"
750
751       binary-digit = "0" / "1"
752
753    The <SQUOTE> rule is defined in [MODELS].
754
755       Example:
756          '0101111101'B
757
758    The LDAP definition for the Bit String syntax is:
759
760       ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
761
762    This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
763
764    ...
765
766 3.3.21.  Name and Optional UID
767
768    A value of the Name and Optional UID syntax is the distinguished name
769    [MODELS] of an entity optionally accompanied by a unique identifier
770    that serves to differentiate the entity from others with an identical
771    distinguished name.
772
773    The LDAP-specific encoding of a value of this syntax is defined by
774    the following ABNF:
775
776        NameAndOptionalUID = distinguishedName [ SHARP BitString ]
777
778    The <BitString> rule is defined in Section 3.3.2.  The
779    <distinguishedName> rule is defined in [LDAPDN].  The <SHARP> rule is
780    defined in [MODELS].
781
782    Note that although the '#' character may occur in the string
783    representation of a distinguished name, no additional escaping of
784    this character is performed when a <distinguishedName> is encoded in
785    a <NameAndOptionalUID>.
786
787       Example:
788          1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
789
790    The LDAP definition for the Name and Optional UID syntax is:
791
792       ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
793
794    This syntax corresponds to the NameAndOptionalUID ASN.1 type from
795    [X.520].
796
797  *
798  * RFC 4512 says:
799  *
800
801 1.4. Common ABNF Productions
802
803   ...
804       SHARP   = %x23 ; octothorpe (or sharp sign) ("#")
805   ...
806       SQUOTE  = %x27 ; single quote ("'")
807   ...
808       
809  *
810  * Note: normalization strips any leading "0"s, unless the
811  * bit string is exactly "'0'B", so the normalized example,
812  * in slapd, would result in
813  * 
814  * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B
815  * 
816  * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
817  * be escaped except when at the beginning of a value, the
818  * definition of Name and Optional UID appears to be flawed,
819  * because there is no clear means to determine whether the
820  * UID part is present or not.
821  *
822  * Example:
823  *
824  *      cn=Someone,dc=example,dc=com#'1'B
825  *
826  * could be either a NameAndOptionalUID with trailing UID, i.e.
827  *
828  *      DN = "cn=Someone,dc=example,dc=com"
829  *      UID = "'1'B"
830  * 
831  * or a NameAndOptionalUID with no trailing UID, and the AVA
832  * in the last RDN made of
833  *
834  *      attributeType = dc 
835  *      attributeValue = com#'1'B
836  *
837  * in fact "com#'1'B" is a valid IA5 string.
838  *
839  * As a consequence, current slapd code assumes that the
840  * presence of portions of a BitString at the end of the string 
841  * representation of a NameAndOptionalUID means a BitString
842  * is expected, and cause an error otherwise.  This is quite
843  * arbitrary, and might change in the future.
844  */
845
846
847 static int
848 nameUIDValidate(
849         Syntax *syntax,
850         struct berval *in )
851 {
852         int rc;
853         struct berval dn, uid;
854
855         if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
856
857         ber_dupbv( &dn, in );
858         if( !dn.bv_val ) return LDAP_OTHER;
859
860         /* if there's a "#", try bitStringValidate()... */
861         uid.bv_val = strrchr( dn.bv_val, '#' );
862         if ( !BER_BVISNULL( &uid ) ) {
863                 uid.bv_val++;
864                 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
865
866                 rc = bitStringValidate( NULL, &uid );
867                 if ( rc == LDAP_SUCCESS ) {
868                         /* in case of success, trim the UID,
869                          * otherwise treat it as part of the DN */
870                         dn.bv_len -= uid.bv_len + 1;
871                         uid.bv_val[-1] = '\0';
872                 }
873         }
874
875         rc = dnValidate( NULL, &dn );
876
877         ber_memfree( dn.bv_val );
878         return rc;
879 }
880
881 int
882 nameUIDPretty(
883         Syntax *syntax,
884         struct berval *val,
885         struct berval *out,
886         void *ctx )
887 {
888         assert( val != NULL );
889         assert( out != NULL );
890
891
892         Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
893
894         if( BER_BVISEMPTY( val ) ) {
895                 ber_dupbv_x( out, val, ctx );
896
897         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
898                 return LDAP_INVALID_SYNTAX;
899
900         } else {
901                 int             rc;
902                 struct berval   dnval = *val;
903                 struct berval   uidval = BER_BVNULL;
904
905                 uidval.bv_val = strrchr( val->bv_val, '#' );
906                 if ( !BER_BVISNULL( &uidval ) ) {
907                         uidval.bv_val++;
908                         uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
909
910                         rc = bitStringValidate( NULL, &uidval );
911
912                         if ( rc == LDAP_SUCCESS ) {
913                                 ber_dupbv_x( &dnval, val, ctx );
914                                 dnval.bv_len -= uidval.bv_len + 1;
915                                 dnval.bv_val[dnval.bv_len] = '\0';
916
917                         } else {
918                                 BER_BVZERO( &uidval );
919                         }
920                 }
921
922                 rc = dnPretty( syntax, &dnval, out, ctx );
923                 if ( dnval.bv_val != val->bv_val ) {
924                         slap_sl_free( dnval.bv_val, ctx );
925                 }
926                 if( rc != LDAP_SUCCESS ) {
927                         return rc;
928                 }
929
930                 if( !BER_BVISNULL( &uidval ) ) {
931                         int     i, c, got1;
932                         char    *tmp;
933
934                         tmp = slap_sl_realloc( out->bv_val, out->bv_len 
935                                 + STRLENOF( "#" ) + uidval.bv_len + 1,
936                                 ctx );
937                         if( tmp == NULL ) {
938                                 ber_memfree_x( out->bv_val, ctx );
939                                 return LDAP_OTHER;
940                         }
941                         out->bv_val = tmp;
942                         out->bv_val[out->bv_len++] = '#';
943                         out->bv_val[out->bv_len++] = '\'';
944
945                         got1 = uidval.bv_len < sizeof("'0'B"); 
946                         for( i = 1; i < uidval.bv_len - 2; i++ ) {
947                                 c = uidval.bv_val[i];
948                                 switch(c) {
949                                         case '0':
950                                                 if( got1 ) out->bv_val[out->bv_len++] = c;
951                                                 break;
952                                         case '1':
953                                                 got1 = 1;
954                                                 out->bv_val[out->bv_len++] = c;
955                                                 break;
956                                 }
957                         }
958
959                         out->bv_val[out->bv_len++] = '\'';
960                         out->bv_val[out->bv_len++] = 'B';
961                         out->bv_val[out->bv_len] = '\0';
962                 }
963         }
964
965         Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
966
967         return LDAP_SUCCESS;
968 }
969
970 static int
971 uniqueMemberNormalize(
972         slap_mask_t usage,
973         Syntax *syntax,
974         MatchingRule *mr,
975         struct berval *val,
976         struct berval *normalized,
977         void *ctx )
978 {
979         struct berval out;
980         int rc;
981
982         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
983
984         ber_dupbv_x( &out, val, ctx );
985         if ( BER_BVISEMPTY( &out ) ) {
986                 *normalized = out;
987
988         } else {
989                 struct berval uid = BER_BVNULL;
990
991                 uid.bv_val = strrchr( out.bv_val, '#' );
992                 if ( !BER_BVISNULL( &uid ) ) {
993                         uid.bv_val++;
994                         uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
995
996                         rc = bitStringValidate( NULL, &uid );
997                         if ( rc == LDAP_SUCCESS ) {
998                                 uid.bv_val[-1] = '\0';
999                                 out.bv_len -= uid.bv_len + 1;
1000                         } else {
1001                                 BER_BVZERO( &uid );
1002                         }
1003                 }
1004
1005                 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1006
1007                 if( rc != LDAP_SUCCESS ) {
1008                         slap_sl_free( out.bv_val, ctx );
1009                         return LDAP_INVALID_SYNTAX;
1010                 }
1011
1012                 if( !BER_BVISNULL( &uid ) ) {
1013                         char    *tmp;
1014
1015                         tmp = ch_realloc( normalized->bv_val,
1016                                 normalized->bv_len + uid.bv_len
1017                                 + STRLENOF("#") + 1 );
1018                         if ( tmp == NULL ) {
1019                                 ber_memfree_x( normalized->bv_val, ctx );
1020                                 return LDAP_OTHER;
1021                         }
1022
1023                         normalized->bv_val = tmp;
1024
1025                         /* insert the separator */
1026                         normalized->bv_val[normalized->bv_len++] = '#';
1027
1028                         /* append the UID */
1029                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1030                                 uid.bv_val, uid.bv_len );
1031                         normalized->bv_len += uid.bv_len;
1032
1033                         /* terminate */
1034                         normalized->bv_val[normalized->bv_len] = '\0';
1035                 }
1036
1037                 slap_sl_free( out.bv_val, ctx );
1038         }
1039
1040         return LDAP_SUCCESS;
1041 }
1042
1043 static int
1044 uniqueMemberMatch(
1045         int *matchp,
1046         slap_mask_t flags,
1047         Syntax *syntax,
1048         MatchingRule *mr,
1049         struct berval *value,
1050         void *assertedValue )
1051 {
1052         int match;
1053         struct berval *asserted = (struct berval *) assertedValue;
1054         struct berval assertedDN = *asserted;
1055         struct berval assertedUID = BER_BVNULL;
1056         struct berval valueDN = *value;
1057         struct berval valueUID = BER_BVNULL;
1058         int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1059
1060         if ( !BER_BVISEMPTY( asserted ) ) {
1061                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1062                 if ( !BER_BVISNULL( &assertedUID ) ) {
1063                         assertedUID.bv_val++;
1064                         assertedUID.bv_len = assertedDN.bv_len
1065                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1066
1067                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1068                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1069
1070                         } else {
1071                                 BER_BVZERO( &assertedUID );
1072                         }
1073                 }
1074         }
1075
1076         if ( !BER_BVISEMPTY( value ) ) {
1077
1078                 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1079                 if ( !BER_BVISNULL( &valueUID ) ) {
1080                         valueUID.bv_val++;
1081                         valueUID.bv_len = valueDN.bv_len
1082                                 - ( valueUID.bv_val - valueDN.bv_val );
1083
1084                         if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1085                                 valueDN.bv_len -= valueUID.bv_len + 1;
1086
1087                         } else {
1088                                 BER_BVZERO( &valueUID );
1089                         }
1090                 }
1091         }
1092
1093         if( valueUID.bv_len && assertedUID.bv_len ) {
1094                 match = valueUID.bv_len - assertedUID.bv_len;
1095                 if ( match ) {
1096                         *matchp = match;
1097                         return LDAP_SUCCESS;
1098                 }
1099
1100                 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1101                 if( match ) {
1102                         *matchp = match;
1103                         return LDAP_SUCCESS;
1104                 }
1105
1106         } else if ( !approx && valueUID.bv_len ) {
1107                 match = -1;
1108                 *matchp = match;
1109                 return LDAP_SUCCESS;
1110
1111         } else if ( !approx && assertedUID.bv_len ) {
1112                 match = 1;
1113                 *matchp = match;
1114                 return LDAP_SUCCESS;
1115         }
1116
1117         return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1118 }
1119
1120 static int 
1121 uniqueMemberIndexer(
1122         slap_mask_t use,
1123         slap_mask_t flags,
1124         Syntax *syntax,
1125         MatchingRule *mr,
1126         struct berval *prefix,
1127         BerVarray values,
1128         BerVarray *keysp,
1129         void *ctx )
1130 {
1131         BerVarray dnvalues;
1132         int rc;
1133         int i;
1134         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1135                 /* just count them */                 
1136         }
1137         assert( i > 0 );
1138
1139         dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1140
1141         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1142                 struct berval assertedDN = values[i];
1143                 struct berval assertedUID = BER_BVNULL;
1144
1145                 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1146                         assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1147                         if ( !BER_BVISNULL( &assertedUID ) ) {
1148                                 assertedUID.bv_val++;
1149                                 assertedUID.bv_len = assertedDN.bv_len
1150                                         - ( assertedUID.bv_val - assertedDN.bv_val );
1151         
1152                                 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1153                                         assertedDN.bv_len -= assertedUID.bv_len + 1;
1154
1155                                 } else {
1156                                         BER_BVZERO( &assertedUID );
1157                                 }
1158                         }
1159                 }
1160
1161                 dnvalues[i] = assertedDN;
1162         }
1163         BER_BVZERO( &dnvalues[i] );
1164
1165         rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1166                 dnvalues, keysp, ctx );
1167
1168         slap_sl_free( dnvalues, ctx );
1169         return rc;
1170 }
1171
1172 static int 
1173 uniqueMemberFilter(
1174         slap_mask_t use,
1175         slap_mask_t flags,
1176         Syntax *syntax,
1177         MatchingRule *mr,
1178         struct berval *prefix,
1179         void * assertedValue,
1180         BerVarray *keysp,
1181         void *ctx )
1182 {
1183         struct berval *asserted = (struct berval *) assertedValue;
1184         struct berval assertedDN = *asserted;
1185         struct berval assertedUID = BER_BVNULL;
1186
1187         if ( !BER_BVISEMPTY( asserted ) ) {
1188                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1189                 if ( !BER_BVISNULL( &assertedUID ) ) {
1190                         assertedUID.bv_val++;
1191                         assertedUID.bv_len = assertedDN.bv_len
1192                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1193
1194                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1195                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1196
1197                         } else {
1198                                 BER_BVZERO( &assertedUID );
1199                         }
1200                 }
1201         }
1202
1203         return octetStringFilter( use, flags, syntax, mr, prefix,
1204                 &assertedDN, keysp, ctx );
1205 }
1206
1207
1208 /*
1209  * Handling boolean syntax and matching is quite rigid.
1210  * A more flexible approach would be to allow a variety
1211  * of strings to be normalized and prettied into TRUE
1212  * and FALSE.
1213  */
1214 static int
1215 booleanValidate(
1216         Syntax *syntax,
1217         struct berval *in )
1218 {
1219         /* very unforgiving validation, requires no normalization
1220          * before simplistic matching
1221          */
1222
1223         if( in->bv_len == 4 ) {
1224                 if( bvmatch( in, &slap_true_bv ) ) {
1225                         return LDAP_SUCCESS;
1226                 }
1227         } else if( in->bv_len == 5 ) {
1228                 if( bvmatch( in, &slap_false_bv ) ) {
1229                         return LDAP_SUCCESS;
1230                 }
1231         }
1232
1233         return LDAP_INVALID_SYNTAX;
1234 }
1235
1236 static int
1237 booleanMatch(
1238         int *matchp,
1239         slap_mask_t flags,
1240         Syntax *syntax,
1241         MatchingRule *mr,
1242         struct berval *value,
1243         void *assertedValue )
1244 {
1245         /* simplistic matching allowed by rigid validation */
1246         struct berval *asserted = (struct berval *) assertedValue;
1247         *matchp = value->bv_len != asserted->bv_len;
1248         return LDAP_SUCCESS;
1249 }
1250
1251 /*-------------------------------------------------------------------
1252 LDAP/X.500 string syntax / matching rules have a few oddities.  This
1253 comment attempts to detail how slapd(8) treats them.
1254
1255 Summary:
1256   StringSyntax          X.500   LDAP    Matching/Comments
1257   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
1258   PrintableString       subset  subset  i/e + ignore insignificant spaces
1259   PrintableString       subset  subset  i/e + ignore insignificant spaces
1260   NumericString         subset  subset  ignore all spaces
1261   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
1262   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
1263
1264   TelephoneNumber       subset  subset  i + ignore all spaces and "-"
1265
1266   See RFC 4518 for details.
1267
1268
1269 Directory String -
1270   In X.500(93), a directory string can be either a PrintableString,
1271   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1272   In later versions, more CHOICEs were added.  In all cases the string
1273   must be non-empty.
1274
1275   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1276   A directory string cannot be zero length.
1277
1278   For matching, there are both case ignore and exact rules.  Both
1279   also require that "insignificant" spaces be ignored.
1280         spaces before the first non-space are ignored;
1281         spaces after the last non-space are ignored;
1282         spaces after a space are ignored.
1283   Note: by these rules (and as clarified in X.520), a string of only
1284   spaces is to be treated as if held one space, not empty (which
1285   would be a syntax error).
1286
1287 NumericString
1288   In ASN.1, numeric string is just a string of digits and spaces
1289   and could be empty.  However, in X.500, all attribute values of
1290   numeric string carry a non-empty constraint.  For example:
1291
1292         internationalISDNNumber ATTRIBUTE ::= {
1293                 WITH SYNTAX InternationalISDNNumber
1294                 EQUALITY MATCHING RULE numericStringMatch
1295                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1296                 ID id-at-internationalISDNNumber }
1297         InternationalISDNNumber ::=
1298             NumericString (SIZE(1..ub-international-isdn-number))
1299
1300   Unforunately, some assertion values are don't carry the same
1301   constraint (but its unclear how such an assertion could ever
1302   be true). In LDAP, there is one syntax (numericString) not two
1303   (numericString with constraint, numericString without constraint).
1304   This should be treated as numericString with non-empty constraint.
1305   Note that while someone may have no ISDN number, there are no ISDN
1306   numbers which are zero length.
1307
1308   In matching, spaces are ignored.
1309
1310 PrintableString
1311   In ASN.1, Printable string is just a string of printable characters
1312   and can be empty.  In X.500, semantics much like NumericString (see
1313   serialNumber for a like example) excepting uses insignificant space
1314   handling instead of ignore all spaces.  
1315
1316 IA5String
1317   Basically same as PrintableString.  There are no examples in X.500,
1318   but same logic applies.  So we require them to be non-empty as
1319   well.
1320
1321 -------------------------------------------------------------------*/
1322
1323 static int
1324 UTF8StringValidate(
1325         Syntax *syntax,
1326         struct berval *in )
1327 {
1328         ber_len_t count;
1329         int len;
1330         unsigned char *u = (unsigned char *)in->bv_val;
1331
1332         if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1333                 /* directory strings cannot be empty */
1334                 return LDAP_INVALID_SYNTAX;
1335         }
1336
1337         for( count = in->bv_len; count > 0; count -= len, u += len ) {
1338                 /* get the length indicated by the first byte */
1339                 len = LDAP_UTF8_CHARLEN2( u, len );
1340
1341                 /* very basic checks */
1342                 switch( len ) {
1343                         case 6:
1344                                 if( (u[5] & 0xC0) != 0x80 ) {
1345                                         return LDAP_INVALID_SYNTAX;
1346                                 }
1347                         case 5:
1348                                 if( (u[4] & 0xC0) != 0x80 ) {
1349                                         return LDAP_INVALID_SYNTAX;
1350                                 }
1351                         case 4:
1352                                 if( (u[3] & 0xC0) != 0x80 ) {
1353                                         return LDAP_INVALID_SYNTAX;
1354                                 }
1355                         case 3:
1356                                 if( (u[2] & 0xC0 )!= 0x80 ) {
1357                                         return LDAP_INVALID_SYNTAX;
1358                                 }
1359                         case 2:
1360                                 if( (u[1] & 0xC0) != 0x80 ) {
1361                                         return LDAP_INVALID_SYNTAX;
1362                                 }
1363                         case 1:
1364                                 /* CHARLEN already validated it */
1365                                 break;
1366                         default:
1367                                 return LDAP_INVALID_SYNTAX;
1368                 }
1369
1370                 /* make sure len corresponds with the offset
1371                         to the next character */
1372                 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1373         }
1374
1375         if( count != 0 ) {
1376                 return LDAP_INVALID_SYNTAX;
1377         }
1378
1379         return LDAP_SUCCESS;
1380 }
1381
1382 static int
1383 UTF8StringNormalize(
1384         slap_mask_t use,
1385         Syntax *syntax,
1386         MatchingRule *mr,
1387         struct berval *val,
1388         struct berval *normalized,
1389         void *ctx )
1390 {
1391         struct berval tmp, nvalue;
1392         int flags;
1393         int i, wasspace;
1394
1395         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1396
1397         if( BER_BVISNULL( val ) ) {
1398                 /* assume we're dealing with a syntax (e.g., UTF8String)
1399                  * which allows empty strings
1400                  */
1401                 BER_BVZERO( normalized );
1402                 return LDAP_SUCCESS;
1403         }
1404
1405         flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1406                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1407         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1408                 ? LDAP_UTF8_APPROX : 0;
1409
1410         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1411         if( val == NULL ) {
1412                 return LDAP_OTHER;
1413         }
1414         
1415         /* collapse spaces (in place) */
1416         nvalue.bv_len = 0;
1417         nvalue.bv_val = tmp.bv_val;
1418
1419         /* trim leading spaces? */
1420         wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1421                 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1422
1423         for( i = 0; i < tmp.bv_len; i++) {
1424                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1425                         if( wasspace++ == 0 ) {
1426                                 /* trim repeated spaces */
1427                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1428                         }
1429                 } else {
1430                         wasspace = 0;
1431                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1432                 }
1433         }
1434
1435         if( !BER_BVISEMPTY( &nvalue ) ) {
1436                 /* trim trailing space? */
1437                 if( wasspace && (
1438                         (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1439                         ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1440                 {
1441                         --nvalue.bv_len;
1442                 }
1443                 nvalue.bv_val[nvalue.bv_len] = '\0';
1444
1445         } else {
1446                 /* string of all spaces is treated as one space */
1447                 nvalue.bv_val[0] = ' ';
1448                 nvalue.bv_val[1] = '\0';
1449                 nvalue.bv_len = 1;
1450         }
1451
1452         *normalized = nvalue;
1453         return LDAP_SUCCESS;
1454 }
1455
1456 static int
1457 directoryStringSubstringsMatch(
1458         int *matchp,
1459         slap_mask_t flags,
1460         Syntax *syntax,
1461         MatchingRule *mr,
1462         struct berval *value,
1463         void *assertedValue )
1464 {
1465         int match = 0;
1466         SubstringsAssertion *sub = assertedValue;
1467         struct berval left = *value;
1468         int i;
1469         int priorspace=0;
1470
1471         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1472                 if ( sub->sa_initial.bv_len > left.bv_len ) {
1473                         /* not enough left */
1474                         match = 1;
1475                         goto done;
1476                 }
1477
1478                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1479                         sub->sa_initial.bv_len );
1480
1481                 if ( match != 0 ) {
1482                         goto done;
1483                 }
1484
1485                 left.bv_val += sub->sa_initial.bv_len;
1486                 left.bv_len -= sub->sa_initial.bv_len;
1487
1488                 priorspace = ASCII_SPACE(
1489                         sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1490         }
1491
1492         if ( sub->sa_any ) {
1493                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1494                         ber_len_t idx;
1495                         char *p;
1496
1497                         if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] ) 
1498                                 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1499                         { 
1500                                 /* allow next space to match */
1501                                 left.bv_val--;
1502                                 left.bv_len++;
1503                         }
1504                         priorspace=0;
1505
1506 retry:
1507                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1508                                 continue;
1509                         }
1510
1511                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1512                                 /* not enough left */
1513                                 match = 1;
1514                                 goto done;
1515                         }
1516
1517                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1518
1519                         if( p == NULL ) {
1520                                 match = 1;
1521                                 goto done;
1522                         }
1523
1524                         idx = p - left.bv_val;
1525
1526                         if ( idx >= left.bv_len ) {
1527                                 /* this shouldn't happen */
1528                                 return LDAP_OTHER;
1529                         }
1530
1531                         left.bv_val = p;
1532                         left.bv_len -= idx;
1533
1534                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1535                                 /* not enough left */
1536                                 match = 1;
1537                                 goto done;
1538                         }
1539
1540                         match = memcmp( left.bv_val,
1541                                 sub->sa_any[i].bv_val,
1542                                 sub->sa_any[i].bv_len );
1543
1544                         if ( match != 0 ) {
1545                                 left.bv_val++;
1546                                 left.bv_len--;
1547                                 goto retry;
1548                         }
1549
1550                         left.bv_val += sub->sa_any[i].bv_len;
1551                         left.bv_len -= sub->sa_any[i].bv_len;
1552
1553                         priorspace = ASCII_SPACE(
1554                                 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1555                 }
1556         }
1557
1558         if ( !BER_BVISNULL( &sub->sa_final ) ) {
1559                 if( priorspace && !BER_BVISEMPTY( &sub->sa_final ) 
1560                         && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1561                 { 
1562                         /* allow next space to match */
1563                         left.bv_val--;
1564                         left.bv_len++;
1565                 }
1566
1567                 if ( sub->sa_final.bv_len > left.bv_len ) {
1568                         /* not enough left */
1569                         match = 1;
1570                         goto done;
1571                 }
1572
1573                 match = memcmp( sub->sa_final.bv_val,
1574                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1575                         sub->sa_final.bv_len );
1576
1577                 if ( match != 0 ) {
1578                         goto done;
1579                 }
1580         }
1581
1582 done:
1583         *matchp = match;
1584         return LDAP_SUCCESS;
1585 }
1586
1587 #if defined(SLAPD_APPROX_INITIALS)
1588 #       define SLAPD_APPROX_DELIMITER "._ "
1589 #       define SLAPD_APPROX_WORDLEN 2
1590 #else
1591 #       define SLAPD_APPROX_DELIMITER " "
1592 #       define SLAPD_APPROX_WORDLEN 1
1593 #endif
1594
1595 static int
1596 approxMatch(
1597         int *matchp,
1598         slap_mask_t flags,
1599         Syntax *syntax,
1600         MatchingRule *mr,
1601         struct berval *value,
1602         void *assertedValue )
1603 {
1604         struct berval *nval, *assertv;
1605         char *val, **values, **words, *c;
1606         int i, count, len, nextchunk=0, nextavail=0;
1607
1608         /* Yes, this is necessary */
1609         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1610         if( nval == NULL ) {
1611                 *matchp = 1;
1612                 return LDAP_SUCCESS;
1613         }
1614
1615         /* Yes, this is necessary */
1616         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1617                 NULL, LDAP_UTF8_APPROX, NULL );
1618         if( assertv == NULL ) {
1619                 ber_bvfree( nval );
1620                 *matchp = 1;
1621                 return LDAP_SUCCESS;
1622         }
1623
1624         /* Isolate how many words there are */
1625         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1626                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1627                 if ( c == NULL ) break;
1628                 *c = '\0';
1629                 count++;
1630         }
1631
1632         /* Get a phonetic copy of each word */
1633         words = (char **)ch_malloc( count * sizeof(char *) );
1634         values = (char **)ch_malloc( count * sizeof(char *) );
1635         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1636                 words[i] = c;
1637                 values[i] = phonetic(c);
1638         }
1639
1640         /* Work through the asserted value's words, to see if at least some
1641            of the words are there, in the same order. */
1642         len = 0;
1643         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1644                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1645                 if( len == 0 ) {
1646                         nextchunk++;
1647                         continue;
1648                 }
1649 #if defined(SLAPD_APPROX_INITIALS)
1650                 else if( len == 1 ) {
1651                         /* Single letter words need to at least match one word's initial */
1652                         for( i=nextavail; i<count; i++ )
1653                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1654                                         nextavail=i+1;
1655                                         break;
1656                                 }
1657                 }
1658 #endif
1659                 else {
1660                         /* Isolate the next word in the asserted value and phonetic it */
1661                         assertv->bv_val[nextchunk+len] = '\0';
1662                         val = phonetic( assertv->bv_val + nextchunk );
1663
1664                         /* See if this phonetic chunk is in the remaining words of *value */
1665                         for( i=nextavail; i<count; i++ ){
1666                                 if( !strcmp( val, values[i] ) ){
1667                                         nextavail = i+1;
1668                                         break;
1669                                 }
1670                         }
1671                         ch_free( val );
1672                 }
1673
1674                 /* This chunk in the asserted value was NOT within the *value. */
1675                 if( i >= count ) {
1676                         nextavail=-1;
1677                         break;
1678                 }
1679
1680                 /* Go on to the next word in the asserted value */
1681                 nextchunk += len+1;
1682         }
1683
1684         /* If some of the words were seen, call it a match */
1685         if( nextavail > 0 ) {
1686                 *matchp = 0;
1687         }
1688         else {
1689                 *matchp = 1;
1690         }
1691
1692         /* Cleanup allocs */
1693         ber_bvfree( assertv );
1694         for( i=0; i<count; i++ ) {
1695                 ch_free( values[i] );
1696         }
1697         ch_free( values );
1698         ch_free( words );
1699         ber_bvfree( nval );
1700
1701         return LDAP_SUCCESS;
1702 }
1703
1704 static int 
1705 approxIndexer(
1706         slap_mask_t use,
1707         slap_mask_t flags,
1708         Syntax *syntax,
1709         MatchingRule *mr,
1710         struct berval *prefix,
1711         BerVarray values,
1712         BerVarray *keysp,
1713         void *ctx )
1714 {
1715         char *c;
1716         int i,j, len, wordcount, keycount=0;
1717         struct berval *newkeys;
1718         BerVarray keys=NULL;
1719
1720         for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1721                 struct berval val = BER_BVNULL;
1722                 /* Yes, this is necessary */
1723                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1724                 assert( !BER_BVISNULL( &val ) );
1725
1726                 /* Isolate how many words there are. There will be a key for each */
1727                 for( wordcount = 0, c = val.bv_val; *c; c++) {
1728                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
1729                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1730                         c+= len;
1731                         if (*c == '\0') break;
1732                         *c = '\0';
1733                 }
1734
1735                 /* Allocate/increase storage to account for new keys */
1736                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
1737                         * sizeof(struct berval) );
1738                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1739                 if( keys ) ch_free( keys );
1740                 keys = newkeys;
1741
1742                 /* Get a phonetic copy of each word */
1743                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1744                         len = strlen( c );
1745                         if( len < SLAPD_APPROX_WORDLEN ) continue;
1746                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1747                         keycount++;
1748                         i++;
1749                 }
1750
1751                 ber_memfree( val.bv_val );
1752         }
1753         BER_BVZERO( &keys[keycount] );
1754         *keysp = keys;
1755
1756         return LDAP_SUCCESS;
1757 }
1758
1759 static int 
1760 approxFilter(
1761         slap_mask_t use,
1762         slap_mask_t flags,
1763         Syntax *syntax,
1764         MatchingRule *mr,
1765         struct berval *prefix,
1766         void * assertedValue,
1767         BerVarray *keysp,
1768         void *ctx )
1769 {
1770         char *c;
1771         int i, count, len;
1772         struct berval *val;
1773         BerVarray keys;
1774
1775         /* Yes, this is necessary */
1776         val = UTF8bvnormalize( ((struct berval *)assertedValue),
1777                 NULL, LDAP_UTF8_APPROX, NULL );
1778         if( val == NULL || BER_BVISNULL( val ) ) {
1779                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1780                 BER_BVZERO( &keys[0] );
1781                 *keysp = keys;
1782                 ber_bvfree( val );
1783                 return LDAP_SUCCESS;
1784         }
1785
1786         /* Isolate how many words there are. There will be a key for each */
1787         for( count = 0,c = val->bv_val; *c; c++) {
1788                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1789                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1790                 c+= len;
1791                 if (*c == '\0') break;
1792                 *c = '\0';
1793         }
1794
1795         /* Allocate storage for new keys */
1796         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1797
1798         /* Get a phonetic copy of each word */
1799         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1800                 len = strlen(c);
1801                 if( len < SLAPD_APPROX_WORDLEN ) continue;
1802                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1803                 i++;
1804         }
1805
1806         ber_bvfree( val );
1807
1808         BER_BVZERO( &keys[count] );
1809         *keysp = keys;
1810
1811         return LDAP_SUCCESS;
1812 }
1813
1814 /* Remove all spaces and '-' characters */
1815 static int
1816 telephoneNumberNormalize(
1817         slap_mask_t usage,
1818         Syntax *syntax,
1819         MatchingRule *mr,
1820         struct berval *val,
1821         struct berval *normalized,
1822         void *ctx )
1823 {
1824         char *p, *q;
1825
1826         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1827
1828         /* validator should have refused an empty string */
1829         assert( !BER_BVISEMPTY( val ) );
1830
1831         q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1832
1833         for( p = val->bv_val; *p; p++ ) {
1834                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1835                         *q++ = *p;
1836                 }
1837         }
1838         *q = '\0';
1839
1840         normalized->bv_len = q - normalized->bv_val;
1841
1842         if( BER_BVISEMPTY( normalized ) ) {
1843                 slap_sl_free( normalized->bv_val, ctx );
1844                 BER_BVZERO( normalized );
1845                 return LDAP_INVALID_SYNTAX;
1846         }
1847
1848         return LDAP_SUCCESS;
1849 }
1850
1851 int
1852 numericoidValidate(
1853         Syntax *syntax,
1854         struct berval *in )
1855 {
1856         struct berval val = *in;
1857
1858         if( BER_BVISEMPTY( &val ) ) {
1859                 /* disallow empty strings */
1860                 return LDAP_INVALID_SYNTAX;
1861         }
1862
1863         while( OID_LEADCHAR( val.bv_val[0] ) ) {
1864                 if ( val.bv_len == 1 ) {
1865                         return LDAP_SUCCESS;
1866                 }
1867
1868                 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
1869                         break;
1870                 }
1871
1872                 val.bv_val++;
1873                 val.bv_len--;
1874
1875                 while ( OID_LEADCHAR( val.bv_val[0] )) {
1876                         val.bv_val++;
1877                         val.bv_len--;
1878
1879                         if ( val.bv_len == 0 ) {
1880                                 return LDAP_SUCCESS;
1881                         }
1882                 }
1883
1884                 if( !OID_SEPARATOR( val.bv_val[0] )) {
1885                         break;
1886                 }
1887
1888                 val.bv_val++;
1889                 val.bv_len--;
1890         }
1891
1892         return LDAP_INVALID_SYNTAX;
1893 }
1894
1895 static int
1896 integerValidate(
1897         Syntax *syntax,
1898         struct berval *in )
1899 {
1900         ber_len_t i;
1901         struct berval val = *in;
1902
1903         if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
1904
1905         if ( val.bv_val[0] == '-' ) {
1906                 val.bv_len--;
1907                 val.bv_val++;
1908
1909                 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
1910                         return LDAP_INVALID_SYNTAX;
1911                 }
1912
1913                 if( val.bv_val[0] == '0' ) { /* "-0" */
1914                         return LDAP_INVALID_SYNTAX;
1915                 }
1916
1917         } else if ( val.bv_val[0] == '0' ) {
1918                 if( val.bv_len > 1 ) { /* "0<more>" */
1919                         return LDAP_INVALID_SYNTAX;
1920                 }
1921
1922                 return LDAP_SUCCESS;
1923         }
1924
1925         for( i=0; i < val.bv_len; i++ ) {
1926                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
1927                         return LDAP_INVALID_SYNTAX;
1928                 }
1929         }
1930
1931         return LDAP_SUCCESS;
1932 }
1933
1934 static int
1935 integerMatch(
1936         int *matchp,
1937         slap_mask_t flags,
1938         Syntax *syntax,
1939         MatchingRule *mr,
1940         struct berval *value,
1941         void *assertedValue )
1942 {
1943         struct berval *asserted = (struct berval *) assertedValue;
1944         int vsign = 1, asign = 1;       /* default sign = '+' */
1945         struct berval v, a;
1946         int match;
1947
1948         v = *value;
1949         if( v.bv_val[0] == '-' ) {
1950                 vsign = -1;
1951                 v.bv_val++;
1952                 v.bv_len--;
1953         }
1954
1955         if( BER_BVISEMPTY( &v ) ) vsign = 0;
1956
1957         a = *asserted;
1958         if( a.bv_val[0] == '-' ) {
1959                 asign = -1;
1960                 a.bv_val++;
1961                 a.bv_len--;
1962         }
1963
1964         if( BER_BVISEMPTY( &a ) ) vsign = 0;
1965
1966         match = vsign - asign;
1967         if( match == 0 ) {
1968                 match = ( v.bv_len != a.bv_len
1969                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
1970                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
1971                 if( vsign < 0 ) match = -match;
1972         }
1973
1974         *matchp = match;
1975         return LDAP_SUCCESS;
1976 }
1977         
1978 static int
1979 countryStringValidate(
1980         Syntax *syntax,
1981         struct berval *val )
1982 {
1983         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
1984
1985         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
1986                 return LDAP_INVALID_SYNTAX;
1987         }
1988         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
1989                 return LDAP_INVALID_SYNTAX;
1990         }
1991
1992         return LDAP_SUCCESS;
1993 }
1994
1995 static int
1996 printableStringValidate(
1997         Syntax *syntax,
1998         struct berval *val )
1999 {
2000         ber_len_t i;
2001
2002         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2003
2004         for(i=0; i < val->bv_len; i++) {
2005                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2006                         return LDAP_INVALID_SYNTAX;
2007                 }
2008         }
2009
2010         return LDAP_SUCCESS;
2011 }
2012
2013 static int
2014 printablesStringValidate(
2015         Syntax *syntax,
2016         struct berval *val )
2017 {
2018         ber_len_t i, len;
2019
2020         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2021
2022         for(i=0,len=0; i < val->bv_len; i++) {
2023                 int c = val->bv_val[i];
2024
2025                 if( c == '$' ) {
2026                         if( len == 0 ) {
2027                                 return LDAP_INVALID_SYNTAX;
2028                         }
2029                         len = 0;
2030
2031                 } else if ( SLAP_PRINTABLE(c) ) {
2032                         len++;
2033                 } else {
2034                         return LDAP_INVALID_SYNTAX;
2035                 }
2036         }
2037
2038         if( len == 0 ) {
2039                 return LDAP_INVALID_SYNTAX;
2040         }
2041
2042         return LDAP_SUCCESS;
2043 }
2044
2045 static int
2046 IA5StringValidate(
2047         Syntax *syntax,
2048         struct berval *val )
2049 {
2050         ber_len_t i;
2051
2052         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2053
2054         for(i=0; i < val->bv_len; i++) {
2055                 if( !LDAP_ASCII(val->bv_val[i]) ) {
2056                         return LDAP_INVALID_SYNTAX;
2057                 }
2058         }
2059
2060         return LDAP_SUCCESS;
2061 }
2062
2063 static int
2064 IA5StringNormalize(
2065         slap_mask_t use,
2066         Syntax *syntax,
2067         MatchingRule *mr,
2068         struct berval *val,
2069         struct berval *normalized,
2070         void *ctx )
2071 {
2072         char *p, *q;
2073         int casefold = !SLAP_MR_ASSOCIATED( mr,
2074                 slap_schema.si_mr_caseExactIA5Match );
2075
2076         assert( !BER_BVISEMPTY( val ) );
2077
2078         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2079
2080         p = val->bv_val;
2081
2082         /* Ignore initial whitespace */
2083         while ( ASCII_SPACE( *p ) ) p++;
2084
2085         normalized->bv_val = ber_strdup_x( p, ctx );
2086         p = q = normalized->bv_val;
2087
2088         while ( *p ) {
2089                 if ( ASCII_SPACE( *p ) ) {
2090                         *q++ = *p++;
2091
2092                         /* Ignore the extra whitespace */
2093                         while ( ASCII_SPACE( *p ) ) {
2094                                 p++;
2095                         }
2096
2097                 } else if ( casefold ) {
2098                         /* Most IA5 rules require casefolding */
2099                         *q++ = TOLOWER(*p); p++;
2100
2101                 } else {
2102                         *q++ = *p++;
2103                 }
2104         }
2105
2106         assert( normalized->bv_val <= p );
2107         assert( q <= p );
2108
2109         /*
2110          * If the string ended in space, backup the pointer one
2111          * position.  One is enough because the above loop collapsed
2112          * all whitespace to a single space.
2113          */
2114         if ( ASCII_SPACE( q[-1] ) ) --q;
2115
2116         /* null terminate */
2117         *q = '\0';
2118
2119         normalized->bv_len = q - normalized->bv_val;
2120         if( BER_BVISEMPTY( normalized ) ) {
2121                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2122                 normalized->bv_val[0] = ' ';
2123                 normalized->bv_val[1] = '\0';
2124                 normalized->bv_len = 1;
2125         }
2126
2127         return LDAP_SUCCESS;
2128 }
2129
2130 static int
2131 UUIDValidate(
2132         Syntax *syntax,
2133         struct berval *in )
2134 {
2135         int i;
2136         if( in->bv_len != 36 ) {
2137                 return LDAP_INVALID_SYNTAX;
2138         }
2139
2140         for( i=0; i<36; i++ ) {
2141                 switch(i) {
2142                         case 8:
2143                         case 13:
2144                         case 18:
2145                         case 23:
2146                                 if( in->bv_val[i] != '-' ) {
2147                                         return LDAP_INVALID_SYNTAX;
2148                                 }
2149                                 break;
2150                         default:
2151                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2152                                         return LDAP_INVALID_SYNTAX;
2153                                 }
2154                 }
2155         }
2156         
2157         return LDAP_SUCCESS;
2158 }
2159
2160 static int
2161 UUIDPretty(
2162         Syntax *syntax,
2163         struct berval *in,
2164         struct berval *out,
2165         void *ctx )
2166 {
2167         int i;
2168         int rc=LDAP_INVALID_SYNTAX;
2169
2170         assert( in != NULL );
2171         assert( out != NULL );
2172
2173         if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2174
2175         out->bv_len = 36;
2176         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2177
2178         for( i=0; i<36; i++ ) {
2179                 switch(i) {
2180                         case 8:
2181                         case 13:
2182                         case 18:
2183                         case 23:
2184                                 if( in->bv_val[i] != '-' ) {
2185                                         goto handle_error;
2186                                 }
2187                                 out->bv_val[i] = '-';
2188                                 break;
2189
2190                         default:
2191                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2192                                         goto handle_error;
2193                                 }
2194                                 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2195                 }
2196         }
2197
2198         rc = LDAP_SUCCESS;
2199         out->bv_val[ out->bv_len ] = '\0';
2200
2201         if( 0 ) {
2202 handle_error:
2203                 slap_sl_free( out->bv_val, ctx );
2204                 out->bv_val = NULL;
2205         }
2206
2207         return rc;
2208 }
2209
2210 int
2211 UUIDNormalize(
2212         slap_mask_t usage,
2213         Syntax *syntax,
2214         MatchingRule *mr,
2215         struct berval *val,
2216         struct berval *normalized,
2217         void *ctx )
2218 {
2219         unsigned char octet = '\0';
2220         int i;
2221         int j;
2222         normalized->bv_len = 16;
2223         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2224
2225         for( i=0, j=0; i<36; i++ ) {
2226                 unsigned char nibble;
2227                 if( val->bv_val[i] == '-' ) {
2228                         continue;
2229
2230                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2231                         nibble = val->bv_val[i] - '0';
2232
2233                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2234                         nibble = val->bv_val[i] - ('a'-10);
2235
2236                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2237                         nibble = val->bv_val[i] - ('A'-10);
2238
2239                 } else {
2240                         slap_sl_free( normalized->bv_val, ctx );
2241                         return LDAP_INVALID_SYNTAX;
2242                 }
2243
2244                 if( j & 1 ) {
2245                         octet |= nibble;
2246                         normalized->bv_val[j>>1] = octet;
2247                 } else {
2248                         octet = nibble << 4;
2249                 }
2250                 j++;
2251         }
2252
2253         normalized->bv_val[normalized->bv_len] = 0;
2254         return LDAP_SUCCESS;
2255 }
2256
2257
2258
2259 static int
2260 numericStringValidate(
2261         Syntax *syntax,
2262         struct berval *in )
2263 {
2264         ber_len_t i;
2265
2266         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2267
2268         for(i=0; i < in->bv_len; i++) {
2269                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2270                         return LDAP_INVALID_SYNTAX;
2271                 }
2272         }
2273
2274         return LDAP_SUCCESS;
2275 }
2276
2277 static int
2278 numericStringNormalize(
2279         slap_mask_t usage,
2280         Syntax *syntax,
2281         MatchingRule *mr,
2282         struct berval *val,
2283         struct berval *normalized,
2284         void *ctx )
2285 {
2286         /* removal all spaces */
2287         char *p, *q;
2288
2289         assert( !BER_BVISEMPTY( val ) );
2290
2291         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2292
2293         p = val->bv_val;
2294         q = normalized->bv_val;
2295
2296         while ( *p ) {
2297                 if ( ASCII_SPACE( *p ) ) {
2298                         /* Ignore whitespace */
2299                         p++;
2300                 } else {
2301                         *q++ = *p++;
2302                 }
2303         }
2304
2305         /* we should have copied no more then is in val */
2306         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2307
2308         /* null terminate */
2309         *q = '\0';
2310
2311         normalized->bv_len = q - normalized->bv_val;
2312
2313         if( BER_BVISEMPTY( normalized ) ) {
2314                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2315                 normalized->bv_val[0] = ' ';
2316                 normalized->bv_val[1] = '\0';
2317                 normalized->bv_len = 1;
2318         }
2319
2320         return LDAP_SUCCESS;
2321 }
2322
2323 /*
2324  * Integer conversion macros that will use the largest available
2325  * type.
2326  */
2327 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2328 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2329 # define SLAP_LONG           long long
2330 #else
2331 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2332 # define SLAP_LONG           long
2333 #endif /* HAVE_STRTOLL ... */
2334
2335 static int
2336 integerBitAndMatch(
2337         int *matchp,
2338         slap_mask_t flags,
2339         Syntax *syntax,
2340         MatchingRule *mr,
2341         struct berval *value,
2342         void *assertedValue )
2343 {
2344         SLAP_LONG lValue, lAssertedValue;
2345
2346         errno = 0;
2347         /* safe to assume integers are NUL terminated? */
2348         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2349         if( errno == ERANGE )
2350         {
2351                 return LDAP_CONSTRAINT_VIOLATION;
2352         }
2353
2354         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2355                 NULL, 10);
2356         if( errno == ERANGE )
2357         {
2358                 return LDAP_CONSTRAINT_VIOLATION;
2359         }
2360
2361         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2362         return LDAP_SUCCESS;
2363 }
2364
2365 static int
2366 integerBitOrMatch(
2367         int *matchp,
2368         slap_mask_t flags,
2369         Syntax *syntax,
2370         MatchingRule *mr,
2371         struct berval *value,
2372         void *assertedValue )
2373 {
2374         SLAP_LONG lValue, lAssertedValue;
2375
2376         errno = 0;
2377         /* safe to assume integers are NUL terminated? */
2378         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2379         if( errno == ERANGE )
2380         {
2381                 return LDAP_CONSTRAINT_VIOLATION;
2382         }
2383
2384         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2385                 NULL, 10);
2386         if( errno == ERANGE )
2387         {
2388                 return LDAP_CONSTRAINT_VIOLATION;
2389         }
2390
2391         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2392         return LDAP_SUCCESS;
2393 }
2394
2395 static int
2396 serialNumberAndIssuerValidate(
2397         Syntax *syntax,
2398         struct berval *in )
2399 {
2400         int rc;
2401         ber_len_t n;
2402         struct berval sn, i;
2403
2404         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
2405                 in->bv_val, 0, 0 );
2406
2407         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2408
2409         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2410                 /* Parse old format */
2411                 i.bv_val = ber_bvchr( in, '$' );
2412                 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2413
2414                 sn.bv_val = in->bv_val;
2415                 sn.bv_len = i.bv_val - in->bv_val;
2416
2417                 i.bv_val++;
2418                 i.bv_len = in->bv_len - (sn.bv_len + 1);
2419
2420                 /* eat leading zeros */
2421                 for( n=0; n < (sn.bv_len-1); n++ ) {
2422                         if( sn.bv_val[n] != '0' ) break;
2423                 }
2424                 sn.bv_val += n;
2425                 sn.bv_len -= n;
2426
2427                 for( n=0; n < sn.bv_len; n++ ) {
2428                         if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2429                 }
2430
2431         } else {
2432                 /* Parse GSER format */ 
2433                 int havesn=0,haveissuer=0;
2434                 struct berval x = *in;
2435                 x.bv_val++;
2436                 x.bv_len-=2;
2437
2438                 /* eat leading spaces */
2439                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2440                         /* empty */;
2441                 }
2442
2443                 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2444                         return LDAP_INVALID_SYNTAX;
2445                 }
2446
2447                 /* should be at issuer or serialNumber NamedValue */
2448                 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2449                         /* parse issuer */
2450                         x.bv_val += STRLENOF("issuer");
2451                         x.bv_len -= STRLENOF("issuer");
2452
2453                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2454                         x.bv_val++; x.bv_len--;
2455
2456                         /* eat leading spaces */
2457                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2458                                 /* empty */;
2459                         }
2460                         
2461                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2462                         x.bv_val++; x.bv_len--;
2463
2464                         i.bv_val = x.bv_val;
2465                         i.bv_len = 0;
2466
2467                         for( ; i.bv_len < x.bv_len; ) {
2468                                 if ( i.bv_val[i.bv_len] != '"' ) {
2469                                         i.bv_len++;
2470                                         continue;
2471                                 }
2472                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2473                                         /* double dquote */
2474                                         i.bv_len+=2;
2475                                         continue;
2476                                 }
2477                                 break;
2478                         }
2479                         x.bv_val += i.bv_len+1;
2480                         x.bv_len -= i.bv_len+1;
2481
2482                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2483                                 return LDAP_INVALID_SYNTAX;
2484                         }
2485
2486                         haveissuer++;
2487
2488                 } else if( strncasecmp( x.bv_val, "serialNumber",
2489                         STRLENOF("serialNumber")) == 0 )
2490                 {
2491                         /* parse serialNumber */
2492                         int neg=0;
2493                         x.bv_val += STRLENOF("serialNumber");
2494                         x.bv_len -= STRLENOF("serialNumber");
2495
2496                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2497                         x.bv_val++; x.bv_len--;
2498
2499                         /* eat leading spaces */
2500                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2501                                 /* empty */;
2502                         }
2503                         
2504                         sn.bv_val = x.bv_val;
2505                         sn.bv_len = 0;
2506
2507                         if( sn.bv_val[0] == '-' ) {
2508                                 neg++;
2509                                 sn.bv_len++;
2510                         }
2511
2512                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2513                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2514                         }
2515
2516                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2517                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2518                                 return LDAP_INVALID_SYNTAX;
2519                         }
2520
2521                         x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
2522
2523                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2524                                 return LDAP_INVALID_SYNTAX;
2525                         }
2526
2527                         havesn++;
2528
2529                 } else return LDAP_INVALID_SYNTAX;
2530
2531                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2532                 x.bv_val++; x.bv_len--;
2533
2534                 /* eat spaces */
2535                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2536                         /* empty */;
2537                 }
2538
2539                 /* should be at remaining NamedValue */
2540                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2541                         STRLENOF("issuer" )) == 0 ))
2542                 {
2543                         /* parse issuer */
2544                         x.bv_val += STRLENOF("issuer");
2545                         x.bv_len -= STRLENOF("issuer");
2546
2547                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2548                         x.bv_val++; x.bv_len--;
2549
2550                         /* eat leading spaces */
2551                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2552                                  /* empty */;
2553                         }
2554                         
2555                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2556                         x.bv_val++; x.bv_len--;
2557
2558                         i.bv_val = x.bv_val;
2559                         i.bv_len = 0;
2560
2561                         for( ; i.bv_len < x.bv_len; ) {
2562                                 if ( i.bv_val[i.bv_len] != '"' ) {
2563                                         i.bv_len++;
2564                                         continue;
2565                                 }
2566                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2567                                         /* double dquote */
2568                                         i.bv_len+=2;
2569                                         continue;
2570                                 }
2571                                 break;
2572                         }
2573                         x.bv_val += i.bv_len+1;
2574                         x.bv_len -= i.bv_len+1;
2575
2576                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2577                         STRLENOF("serialNumber")) == 0 ))
2578                 {
2579                         /* parse serialNumber */
2580                         int neg=0;
2581                         x.bv_val += STRLENOF("serialNumber");
2582                         x.bv_len -= STRLENOF("serialNumber");
2583
2584                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2585                         x.bv_val++; x.bv_len--;
2586
2587                         /* eat leading spaces */
2588                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2589                                 /* empty */;
2590                         }
2591                         
2592                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2593                         x.bv_val++; x.bv_len--;
2594
2595                         sn.bv_val = x.bv_val;
2596                         sn.bv_len = 0;
2597
2598                         if( sn.bv_val[0] == '-' ) {
2599                                 neg++;
2600                                 sn.bv_len++;
2601                         }
2602
2603                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2604                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2605                         }
2606
2607                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2608                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2609                                 return LDAP_INVALID_SYNTAX;
2610                         }
2611
2612                         x.bv_val += sn.bv_len;
2613                         x.bv_len -= sn.bv_len;
2614
2615                 } else return LDAP_INVALID_SYNTAX;
2616
2617                 /* eat trailing spaces */
2618                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2619                         /* empty */;
2620                 }
2621
2622                 /* should have no characters left... */
2623                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2624         }
2625
2626         /* validate DN -- doesn't handle double dquote */ 
2627         rc = dnValidate( NULL, &i );
2628         if( rc ) return LDAP_INVALID_SYNTAX;
2629
2630         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: OKAY\n",
2631                 in->bv_val, 0, 0 );
2632         return LDAP_SUCCESS;
2633 }
2634
2635 int
2636 serialNumberAndIssuerPretty(
2637         Syntax *syntax,
2638         struct berval *in,
2639         struct berval *out,
2640         void *ctx )
2641 {
2642         int rc;
2643         ber_len_t n;
2644         struct berval sn, i, ni;
2645
2646         assert( in != NULL );
2647         assert( out != NULL );
2648
2649         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2650                 in->bv_val, 0, 0 );
2651
2652         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2653
2654         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2655                 /* Parse old format */
2656                 i.bv_val = ber_bvchr( in, '$' );
2657                 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2658
2659                 sn.bv_val = in->bv_val;
2660                 sn.bv_len = i.bv_val - in->bv_val;
2661
2662                 i.bv_val++;
2663                 i.bv_len = in->bv_len - (sn.bv_len + 1);
2664
2665                 /* eat leading zeros */
2666                 for( n=0; n < (sn.bv_len-1); n++ ) {
2667                         if( sn.bv_val[n] != '0' ) break;
2668                 }
2669                 sn.bv_val += n;
2670                 sn.bv_len -= n;
2671
2672                 for( n=0; n < sn.bv_len; n++ ) {
2673                         if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2674                 }
2675
2676         } else {
2677                 /* Parse GSER format */ 
2678                 int havesn=0,haveissuer=0;
2679                 struct berval x = *in;
2680                 x.bv_val++;
2681                 x.bv_len-=2;
2682
2683                 /* eat leading spaces */
2684                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2685                         /* empty */;
2686                 }
2687
2688                 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2689                         return LDAP_INVALID_SYNTAX;
2690                 }
2691
2692                 /* should be at issuer or serialNumber NamedValue */
2693                 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2694                         /* parse issuer */
2695                         x.bv_val += STRLENOF("issuer");
2696                         x.bv_len -= STRLENOF("issuer");
2697
2698                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2699                         x.bv_val++; x.bv_len--;
2700
2701                         /* eat leading spaces */
2702                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2703                                 /* empty */;
2704                         }
2705                         
2706                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2707                         x.bv_val++; x.bv_len--;
2708
2709                         i.bv_val = x.bv_val;
2710                         i.bv_len = 0;
2711
2712                         for( ; i.bv_len < x.bv_len; ) {
2713                                 if ( i.bv_val[i.bv_len] != '"' ) {
2714                                         i.bv_len++;
2715                                         continue;
2716                                 }
2717                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2718                                         /* double dquote */
2719                                         i.bv_len+=2;
2720                                         continue;
2721                                 }
2722                                 break;
2723                         }
2724                         x.bv_val += i.bv_len+1;
2725                         x.bv_len -= i.bv_len+1;
2726
2727                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2728                                 return LDAP_INVALID_SYNTAX;
2729                         }
2730
2731                         haveissuer++;
2732
2733                 } else if( strncasecmp( x.bv_val, "serialNumber",
2734                         STRLENOF("serialNumber")) == 0 )
2735                 {
2736                         /* parse serialNumber */
2737                         int neg=0;
2738                         x.bv_val += STRLENOF("serialNumber");
2739                         x.bv_len -= STRLENOF("serialNumber");
2740
2741                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2742                         x.bv_val++; x.bv_len--;
2743
2744                         /* eat leading spaces */
2745                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2746                                 /* empty */;
2747                         }
2748                         
2749                         sn.bv_val = x.bv_val;
2750                         sn.bv_len = 0;
2751
2752                         if( sn.bv_val[0] == '-' ) {
2753                                 neg++;
2754                                 sn.bv_len++;
2755                         }
2756
2757                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2758                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2759                         }
2760
2761                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2762                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2763                                 return LDAP_INVALID_SYNTAX;
2764                         }
2765
2766                         x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
2767
2768                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2769                                 return LDAP_INVALID_SYNTAX;
2770                         }
2771
2772                         havesn++;
2773
2774                 } else return LDAP_INVALID_SYNTAX;
2775
2776                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2777                 x.bv_val++; x.bv_len--;
2778
2779                 /* eat spaces */
2780                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2781                         /* empty */;
2782                 }
2783
2784                 /* should be at remaining NamedValue */
2785                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2786                         STRLENOF("issuer" )) == 0 ))
2787                 {
2788                         /* parse issuer */
2789                         x.bv_val += STRLENOF("issuer");
2790                         x.bv_len -= STRLENOF("issuer");
2791
2792                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2793                         x.bv_val++; x.bv_len--;
2794
2795                         /* eat leading spaces */
2796                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2797                                  /* empty */;
2798                         }
2799                         
2800                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2801                         x.bv_val++; x.bv_len--;
2802
2803                         i.bv_val = x.bv_val;
2804                         i.bv_len = 0;
2805
2806                         for( ; i.bv_len < x.bv_len; ) {
2807                                 if ( i.bv_val[i.bv_len] != '"' ) {
2808                                         i.bv_len++;
2809                                         continue;
2810                                 }
2811                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2812                                         /* double dquote */
2813                                         i.bv_len+=2;
2814                                         continue;
2815                                 }
2816                                 break;
2817                         }
2818                         x.bv_val += i.bv_len+1;
2819                         x.bv_len -= i.bv_len+1;
2820
2821                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2822                         STRLENOF("serialNumber")) == 0 ))
2823                 {
2824                         /* parse serialNumber */
2825                         int neg=0;
2826                         x.bv_val += STRLENOF("serialNumber");
2827                         x.bv_len -= STRLENOF("serialNumber");
2828
2829                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2830                         x.bv_val++; x.bv_len--;
2831
2832                         /* eat leading spaces */
2833                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2834                                 /* empty */;
2835                         }
2836                         
2837                         sn.bv_val = x.bv_val;
2838                         sn.bv_len = 0;
2839
2840                         if( sn.bv_val[0] == '-' ) {
2841                                 neg++;
2842                                 sn.bv_len++;
2843                         }
2844
2845                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2846                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2847                         }
2848
2849                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2850                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2851                                 return LDAP_INVALID_SYNTAX;
2852                         }
2853
2854                         x.bv_val += sn.bv_len;
2855                         x.bv_len -= sn.bv_len;
2856
2857                 } else return LDAP_INVALID_SYNTAX;
2858
2859                 /* eat trailing spaces */
2860                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2861                         /* empty */;
2862                 }
2863
2864                 /* should have no characters left... */
2865                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2866
2867                 ber_dupbv_x( &ni, &i, ctx );
2868                 i = ni;
2869
2870                 /* need to handle double dquotes here */
2871         }
2872
2873         rc = dnPretty( syntax, &i, &ni, ctx );
2874
2875         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
2876                 slap_sl_free( i.bv_val, ctx );
2877         }
2878
2879         if( rc ) return LDAP_INVALID_SYNTAX;
2880
2881         /* make room from sn + "$" */
2882         out->bv_len = STRLENOF("{ serialNumber , issuer \"\" }")
2883                 + sn.bv_len + ni.bv_len;
2884         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2885
2886         if( out->bv_val == NULL ) {
2887                 out->bv_len = 0;
2888                 slap_sl_free( ni.bv_val, ctx );
2889                 return LDAP_OTHER;
2890         }
2891
2892         n = 0;
2893         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
2894                 STRLENOF("{ serialNumber "));
2895         n = STRLENOF("{ serialNumber ");
2896
2897         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
2898         n += sn.bv_len;
2899
2900         AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF(", issuer \""));
2901         n += STRLENOF(", issuer \"");
2902
2903         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
2904         n += ni.bv_len;
2905
2906         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
2907         n += STRLENOF("\" }");
2908
2909         out->bv_val[n] = '\0';
2910
2911         assert( n == out->bv_len );
2912
2913         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2914                 out->bv_val, 0, 0 );
2915
2916         slap_sl_free( ni.bv_val, ctx );
2917
2918         return LDAP_SUCCESS; 
2919 }
2920
2921 /*
2922  * This routine is called by certificateExactNormalize when
2923  * certificateExactNormalize receives a search string instead of
2924  * a certificate. This routine checks if the search value is valid
2925  * and then returns the normalized value
2926  */
2927 static int
2928 serialNumberAndIssuerNormalize(
2929         slap_mask_t usage,
2930         Syntax *syntax,
2931         MatchingRule *mr,
2932         struct berval *in,
2933         struct berval *out,
2934         void *ctx )
2935 {
2936         int rc;
2937         ber_len_t n;
2938         struct berval sn, i, ni;
2939
2940         assert( in != NULL );
2941         assert( out != NULL );
2942
2943         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2944                 in->bv_val, 0, 0 );
2945
2946         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2947
2948         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2949                 /* Parse old format */
2950                 i.bv_val = ber_bvchr( in, '$' );
2951                 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2952
2953                 sn.bv_val = in->bv_val;
2954                 sn.bv_len = i.bv_val - in->bv_val;
2955
2956                 i.bv_val++;
2957                 i.bv_len = in->bv_len - (sn.bv_len + 1);
2958
2959                 /* eat leading zeros */
2960                 for( n=0; n < (sn.bv_len-1); n++ ) {
2961                         if( sn.bv_val[n] != '0' ) break;
2962                 }
2963                 sn.bv_val += n;
2964                 sn.bv_len -= n;
2965
2966                 for( n=0; n < sn.bv_len; n++ ) {
2967                         if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2968                 }
2969
2970         } else {
2971                 /* Parse GSER format */ 
2972                 int havesn=0,haveissuer=0;
2973                 struct berval x = *in;
2974                 x.bv_val++;
2975                 x.bv_len-=2;
2976
2977                 /* eat leading spaces */
2978                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2979                         /* empty */;
2980                 }
2981
2982                 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2983                         return LDAP_INVALID_SYNTAX;
2984                 }
2985
2986                 /* should be at issuer or serialNumber NamedValue */
2987                 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2988                         /* parse issuer */
2989                         x.bv_val += STRLENOF("issuer");
2990                         x.bv_len -= STRLENOF("issuer");
2991
2992                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2993                         x.bv_val++; x.bv_len--;
2994
2995                         /* eat leading spaces */
2996                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2997                                 /* empty */;
2998                         }
2999                         
3000                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3001                         x.bv_val++; x.bv_len--;
3002
3003                         i.bv_val = x.bv_val;
3004                         i.bv_len = 0;
3005
3006                         for( ; i.bv_len < x.bv_len; ) {
3007                                 if ( i.bv_val[i.bv_len] != '"' ) {
3008                                         i.bv_len++;
3009                                         continue;
3010                                 }
3011                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
3012                                         /* double dquote */
3013                                         i.bv_len+=2;
3014                                         continue;
3015                                 }
3016                                 break;
3017                         }
3018                         x.bv_val += i.bv_len+1;
3019                         x.bv_len -= i.bv_len+1;
3020
3021                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
3022                                 return LDAP_INVALID_SYNTAX;
3023                         }
3024
3025                         haveissuer++;
3026
3027                 } else if( strncasecmp( x.bv_val, "serialNumber",
3028                         STRLENOF("serialNumber")) == 0 )
3029                 {
3030                         /* parse serialNumber */
3031                         int neg=0;
3032                         x.bv_val += STRLENOF("serialNumber");
3033                         x.bv_len -= STRLENOF("serialNumber");
3034
3035                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3036                         x.bv_val++; x.bv_len--;
3037
3038                         /* eat leading spaces */
3039                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3040                                 /* empty */;
3041                         }
3042                         
3043                         sn.bv_val = x.bv_val;
3044                         sn.bv_len = 0;
3045
3046                         if( sn.bv_val[0] == '-' ) {
3047                                 neg++;
3048                                 sn.bv_len++;
3049                         }
3050
3051                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
3052                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
3053                         }
3054
3055                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
3056                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
3057                                 return LDAP_INVALID_SYNTAX;
3058                         }
3059
3060                         x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
3061
3062                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
3063                                 return LDAP_INVALID_SYNTAX;
3064                         }
3065
3066                         havesn++;
3067
3068                 } else return LDAP_INVALID_SYNTAX;
3069
3070                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
3071                 x.bv_val++; x.bv_len--;
3072
3073                 /* eat spaces */
3074                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3075                         /* empty */;
3076                 }
3077
3078                 /* should be at remaining NamedValue */
3079                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
3080                         STRLENOF("issuer" )) == 0 ))
3081                 {
3082                         /* parse issuer */
3083                         x.bv_val += STRLENOF("issuer");
3084                         x.bv_len -= STRLENOF("issuer");
3085
3086                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3087                         x.bv_val++; x.bv_len--;
3088
3089                         /* eat leading spaces */
3090                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3091                                  /* empty */;
3092                         }
3093                         
3094                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3095                         x.bv_val++; x.bv_len--;
3096
3097                         i.bv_val = x.bv_val;
3098                         i.bv_len = 0;
3099
3100                         for( ; i.bv_len < x.bv_len; ) {
3101                                 if ( i.bv_val[i.bv_len] != '"' ) {
3102                                         i.bv_len++;
3103                                         continue;
3104                                 }
3105                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
3106                                         /* double dquote */
3107                                         i.bv_len+=2;
3108                                         continue;
3109                                 }
3110                                 break;
3111                         }
3112                         x.bv_val += i.bv_len+1;
3113                         x.bv_len -= i.bv_len+1;
3114
3115                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
3116                         STRLENOF("serialNumber")) == 0 ))
3117                 {
3118                         /* parse serialNumber */
3119                         int neg=0;
3120                         x.bv_val += STRLENOF("serialNumber");
3121                         x.bv_len -= STRLENOF("serialNumber");
3122
3123                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3124                         x.bv_val++; x.bv_len--;
3125
3126                         /* eat leading spaces */
3127                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
3128                                 /* empty */;
3129                         }
3130                         
3131                         sn.bv_val = x.bv_val;
3132                         sn.bv_len = 0;
3133
3134                         if( sn.bv_val[0] == '-' ) {
3135                                 neg++;
3136                                 sn.bv_len++;
3137                         }
3138
3139                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
3140                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
3141                         }
3142
3143                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
3144                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
3145                                 return LDAP_INVALID_SYNTAX;
3146                         }
3147
3148                         x.bv_val += sn.bv_len;
3149                         x.bv_len -= sn.bv_len;
3150
3151                 } else return LDAP_INVALID_SYNTAX;
3152
3153                 /* eat trailing spaces */
3154                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3155                         /* empty */;
3156                 }
3157
3158                 /* should have no characters left... */
3159                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
3160
3161                 ber_dupbv_x( &ni, &i, ctx );
3162                 i = ni;
3163
3164                 /* need to handle double dquotes here */
3165         }
3166
3167         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3168
3169         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3170                 slap_sl_free( i.bv_val, ctx );
3171         }
3172
3173         if( rc ) return LDAP_INVALID_SYNTAX;
3174
3175         /* make room from sn + "$" */
3176         out->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3177                 + sn.bv_len + ni.bv_len;
3178         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3179
3180         if( out->bv_val == NULL ) {
3181                 out->bv_len = 0;
3182                 slap_sl_free( ni.bv_val, ctx );
3183                 return LDAP_OTHER;
3184         }
3185
3186         n = 0;
3187         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3188                 STRLENOF( "{ serialNumber " ));
3189         n = STRLENOF( "{ serialNumber " );
3190
3191         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3192         n += sn.bv_len;
3193
3194         AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF( ", issuer \"" ));
3195         n += STRLENOF( ", issuer \"" );
3196
3197         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3198         n += ni.bv_len;
3199
3200         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
3201         n += STRLENOF( "\" }" );
3202
3203         out->bv_val[n] = '\0';
3204
3205         assert( n == out->bv_len );
3206
3207         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
3208                 out->bv_val, 0, 0 );
3209
3210         slap_sl_free( ni.bv_val, ctx );
3211
3212         return LDAP_SUCCESS;
3213 }
3214
3215 #ifdef HAVE_TLS
3216 static int
3217 certificateExactNormalize(
3218         slap_mask_t usage,
3219         Syntax *syntax,
3220         MatchingRule *mr,
3221         struct berval *val,
3222         struct berval *normalized,
3223         void *ctx )
3224 {
3225         int rc = LDAP_INVALID_SYNTAX;
3226         unsigned char *p;
3227         char *serial = NULL;
3228         ber_len_t seriallen;
3229         struct berval issuer_dn = BER_BVNULL;
3230         X509_NAME *name = NULL;
3231         ASN1_INTEGER *sn = NULL;
3232         X509 *xcert = NULL;
3233
3234         if( BER_BVISEMPTY( val ) ) goto done;
3235
3236         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3237                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
3238         }
3239
3240         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3241
3242         p = (unsigned char *)val->bv_val;
3243         xcert = d2i_X509( NULL, &p, val->bv_len);
3244         if( xcert == NULL ) goto done;
3245
3246         sn=X509_get_serialNumber(xcert);
3247         if ( sn == NULL ) goto done;
3248         serial=i2s_ASN1_INTEGER(0, sn );
3249         if( serial == NULL ) goto done;
3250         seriallen=strlen(serial);
3251
3252         name=X509_get_issuer_name(xcert);
3253         if( name == NULL ) goto done;
3254         rc = dnX509normalize( name, &issuer_dn );
3255         if( rc != LDAP_SUCCESS ) goto done;
3256
3257         normalized->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3258                 + seriallen + issuer_dn.bv_len;
3259         normalized->bv_val = ch_malloc(normalized->bv_len+1);
3260
3261         p = (unsigned char *)normalized->bv_val;
3262
3263         AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3264         p += STRLENOF( "{ serialNumber " );
3265
3266         AC_MEMCPY(p, serial, seriallen);
3267         p += seriallen;
3268
3269         AC_MEMCPY(p, ", issuer \"", STRLENOF( ", issuer \"" ));
3270         p += STRLENOF( ", issuer \"" );
3271
3272         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3273         p += issuer_dn.bv_len;
3274
3275         AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3276         p += STRLENOF( "\" }" );
3277
3278         *p = '\0';
3279
3280         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3281                 normalized->bv_val, NULL, NULL );
3282
3283         rc = LDAP_SUCCESS;
3284
3285 done:
3286         if (xcert) X509_free(xcert);
3287         if (serial) ch_free(serial);
3288         if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
3289
3290         return rc;
3291 }
3292 #endif /* HAVE_TLS */
3293
3294
3295 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3296 /* slight optimization - does not need the start parameter */
3297 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3298 enum { start = 0 };
3299 #endif
3300
3301 static int
3302 check_time_syntax (struct berval *val,
3303         int start,
3304         int *parts,
3305         struct berval *fraction)
3306 {
3307         /*
3308          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3309          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
3310          * GeneralizedTime supports leap seconds, UTCTime does not.
3311          */
3312         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3313         static const int mdays[2][12] = {
3314                 /* non-leap years */
3315                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3316                 /* leap years */
3317                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3318         };
3319         char *p, *e;
3320         int part, c, c1, c2, tzoffset, leapyear = 0;
3321
3322         p = val->bv_val;
3323         e = p + val->bv_len;
3324
3325 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3326         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3327 #endif
3328         for (part = start; part < 7 && p < e; part++) {
3329                 c1 = *p;
3330                 if (!ASCII_DIGIT(c1)) {
3331                         break;
3332                 }
3333                 p++;
3334                 if (p == e) {
3335                         return LDAP_INVALID_SYNTAX;
3336                 }
3337                 c = *p++;
3338                 if (!ASCII_DIGIT(c)) {
3339                         return LDAP_INVALID_SYNTAX;
3340                 }
3341                 c += c1 * 10 - '0' * 11;
3342                 if ((part | 1) == 3) {
3343                         --c;
3344                         if (c < 0) {
3345                                 return LDAP_INVALID_SYNTAX;
3346                         }
3347                 }
3348                 if (c >= ceiling[part]) {
3349                         if (! (c == 60 && part == 6 && start == 0))
3350                                 return LDAP_INVALID_SYNTAX;
3351                 }
3352                 parts[part] = c;
3353         }
3354         if (part < 5 + start) {
3355                 return LDAP_INVALID_SYNTAX;
3356         }
3357         for (; part < 9; part++) {
3358                 parts[part] = 0;
3359         }
3360
3361         /* leapyear check for the Gregorian calendar (year>1581) */
3362         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3363                 leapyear = 1;
3364         }
3365
3366         if (parts[3] >= mdays[leapyear][parts[2]]) {
3367                 return LDAP_INVALID_SYNTAX;
3368         }
3369
3370         if (start == 0) {
3371                 fraction->bv_val = p;
3372                 fraction->bv_len = 0;
3373                 if (p < e && (*p == '.' || *p == ',')) {
3374                         char *end_num;
3375                         while (++p < e && ASCII_DIGIT(*p)) {
3376                                 /* EMTPY */;
3377                         }
3378                         if (p - fraction->bv_val == 1) {
3379                                 return LDAP_INVALID_SYNTAX;
3380                         }
3381                         for (end_num = p; end_num[-1] == '0'; --end_num) {
3382                                 /* EMPTY */;
3383                         }
3384                         c = end_num - fraction->bv_val;
3385                         if (c != 1) fraction->bv_len = c;
3386                 }
3387         }
3388
3389         if (p == e) {
3390                 /* no time zone */
3391                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3392         }
3393
3394         tzoffset = *p++;
3395         switch (tzoffset) {
3396         default:
3397                 return LDAP_INVALID_SYNTAX;
3398         case 'Z':
3399                 /* UTC */
3400                 break;
3401         case '+':
3402         case '-':
3403                 for (part = 7; part < 9 && p < e; part++) {
3404                         c1 = *p;
3405                         if (!ASCII_DIGIT(c1)) {
3406                                 break;
3407                         }
3408                         p++;
3409                         if (p == e) {
3410                                 return LDAP_INVALID_SYNTAX;
3411                         }
3412                         c2 = *p++;
3413                         if (!ASCII_DIGIT(c2)) {
3414                                 return LDAP_INVALID_SYNTAX;
3415                         }
3416                         parts[part] = c1 * 10 + c2 - '0' * 11;
3417                         if (parts[part] >= ceiling[part]) {
3418                                 return LDAP_INVALID_SYNTAX;
3419                         }
3420                 }
3421                 if (part < 8 + start) {
3422                         return LDAP_INVALID_SYNTAX;
3423                 }
3424
3425                 if (tzoffset == '-') {
3426                         /* negative offset to UTC, ie west of Greenwich */
3427                         parts[4] += parts[7];
3428                         parts[5] += parts[8];
3429                         /* offset is just hhmm, no seconds */
3430                         for (part = 6; --part >= 0; ) {
3431                                 if (part != 3) {
3432                                         c = ceiling[part];
3433                                 } else {
3434                                         c = mdays[leapyear][parts[2]];
3435                                 }
3436                                 if (parts[part] >= c) {
3437                                         if (part == 0) {
3438                                                 return LDAP_INVALID_SYNTAX;
3439                                         }
3440                                         parts[part] -= c;
3441                                         parts[part - 1]++;
3442                                         continue;
3443                                 } else if (part != 5) {
3444                                         break;
3445                                 }
3446                         }
3447                 } else {
3448                         /* positive offset to UTC, ie east of Greenwich */
3449                         parts[4] -= parts[7];
3450                         parts[5] -= parts[8];
3451                         for (part = 6; --part >= 0; ) {
3452                                 if (parts[part] < 0) {
3453                                         if (part == 0) {
3454                                                 return LDAP_INVALID_SYNTAX;
3455                                         }
3456                                         if (part != 3) {
3457                                                 c = ceiling[part];
3458                                         } else {
3459                                                 /* make first arg to % non-negative */
3460                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
3461                                         }
3462                                         parts[part] += c;
3463                                         parts[part - 1]--;
3464                                         continue;
3465                                 } else if (part != 5) {
3466                                         break;
3467                                 }
3468                         }
3469                 }
3470         }
3471
3472         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3473 }
3474
3475 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3476
3477 #if 0
3478 static int
3479 xutcTimeNormalize(
3480         Syntax *syntax,
3481         struct berval *val,
3482         struct berval *normalized )
3483 {
3484         int parts[9], rc;
3485
3486         rc = check_time_syntax(val, 1, parts, NULL);
3487         if (rc != LDAP_SUCCESS) {
3488                 return rc;
3489         }
3490
3491         normalized->bv_val = ch_malloc( 14 );
3492         if ( normalized->bv_val == NULL ) {
3493                 return LBER_ERROR_MEMORY;
3494         }
3495
3496         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
3497                 parts[1], parts[2] + 1, parts[3] + 1,
3498                 parts[4], parts[5], parts[6] );
3499         normalized->bv_len = 13;
3500
3501         return LDAP_SUCCESS;
3502 }
3503 #endif /* 0 */
3504
3505 static int
3506 utcTimeValidate(
3507         Syntax *syntax,
3508         struct berval *in )
3509 {
3510         int parts[9];
3511         return check_time_syntax(in, 1, parts, NULL);
3512 }
3513
3514 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
3515
3516 static int
3517 generalizedTimeValidate(
3518         Syntax *syntax,
3519         struct berval *in )
3520 {
3521         int parts[9];
3522         struct berval fraction;
3523         return check_time_syntax(in, 0, parts, &fraction);
3524 }
3525
3526 static int
3527 generalizedTimeNormalize(
3528         slap_mask_t usage,
3529         Syntax *syntax,
3530         MatchingRule *mr,
3531         struct berval *val,
3532         struct berval *normalized,
3533         void *ctx )
3534 {
3535         int parts[9], rc;
3536         unsigned int len;
3537         struct berval fraction;
3538
3539         rc = check_time_syntax(val, 0, parts, &fraction);
3540         if (rc != LDAP_SUCCESS) {
3541                 return rc;
3542         }
3543
3544         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
3545         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
3546         if ( BER_BVISNULL( normalized ) ) {
3547                 return LBER_ERROR_MEMORY;
3548         }
3549
3550         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
3551                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
3552                 parts[4], parts[5], parts[6] );
3553         if ( !BER_BVISEMPTY( &fraction ) ) {
3554                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
3555                         fraction.bv_val, fraction.bv_len );
3556                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
3557         }
3558         strcpy( normalized->bv_val + len-1, "Z" );
3559         normalized->bv_len = len;
3560
3561         return LDAP_SUCCESS;
3562 }
3563
3564 static int
3565 generalizedTimeOrderingMatch(
3566         int *matchp,
3567         slap_mask_t flags,
3568         Syntax *syntax,
3569         MatchingRule *mr,
3570         struct berval *value,
3571         void *assertedValue )
3572 {
3573         struct berval *asserted = (struct berval *) assertedValue;
3574         ber_len_t v_len  = value->bv_len;
3575         ber_len_t av_len = asserted->bv_len;
3576
3577         /* ignore trailing 'Z' when comparing */
3578         int match = memcmp( value->bv_val, asserted->bv_val,
3579                 (v_len < av_len ? v_len : av_len) - 1 );
3580         if ( match == 0 ) match = v_len - av_len;
3581
3582         *matchp = match;
3583         return LDAP_SUCCESS;
3584 }
3585
3586 /* Index generation function */
3587 int generalizedTimeIndexer(
3588         slap_mask_t use,
3589         slap_mask_t flags,
3590         Syntax *syntax,
3591         MatchingRule *mr,
3592         struct berval *prefix,
3593         BerVarray values,
3594         BerVarray *keysp,
3595         void *ctx )
3596 {
3597         int i, j;
3598         BerVarray keys;
3599         char tmp[5];
3600         BerValue bvtmp; /* 40 bit index */
3601         struct lutil_tm tm;
3602         struct lutil_timet tt;
3603
3604         bvtmp.bv_len = sizeof(tmp);
3605         bvtmp.bv_val = tmp;
3606         for( i=0; values[i].bv_val != NULL; i++ ) {
3607                 /* just count them */
3608         }
3609
3610         /* we should have at least one value at this point */
3611         assert( i > 0 );
3612
3613         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
3614
3615         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3616         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
3617                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
3618                 /* Use 40 bits of time for key */
3619                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
3620                         lutil_tm2time( &tm, &tt );
3621                         tmp[0] = tt.tt_gsec & 0xff;
3622                         tmp[4] = tt.tt_sec & 0xff;
3623                         tt.tt_sec >>= 8;
3624                         tmp[3] = tt.tt_sec & 0xff;
3625                         tt.tt_sec >>= 8;
3626                         tmp[2] = tt.tt_sec & 0xff;
3627                         tt.tt_sec >>= 8;
3628                         tmp[1] = tt.tt_sec & 0xff;
3629                         
3630                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
3631                 }
3632         }
3633
3634         keys[j].bv_val = NULL;
3635         keys[j].bv_len = 0;
3636
3637         *keysp = keys;
3638
3639         return LDAP_SUCCESS;
3640 }
3641
3642 /* Index generation function */
3643 int generalizedTimeFilter(
3644         slap_mask_t use,
3645         slap_mask_t flags,
3646         Syntax *syntax,
3647         MatchingRule *mr,
3648         struct berval *prefix,
3649         void * assertedValue,
3650         BerVarray *keysp,
3651         void *ctx )
3652 {
3653         BerVarray keys;
3654         char tmp[5];
3655         BerValue bvtmp; /* 40 bit index */
3656         BerValue *value = (BerValue *) assertedValue;
3657         struct lutil_tm tm;
3658         struct lutil_timet tt;
3659         
3660         bvtmp.bv_len = sizeof(tmp);
3661         bvtmp.bv_val = tmp;
3662         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3663         /* Use 40 bits of time for key */
3664         if ( value->bv_val && value->bv_len >= 10 &&
3665                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
3666
3667                 lutil_tm2time( &tm, &tt );
3668                 tmp[0] = tt.tt_gsec & 0xff;
3669                 tmp[4] = tt.tt_sec & 0xff;
3670                 tt.tt_sec >>= 8;
3671                 tmp[3] = tt.tt_sec & 0xff;
3672                 tt.tt_sec >>= 8;
3673                 tmp[2] = tt.tt_sec & 0xff;
3674                 tt.tt_sec >>= 8;
3675                 tmp[1] = tt.tt_sec & 0xff;
3676
3677                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
3678                 ber_dupbv_x(keys, &bvtmp, ctx );
3679                 keys[1].bv_val = NULL;
3680                 keys[1].bv_len = 0;
3681         } else {
3682                 keys = NULL;
3683         }
3684
3685         *keysp = keys;
3686
3687         return LDAP_SUCCESS;
3688 }
3689
3690 static int
3691 deliveryMethodValidate(
3692         Syntax *syntax,
3693         struct berval *val )
3694 {
3695 #undef LENOF
3696 #define LENOF(s) (sizeof(s)-1)
3697         struct berval tmp = *val;
3698         /*
3699      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
3700          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
3701          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
3702          */
3703 again:
3704         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3705
3706         switch( tmp.bv_val[0] ) {
3707         case 'a':
3708         case 'A':
3709                 if(( tmp.bv_len >= LENOF("any") ) &&
3710                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
3711                 {
3712                         tmp.bv_len -= LENOF("any");
3713                         tmp.bv_val += LENOF("any");
3714                         break;
3715                 }
3716                 return LDAP_INVALID_SYNTAX;
3717
3718         case 'm':
3719         case 'M':
3720                 if(( tmp.bv_len >= LENOF("mhs") ) &&
3721                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
3722                 {
3723                         tmp.bv_len -= LENOF("mhs");
3724                         tmp.bv_val += LENOF("mhs");
3725                         break;
3726                 }
3727                 return LDAP_INVALID_SYNTAX;
3728
3729         case 'p':
3730         case 'P':
3731                 if(( tmp.bv_len >= LENOF("physical") ) &&
3732                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
3733                 {
3734                         tmp.bv_len -= LENOF("physical");
3735                         tmp.bv_val += LENOF("physical");
3736                         break;
3737                 }
3738                 return LDAP_INVALID_SYNTAX;
3739
3740         case 't':
3741         case 'T': /* telex or teletex or telephone */
3742                 if(( tmp.bv_len >= LENOF("telex") ) &&
3743                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
3744                 {
3745                         tmp.bv_len -= LENOF("telex");
3746                         tmp.bv_val += LENOF("telex");
3747                         break;
3748                 }
3749                 if(( tmp.bv_len >= LENOF("teletex") ) &&
3750                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
3751                 {
3752                         tmp.bv_len -= LENOF("teletex");
3753                         tmp.bv_val += LENOF("teletex");
3754                         break;
3755                 }
3756                 if(( tmp.bv_len >= LENOF("telephone") ) &&
3757                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
3758                 {
3759                         tmp.bv_len -= LENOF("telephone");
3760                         tmp.bv_val += LENOF("telephone");
3761                         break;
3762                 }
3763                 return LDAP_INVALID_SYNTAX;
3764
3765         case 'g':
3766         case 'G': /* g3fax or g4fax */
3767                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
3768                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
3769                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
3770                 {
3771                         tmp.bv_len -= LENOF("g3fax");
3772                         tmp.bv_val += LENOF("g3fax");
3773                         break;
3774                 }
3775                 return LDAP_INVALID_SYNTAX;
3776
3777         case 'i':
3778         case 'I':
3779                 if(( tmp.bv_len >= LENOF("ia5") ) &&
3780                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
3781                 {
3782                         tmp.bv_len -= LENOF("ia5");
3783                         tmp.bv_val += LENOF("ia5");
3784                         break;
3785                 }
3786                 return LDAP_INVALID_SYNTAX;
3787
3788         case 'v':
3789         case 'V':
3790                 if(( tmp.bv_len >= LENOF("videotex") ) &&
3791                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
3792                 {
3793                         tmp.bv_len -= LENOF("videotex");
3794                         tmp.bv_val += LENOF("videotex");
3795                         break;
3796                 }
3797                 return LDAP_INVALID_SYNTAX;
3798
3799         default:
3800                 return LDAP_INVALID_SYNTAX;
3801         }
3802
3803         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
3804
3805         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3806                 tmp.bv_len++;
3807                 tmp.bv_val--;
3808         }
3809         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
3810                 tmp.bv_len++;
3811                 tmp.bv_val--;
3812         } else {
3813                 return LDAP_INVALID_SYNTAX;
3814         }
3815         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3816                 tmp.bv_len++;
3817                 tmp.bv_val--;
3818         }
3819
3820         goto again;
3821 }
3822
3823 static int
3824 nisNetgroupTripleValidate(
3825         Syntax *syntax,
3826         struct berval *val )
3827 {
3828         char *p, *e;
3829         int commas = 0;
3830
3831         if ( BER_BVISEMPTY( val ) ) {
3832                 return LDAP_INVALID_SYNTAX;
3833         }
3834
3835         p = (char *)val->bv_val;
3836         e = p + val->bv_len;
3837
3838         if ( *p != '(' /*')'*/ ) {
3839                 return LDAP_INVALID_SYNTAX;
3840         }
3841
3842         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
3843                 if ( *p == ',' ) {
3844                         commas++;
3845                         if ( commas > 2 ) {
3846                                 return LDAP_INVALID_SYNTAX;
3847                         }
3848
3849                 } else if ( !AD_CHAR( *p ) ) {
3850                         return LDAP_INVALID_SYNTAX;
3851                 }
3852         }
3853
3854         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
3855                 return LDAP_INVALID_SYNTAX;
3856         }
3857
3858         p++;
3859
3860         if (p != e) {
3861                 return LDAP_INVALID_SYNTAX;
3862         }
3863
3864         return LDAP_SUCCESS;
3865 }
3866
3867 static int
3868 bootParameterValidate(
3869         Syntax *syntax,
3870         struct berval *val )
3871 {
3872         char *p, *e;
3873
3874         if ( BER_BVISEMPTY( val ) ) {
3875                 return LDAP_INVALID_SYNTAX;
3876         }
3877
3878         p = (char *)val->bv_val;
3879         e = p + val->bv_len;
3880
3881         /* key */
3882         for (; ( p < e ) && ( *p != '=' ); p++ ) {
3883                 if ( !AD_CHAR( *p ) ) {
3884                         return LDAP_INVALID_SYNTAX;
3885                 }
3886         }
3887
3888         if ( *p != '=' ) {
3889                 return LDAP_INVALID_SYNTAX;
3890         }
3891
3892         /* server */
3893         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
3894                 if ( !AD_CHAR( *p ) ) {
3895                         return LDAP_INVALID_SYNTAX;
3896                 }
3897         }
3898
3899         if ( *p != ':' ) {
3900                 return LDAP_INVALID_SYNTAX;
3901         }
3902
3903         /* path */
3904         for ( p++; p < e; p++ ) {
3905                 if ( !SLAP_PRINTABLE( *p ) ) {
3906                         return LDAP_INVALID_SYNTAX;
3907                 }
3908         }
3909
3910         return LDAP_SUCCESS;
3911 }
3912
3913 static int
3914 firstComponentNormalize(
3915         slap_mask_t usage,
3916         Syntax *syntax,
3917         MatchingRule *mr,
3918         struct berval *val,
3919         struct berval *normalized,
3920         void *ctx )
3921 {
3922         int rc;
3923         struct berval comp;
3924         ber_len_t len;
3925
3926         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
3927                 ber_dupbv_x( normalized, val, ctx );
3928                 return LDAP_SUCCESS;
3929         }
3930
3931         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3932
3933         if( val->bv_val[0] != '(' /*')'*/ &&
3934                 val->bv_val[0] != '{' /*'}'*/ )
3935         {
3936                 return LDAP_INVALID_SYNTAX;
3937         }
3938
3939         /* trim leading white space */
3940         for( len=1;
3941                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
3942                 len++ )
3943         {
3944                 /* empty */
3945         }
3946
3947         /* grab next word */
3948         comp.bv_val = &val->bv_val[len];
3949         len = val->bv_len - len;
3950         for( comp.bv_len = 0;
3951                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
3952                 comp.bv_len++ )
3953         {
3954                 /* empty */
3955         }
3956
3957         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
3958                 rc = numericoidValidate( NULL, &comp );
3959         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
3960                 rc = integerValidate( NULL, &comp );
3961         } else {
3962                 rc = LDAP_INVALID_SYNTAX;
3963         }
3964         
3965
3966         if( rc == LDAP_SUCCESS ) {
3967                 ber_dupbv_x( normalized, &comp, ctx );
3968         }
3969
3970         return rc;
3971 }
3972
3973
3974 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
3975 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
3976
3977 static slap_syntax_defs_rec syntax_defs[] = {
3978         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
3979                 X_BINARY X_NOT_H_R ")",
3980                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
3981         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
3982                 0, NULL, NULL},
3983         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
3984                 0, NULL, NULL},
3985         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
3986                 X_NOT_H_R ")",
3987                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3988         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
3989                 X_NOT_H_R ")",
3990                 SLAP_SYNTAX_BER, berValidate, NULL},
3991         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
3992                 0, bitStringValidate, NULL },
3993         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
3994                 0, booleanValidate, NULL},
3995         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
3996                 X_BINARY X_NOT_H_R ")",
3997                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
3998         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
3999                 X_BINARY X_NOT_H_R ")",
4000                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
4001         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4002                 X_BINARY X_NOT_H_R ")",
4003                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
4004         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4005                 0, countryStringValidate, NULL},
4006         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4007                 0, dnValidate, dnPretty},
4008         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4009                 0, rdnValidate, rdnPretty},
4010 #ifdef LDAP_COMP_MATCH
4011         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4012                 0, allComponentsValidate, NULL},
4013         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4014                 0, componentFilterValidate, NULL},
4015 #endif
4016         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4017                 0, NULL, NULL},
4018         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4019                 0, deliveryMethodValidate, NULL},
4020         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4021                 0, UTF8StringValidate, NULL},
4022         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4023                 0, NULL, NULL},
4024         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4025                 0, NULL, NULL},
4026         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4027                 0, NULL, NULL},
4028         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4029                 0, NULL, NULL},
4030         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4031                 0, NULL, NULL},
4032         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4033                 0, printablesStringValidate, NULL},
4034         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4035                 SLAP_SYNTAX_BLOB, NULL, NULL},
4036         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4037                 0, generalizedTimeValidate, NULL},
4038         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4039                 0, NULL, NULL},
4040         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4041                 0, IA5StringValidate, NULL},
4042         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4043                 0, integerValidate, NULL},
4044         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4045                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
4046         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4047                 0, NULL, NULL},
4048         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4049                 0, NULL, NULL},
4050         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4051                 0, NULL, NULL},
4052         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4053                 0, NULL, NULL},
4054         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4055                 0, NULL, NULL},
4056         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4057                 0, nameUIDValidate, nameUIDPretty },
4058         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4059                 0, NULL, NULL},
4060         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4061                 0, numericStringValidate, NULL},
4062         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4063                 0, NULL, NULL},
4064         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4065                 0, numericoidValidate, NULL},
4066         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4067                 0, IA5StringValidate, NULL},
4068         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4069                 0, blobValidate, NULL},
4070         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4071                 0, UTF8StringValidate, NULL},
4072         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4073                 0, NULL, NULL},
4074         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4075                 0, NULL, NULL},
4076         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4077                 0, printableStringValidate, NULL},
4078         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4079 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4080                 0, subtreeSpecificationValidate, NULL},
4081         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4082                 X_BINARY X_NOT_H_R ")",
4083                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
4084         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4085                 0, printableStringValidate, NULL},
4086         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4087                 0, NULL, NULL},
4088         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4089                 0, printablesStringValidate, NULL},
4090 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4091         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4092                 0, utcTimeValidate, NULL},
4093 #endif
4094         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4095                 0, NULL, NULL},
4096         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4097                 0, NULL, NULL},
4098         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4099                 0, NULL, NULL},
4100         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4101                 0, NULL, NULL},
4102         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4103                 0, NULL, NULL},
4104
4105         /* RFC 2307 NIS Syntaxes */
4106         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4107                 0, nisNetgroupTripleValidate, NULL},
4108         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4109                 0, bootParameterValidate, NULL},
4110
4111         /* draft-zeilenga-ldap-x509 */
4112         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4113                 SLAP_SYNTAX_HIDE,
4114                 serialNumberAndIssuerValidate,
4115                 serialNumberAndIssuerPretty},
4116         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4117                 SLAP_SYNTAX_HIDE, NULL, NULL},
4118         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4119                 SLAP_SYNTAX_HIDE, NULL, NULL},
4120         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4121                 SLAP_SYNTAX_HIDE, NULL, NULL},
4122         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4123                 SLAP_SYNTAX_HIDE, NULL, NULL},
4124         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4125                 SLAP_SYNTAX_HIDE, NULL, NULL},
4126         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4127                 SLAP_SYNTAX_HIDE, NULL, NULL},
4128
4129 #ifdef SLAPD_AUTHPASSWD
4130         /* needs updating */
4131         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4132                 SLAP_SYNTAX_HIDE, NULL, NULL},
4133 #endif
4134
4135         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4136                 0, UUIDValidate, UUIDPretty},
4137
4138         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4139                 SLAP_SYNTAX_HIDE, csnValidate, NULL},
4140
4141         /* OpenLDAP Void Syntax */
4142         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4143                 SLAP_SYNTAX_HIDE, inValidate, NULL},
4144
4145         /* FIXME: OID is unused, but not registered yet */
4146         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4147                 SLAP_SYNTAX_HIDE, authzValidate, authzPretty},
4148
4149         {NULL, 0, NULL, NULL}
4150 };
4151
4152 char *certificateExactMatchSyntaxes[] = {
4153         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4154         NULL
4155 };
4156 #ifdef LDAP_COMP_MATCH
4157 char *componentFilterMatchSyntaxes[] = {
4158         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4159         NULL
4160 };
4161 #endif
4162 char *directoryStringSyntaxes[] = {
4163         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4164         NULL
4165 };
4166 char *integerFirstComponentMatchSyntaxes[] = {
4167         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4168         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4169         NULL
4170 };
4171 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4172         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4173         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
4174         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4175         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4176         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4177         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4178         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4179         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4180         NULL
4181 };
4182
4183 /*
4184  * Other matching rules in X.520 that we do not use (yet):
4185  *
4186  * 2.5.13.25    uTCTimeMatch
4187  * 2.5.13.26    uTCTimeOrderingMatch
4188  * 2.5.13.31*   directoryStringFirstComponentMatch
4189  * 2.5.13.32*   wordMatch
4190  * 2.5.13.33*   keywordMatch
4191  * 2.5.13.36+   certificatePairExactMatch
4192  * 2.5.13.37+   certificatePairMatch
4193  * 2.5.13.38+   certificateListExactMatch
4194  * 2.5.13.39+   certificateListMatch
4195  * 2.5.13.40+   algorithmIdentifierMatch
4196  * 2.5.13.41*   storedPrefixMatch
4197  * 2.5.13.42    attributeCertificateMatch
4198  * 2.5.13.43    readerAndKeyIDMatch
4199  * 2.5.13.44    attributeIntegrityMatch
4200  *
4201  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4202  * (+) described in draft-zeilenga-ldap-x509
4203  */
4204 static slap_mrule_defs_rec mrule_defs[] = {
4205         /*
4206          * EQUALITY matching rules must be listed after associated APPROX
4207          * matching rules.  So, we list all APPROX matching rules first.
4208          */
4209         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4210                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4211                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4212                 NULL, NULL, directoryStringApproxMatch,
4213                 directoryStringApproxIndexer, directoryStringApproxFilter,
4214                 NULL},
4215
4216         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4217                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4218                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4219                 NULL, NULL, IA5StringApproxMatch,
4220                 IA5StringApproxIndexer, IA5StringApproxFilter,
4221                 NULL},
4222
4223         /*
4224          * Other matching rules
4225          */
4226         
4227         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4228                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4229                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4230                 NULL, NULL, octetStringMatch,
4231                 octetStringIndexer, octetStringFilter,
4232                 NULL },
4233
4234         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4235                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4236                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4237                 NULL, dnNormalize, dnMatch,
4238                 octetStringIndexer, octetStringFilter,
4239                 NULL },
4240
4241         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4242                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4243                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4244                 NULL, dnNormalize, dnRelativeMatch,
4245                 NULL, NULL,
4246                 NULL },
4247
4248         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4249                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4250                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4251                 NULL, dnNormalize, dnRelativeMatch,
4252                 NULL, NULL,
4253                 NULL },
4254
4255         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4256                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4257                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4258                 NULL, dnNormalize, dnRelativeMatch,
4259                 NULL, NULL,
4260                 NULL },
4261
4262         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4263                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4264                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4265                 NULL, dnNormalize, dnRelativeMatch,
4266                 NULL, NULL,
4267                 NULL },
4268
4269         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4270                 "SYNTAX 1.2.36.79672281.1.5.0 )",
4271                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4272                 NULL, rdnNormalize, rdnMatch,
4273                 octetStringIndexer, octetStringFilter,
4274                 NULL },
4275
4276 #ifdef LDAP_COMP_MATCH
4277         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4278                 "SYNTAX 1.2.36.79672281.1.5.2 )",
4279                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4280                 NULL, NULL , componentFilterMatch,
4281                 octetStringIndexer, octetStringFilter,
4282                 NULL },
4283
4284         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4285                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4286                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4287                 NULL, NULL , allComponentsMatch,
4288                 octetStringIndexer, octetStringFilter,
4289                 NULL },
4290
4291         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4292                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4293                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4294                 NULL, NULL , directoryComponentsMatch,
4295                 octetStringIndexer, octetStringFilter,
4296                 NULL },
4297 #endif
4298
4299         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4300                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4301                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4302                 NULL, UTF8StringNormalize, octetStringMatch,
4303                 octetStringIndexer, octetStringFilter,
4304                 directoryStringApproxMatchOID },
4305
4306         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4307                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4308                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4309                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4310                 NULL, NULL,
4311                 "caseIgnoreMatch" },
4312
4313         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4314                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4315                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4316                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4317                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4318                 "caseIgnoreMatch" },
4319
4320         {"( 2.5.13.5 NAME 'caseExactMatch' "
4321                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4322                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4323                 NULL, UTF8StringNormalize, octetStringMatch,
4324                 octetStringIndexer, octetStringFilter,
4325                 directoryStringApproxMatchOID },
4326
4327         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4328                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4329                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4330                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4331                 NULL, NULL,
4332                 "caseExactMatch" },
4333
4334         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4335                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4336                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4337                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4338                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4339                 "caseExactMatch" },
4340
4341         {"( 2.5.13.8 NAME 'numericStringMatch' "
4342                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4343                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4344                 NULL, numericStringNormalize, octetStringMatch,
4345                 octetStringIndexer, octetStringFilter,
4346                 NULL },
4347
4348         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4349                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4350                 SLAP_MR_ORDERING, NULL,
4351                 NULL, numericStringNormalize, octetStringOrderingMatch,
4352                 NULL, NULL,
4353                 "numericStringMatch" },
4354
4355         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4356                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4357                 SLAP_MR_SUBSTR, NULL,
4358                 NULL, numericStringNormalize, octetStringSubstringsMatch,
4359                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4360                 "numericStringMatch" },
4361
4362         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4363                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4364                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4365                 NULL, NULL, NULL, NULL, NULL, NULL },
4366
4367         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4368                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4369                 SLAP_MR_SUBSTR, NULL,
4370                 NULL, NULL, NULL, NULL, NULL,
4371                 "caseIgnoreListMatch" },
4372
4373         {"( 2.5.13.13 NAME 'booleanMatch' "
4374                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4375                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4376                 NULL, NULL, booleanMatch,
4377                 octetStringIndexer, octetStringFilter,
4378                 NULL },
4379
4380         {"( 2.5.13.14 NAME 'integerMatch' "
4381                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4382                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4383                 NULL, NULL, integerMatch,
4384                 octetStringIndexer, octetStringFilter,
4385                 NULL },
4386
4387         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4388                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4389                 SLAP_MR_ORDERING, NULL,
4390                 NULL, NULL, integerMatch,
4391                 NULL, NULL,
4392                 "integerMatch" },
4393
4394         {"( 2.5.13.16 NAME 'bitStringMatch' "
4395                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4396                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4397                 NULL, NULL, octetStringMatch,
4398                 octetStringIndexer, octetStringFilter,
4399                 NULL },
4400
4401         {"( 2.5.13.17 NAME 'octetStringMatch' "
4402                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4403                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4404                 NULL, NULL, octetStringMatch,
4405                 octetStringIndexer, octetStringFilter,
4406                 NULL },
4407
4408         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
4409                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4410                 SLAP_MR_ORDERING, NULL,
4411                 NULL, NULL, octetStringOrderingMatch,
4412                 NULL, NULL,
4413                 "octetStringMatch" },
4414
4415         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
4416                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4417                 SLAP_MR_SUBSTR, NULL,
4418                 NULL, NULL, octetStringSubstringsMatch,
4419                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4420                 "octetStringMatch" },
4421
4422         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
4423                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
4424                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4425                 NULL,
4426                 telephoneNumberNormalize, octetStringMatch,
4427                 octetStringIndexer, octetStringFilter,
4428                 NULL },
4429
4430         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
4431                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4432                 SLAP_MR_SUBSTR, NULL,
4433                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
4434                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4435                 "telephoneNumberMatch" },
4436
4437         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
4438                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
4439                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4440                 NULL, NULL, NULL, NULL, NULL, NULL },
4441
4442         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
4443                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
4444                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4445                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
4446                 uniqueMemberIndexer, uniqueMemberFilter,
4447                 NULL },
4448
4449         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
4450                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
4451                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4452                 NULL, NULL, NULL, NULL, NULL, NULL },
4453
4454         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
4455                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4456                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
4457                 NULL, generalizedTimeNormalize, octetStringMatch,
4458                 generalizedTimeIndexer, generalizedTimeFilter,
4459                 NULL },
4460
4461         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
4462                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4463                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4464                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
4465                 NULL, NULL,
4466                 "generalizedTimeMatch" },
4467
4468         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
4469                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4470                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4471                         integerFirstComponentMatchSyntaxes,
4472                 NULL, firstComponentNormalize, integerMatch,
4473                 octetStringIndexer, octetStringFilter,
4474                 NULL },
4475
4476         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
4477                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4478                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4479                         objectIdentifierFirstComponentMatchSyntaxes,
4480                 NULL, firstComponentNormalize, octetStringMatch,
4481                 octetStringIndexer, octetStringFilter,
4482                 NULL },
4483
4484         {"( 2.5.13.34 NAME 'certificateExactMatch' "
4485                 "SYNTAX 1.3.6.1.1.15.1 )",
4486                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
4487 #ifdef HAVE_TLS
4488                 NULL, certificateExactNormalize, octetStringMatch,
4489                 octetStringIndexer, octetStringFilter,
4490 #else
4491                 NULL, NULL, NULL, NULL, NULL,
4492 #endif
4493                 NULL },
4494
4495         {"( 2.5.13.35 NAME 'certificateMatch' "
4496                 "SYNTAX 1.3.6.1.1.15.2 )",
4497                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4498                 NULL, NULL, NULL, NULL, NULL,
4499                 NULL },
4500
4501         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
4502                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4503                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4504                 NULL, IA5StringNormalize, octetStringMatch,
4505                 octetStringIndexer, octetStringFilter,
4506                 IA5StringApproxMatchOID },
4507
4508         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
4509                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4510                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4511                 NULL, IA5StringNormalize, octetStringMatch,
4512                 octetStringIndexer, octetStringFilter,
4513                 IA5StringApproxMatchOID },
4514
4515         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
4516                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4517                 SLAP_MR_SUBSTR, NULL,
4518                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4519                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4520                 "caseIgnoreIA5Match" },
4521
4522         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
4523                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4524                 SLAP_MR_SUBSTR, NULL,
4525                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4526                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4527                 "caseExactIA5Match" },
4528
4529 #ifdef SLAPD_AUTHPASSWD
4530         /* needs updating */
4531         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
4532                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4533                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4534                 NULL, NULL, authPasswordMatch,
4535                 NULL, NULL,
4536                 NULL},
4537 #endif
4538
4539         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
4540                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4541                 SLAP_MR_EXT, NULL,
4542                 NULL, NULL, integerBitAndMatch,
4543                 NULL, NULL,
4544                 "integerMatch" },
4545
4546         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
4547                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4548                 SLAP_MR_EXT, NULL,
4549                 NULL, NULL, integerBitOrMatch,
4550                 NULL, NULL,
4551                 "integerMatch" },
4552
4553         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
4554                 "SYNTAX 1.3.6.1.1.16.1 )",
4555                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
4556                 NULL, UUIDNormalize, octetStringMatch,
4557                 octetStringIndexer, octetStringFilter,
4558                 NULL},
4559
4560         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
4561                 "SYNTAX 1.3.6.1.1.16.1 )",
4562                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
4563                 NULL, UUIDNormalize, octetStringOrderingMatch,
4564                 octetStringIndexer, octetStringFilter,
4565                 "UUIDMatch"},
4566
4567         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
4568                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4569                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
4570                 NULL, NULL, csnMatch,
4571                 csnIndexer, csnFilter,
4572                 NULL},
4573
4574         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
4575                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4576                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4577                 NULL, NULL, csnOrderingMatch,
4578                 NULL, NULL,
4579                 "CSNMatch" },
4580
4581         /* FIXME: OID is unused, but not registered yet */
4582         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
4583                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
4584                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4585                 NULL, authzNormalize, authzMatch,
4586                 NULL, NULL,
4587                 NULL},
4588
4589         {NULL, SLAP_MR_NONE, NULL,
4590                 NULL, NULL, NULL, NULL, NULL,
4591                 NULL }
4592 };
4593
4594 int
4595 slap_schema_init( void )
4596 {
4597         int             res;
4598         int             i;
4599
4600         /* we should only be called once (from main) */
4601         assert( schema_init_done == 0 );
4602
4603         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
4604                 res = register_syntax( &syntax_defs[i] );
4605
4606                 if ( res ) {
4607                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
4608                                  syntax_defs[i].sd_desc );
4609                         return LDAP_OTHER;
4610                 }
4611         }
4612
4613         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
4614                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
4615                         mrule_defs[i].mrd_compat_syntaxes == NULL )
4616                 {
4617                         fprintf( stderr,
4618                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
4619                                  mrule_defs[i].mrd_desc );
4620                         continue;
4621                 }
4622
4623                 res = register_matching_rule( &mrule_defs[i] );
4624
4625                 if ( res ) {
4626                         fprintf( stderr,
4627                                 "slap_schema_init: Error registering matching rule %s\n",
4628                                  mrule_defs[i].mrd_desc );
4629                         return LDAP_OTHER;
4630                 }
4631         }
4632
4633         res = slap_schema_load();
4634         schema_init_done = 1;
4635         return res;
4636 }
4637
4638 void
4639 schema_destroy( void )
4640 {
4641         oidm_destroy();
4642         oc_destroy();
4643         at_destroy();
4644         mr_destroy();
4645         mru_destroy();
4646         syn_destroy();
4647
4648         if( schema_init_done ) {
4649                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
4650                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
4651         }
4652 }