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