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