]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
Warnings cleanup
[openldap] / servers / slapd / schema_init.c
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2008 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #ifdef HAVE_LIMITS_H
21 #include <limits.h>
22 #endif
23
24 #include <ac/ctype.h>
25 #include <ac/errno.h>
26 #include <ac/string.h>
27 #include <ac/socket.h>
28
29 #include "slap.h"
30 #include "../../libraries/liblber/lber-int.h" /* get ber_ptrlen() */
31
32 #include "ldap_utf8.h"
33
34 #include "lutil.h"
35 #include "lutil_hash.h"
36 #define HASH_BYTES                              LUTIL_HASH_BYTES
37 #define HASH_CONTEXT                    lutil_HASH_CTX
38 #define HASH_Init(c)                    lutil_HASHInit(c)
39 #define HASH_Update(c,buf,len)  lutil_HASHUpdate(c,buf,len)
40 #define HASH_Final(d,c)                 lutil_HASHFinal(d,c)
41
42 /* approx matching rules */
43 #define directoryStringApproxMatchOID   "1.3.6.1.4.1.4203.666.4.4"
44 #define directoryStringApproxMatch              approxMatch
45 #define directoryStringApproxIndexer    approxIndexer
46 #define directoryStringApproxFilter             approxFilter
47 #define IA5StringApproxMatchOID                 "1.3.6.1.4.1.4203.666.4.5"
48 #define IA5StringApproxMatch                    approxMatch
49 #define IA5StringApproxIndexer                  approxIndexer
50 #define IA5StringApproxFilter                   approxFilter
51
52 /* Change Sequence Number (CSN) - much of this will change */
53 #define csnMatch                                octetStringMatch
54 #define csnOrderingMatch                octetStringOrderingMatch
55 #define csnIndexer                              generalizedTimeIndexer
56 #define csnFilter                               generalizedTimeFilter
57
58 #define authzMatch                              octetStringMatch
59
60 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
61 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
62 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
63 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
64
65 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
66 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
67         SLAP_INDEX_INTLEN_DEFAULT );
68
69 ldap_pvt_thread_mutex_t ad_undef_mutex;
70 ldap_pvt_thread_mutex_t oc_undef_mutex;
71
72 static int
73 generalizedTimeValidate(
74         Syntax *syntax,
75         struct berval *in );
76
77 #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, wasspace;
1547         ber_len_t i;
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         ber_len_t 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         ber_len_t 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         ber_len_t 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         ber_len_t neg = 0, extra = 0;
2855         char first = '\0';
2856
2857         out->bv_val = in->bv_val;
2858         out->bv_len = 0;
2859
2860         if ( out->bv_val[0] == '-' ) {
2861                 neg++;
2862                 out->bv_len++;
2863         }
2864
2865         if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
2866                 first = out->bv_val[2];
2867                 extra = 2;
2868
2869                 out->bv_len += STRLENOF("0x");
2870                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
2871                         if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
2872                 }
2873
2874         } else if ( out->bv_val[0] == '\'' ) {
2875                 first = out->bv_val[1];
2876                 extra = 3;
2877
2878                 out->bv_len += STRLENOF("'");
2879
2880                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
2881                         if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
2882                 }
2883                 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
2884                         return -1;
2885                 }
2886                 out->bv_len += STRLENOF("'H");
2887
2888         } else {
2889                 first = out->bv_val[0];
2890                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
2891                         if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
2892                 }
2893         }
2894
2895         if ( !( out->bv_len > neg ) ) {
2896                 return -1;
2897         }
2898
2899         if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
2900                 return -1;
2901         }
2902
2903         return 0;
2904 }
2905
2906 static int
2907 serialNumberAndIssuerCheck(
2908         struct berval *in,
2909         struct berval *sn,
2910         struct berval *is,
2911         void *ctx )
2912 {
2913         ber_len_t n;
2914
2915         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2916
2917         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2918                 /* Parse old format */
2919                 is->bv_val = ber_bvchr( in, '$' );
2920                 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
2921
2922                 sn->bv_val = in->bv_val;
2923                 sn->bv_len = is->bv_val - in->bv_val;
2924
2925                 is->bv_val++;
2926                 is->bv_len = in->bv_len - (sn->bv_len + 1);
2927
2928                 /* eat leading zeros */
2929                 for( n=0; n < (sn->bv_len-1); n++ ) {
2930                         if( sn->bv_val[n] != '0' ) break;
2931                 }
2932                 sn->bv_val += n;
2933                 sn->bv_len -= n;
2934
2935                 for( n=0; n < sn->bv_len; n++ ) {
2936                         if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2937                 }
2938
2939         } else {
2940                 /* Parse GSER format */ 
2941                 enum {
2942                         HAVE_NONE = 0x0,
2943                         HAVE_ISSUER = 0x1,
2944                         HAVE_SN = 0x2,
2945                         HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
2946                 } have = HAVE_NONE;
2947
2948                 int numdquotes = 0;
2949                 struct berval x = *in;
2950                 struct berval ni;
2951                 x.bv_val++;
2952                 x.bv_len -= 2;
2953
2954                 do {
2955                         /* eat leading spaces */
2956                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
2957                                 /* empty */;
2958                         }
2959
2960                         /* should be at issuer or serialNumber NamedValue */
2961                         if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
2962                                 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
2963
2964                                 /* parse issuer */
2965                                 x.bv_val += STRLENOF("issuer");
2966                                 x.bv_len -= STRLENOF("issuer");
2967
2968                                 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2969                                 x.bv_val++;
2970                                 x.bv_len--;
2971
2972                                 /* eat leading spaces */
2973                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
2974                                         /* empty */;
2975                                 }
2976
2977                                 /* For backward compatibility, this part is optional */
2978                                 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
2979                                         x.bv_val += STRLENOF("rdnSequence:");
2980                                         x.bv_len -= STRLENOF("rdnSequence:");
2981                                 }
2982
2983                                 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2984                                 x.bv_val++;
2985                                 x.bv_len--;
2986
2987                                 is->bv_val = x.bv_val;
2988                                 is->bv_len = 0;
2989
2990                                 for ( ; is->bv_len < x.bv_len; ) {
2991                                         if ( is->bv_val[is->bv_len] != '"' ) {
2992                                                 is->bv_len++;
2993                                                 continue;
2994                                         }
2995                                         if ( is->bv_val[is->bv_len+1] == '"' ) {
2996                                                 /* double dquote */
2997                                                 is->bv_len += 2;
2998                                                 continue;
2999                                         }
3000                                         break;
3001                                 }
3002                                 x.bv_val += is->bv_len + 1;
3003                                 x.bv_len -= is->bv_len + 1;
3004
3005                                 have |= HAVE_ISSUER;
3006
3007                         } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3008                         {
3009                                 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3010
3011                                 /* parse serialNumber */
3012                                 x.bv_val += STRLENOF("serialNumber");
3013                                 x.bv_len -= STRLENOF("serialNumber");
3014
3015                                 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3016                                 x.bv_val++;
3017                                 x.bv_len--;
3018
3019                                 /* eat leading spaces */
3020                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3021                                         /* empty */;
3022                                 }
3023
3024                                 if ( checkNum( &x, sn ) ) {
3025                                         return LDAP_INVALID_SYNTAX;
3026                                 }
3027
3028                                 x.bv_val += sn->bv_len;
3029                                 x.bv_len -= sn->bv_len;
3030
3031                                 have |= HAVE_SN;
3032
3033                         } else {
3034                                 return LDAP_INVALID_SYNTAX;
3035                         }
3036
3037                         /* eat leading spaces */
3038                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3039                                 /* empty */;
3040                         }
3041
3042                         if ( have == HAVE_ALL ) {
3043                                 break;
3044                         }
3045
3046                         if ( x.bv_val[0] != ',' ) {
3047                                 return LDAP_INVALID_SYNTAX;
3048                         }
3049
3050                         x.bv_val++;
3051                         x.bv_len--;
3052                 } while ( 1 );
3053
3054                 /* should have no characters left... */
3055                 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3056
3057                 if ( numdquotes == 0 ) {
3058                         ber_dupbv_x( &ni, is, ctx );
3059
3060                 } else {
3061                         ber_len_t src, dst;
3062
3063                         ni.bv_len = is->bv_len - numdquotes;
3064                         ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3065                         for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3066                                 if ( is->bv_val[src] == '"' ) {
3067                                         src++;
3068                                 }
3069                                 ni.bv_val[dst] = is->bv_val[src];
3070                         }
3071                         ni.bv_val[dst] = '\0';
3072                 }
3073                         
3074                 *is = ni;
3075         }
3076
3077         return 0;
3078 }
3079         
3080 static int
3081 serialNumberAndIssuerValidate(
3082         Syntax *syntax,
3083         struct berval *in )
3084 {
3085         int rc;
3086         struct berval sn, i;
3087
3088         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3089                 in->bv_val, 0, 0 );
3090
3091         rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3092         if ( rc ) {
3093                 goto done;
3094         }
3095
3096         /* validate DN -- doesn't handle double dquote */ 
3097         rc = dnValidate( NULL, &i );
3098         if ( rc ) {
3099                 rc = LDAP_INVALID_SYNTAX;
3100         }
3101
3102         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3103                 slap_sl_free( i.bv_val, NULL );
3104         }
3105
3106         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3107                 in->bv_val, rc, 0 );
3108
3109 done:;
3110         return rc;
3111 }
3112
3113 static int
3114 serialNumberAndIssuerPretty(
3115         Syntax *syntax,
3116         struct berval *in,
3117         struct berval *out,
3118         void *ctx )
3119 {
3120         int rc;
3121         struct berval sn, i, ni = BER_BVNULL;
3122         char *p;
3123
3124         assert( in != NULL );
3125         assert( out != NULL );
3126
3127         BER_BVZERO( out );
3128
3129         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3130                 in->bv_val, 0, 0 );
3131
3132         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3133         if ( rc ) {
3134                 goto done;
3135         }
3136
3137         rc = dnPretty( syntax, &i, &ni, ctx );
3138
3139         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3140                 slap_sl_free( i.bv_val, ctx );
3141         }
3142
3143         if ( rc ) {
3144                 rc = LDAP_INVALID_SYNTAX;
3145                 goto done;
3146         }
3147
3148         /* make room from sn + "$" */
3149         out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3150                 + sn.bv_len + ni.bv_len;
3151         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3152
3153         if ( out->bv_val == NULL ) {
3154                 out->bv_len = 0;
3155                 rc = LDAP_OTHER;
3156                 goto done;
3157         }
3158
3159         p = out->bv_val;
3160         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3161         p = lutil_strncopy( p, sn.bv_val, sn.bv_len );
3162         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3163         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3164         p = lutil_strcopy( p, /*{*/ "\" }" );
3165
3166         assert( p == &out->bv_val[out->bv_len] );
3167
3168 done:;
3169         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3170                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3171
3172         slap_sl_free( ni.bv_val, ctx );
3173
3174         return LDAP_SUCCESS; 
3175 }
3176
3177 static int
3178 slap_bin2hex(
3179         struct berval *in,
3180         struct berval *out,
3181         void *ctx )
3182
3183 {       
3184         /* Use hex format. '123456789abcdef'H */
3185         unsigned char *ptr, zero = '\0';
3186         char *sptr;
3187         int first;
3188         ber_len_t i, len, nlen;
3189
3190         assert( in != NULL );
3191         assert( !BER_BVISNULL( in ) );
3192         assert( out != NULL );
3193         assert( !BER_BVISNULL( out ) );
3194
3195         ptr = (unsigned char *)in->bv_val;
3196         len = in->bv_len;
3197
3198         /* Check for minimal encodings */
3199         if ( len > 1 ) {
3200                 if ( ptr[0] & 0x80 ) {
3201                         if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3202                                 return -1;
3203                         }
3204
3205                 } else if ( ptr[0] == 0 ) {
3206                         if ( !( ptr[1] & 0x80 ) ) {
3207                                 return -1;
3208                         }
3209                         len--;
3210                         ptr++;
3211                 }
3212
3213         } else if ( len == 0 ) {
3214                 /* FIXME: this should not be possible,
3215                  * since a value of zero would have length 1 */
3216                 len = 1;
3217                 ptr = &zero;
3218         }
3219
3220         first = !( ptr[0] & 0xf0U );
3221         nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3222         if ( nlen >= out->bv_len ) {
3223                 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3224         }
3225         sptr = out->bv_val;
3226         *sptr++ = '\'';
3227         i = 0;
3228         if ( first ) {
3229                 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3230                 sptr++;
3231                 i = 1;
3232         }
3233         for ( ; i < len; i++ ) {
3234                 sprintf( sptr, "%02X", ptr[i] );
3235                 sptr += 2;
3236         }
3237         *sptr++ = '\'';
3238         *sptr++ = 'H';
3239         *sptr = '\0';
3240
3241         assert( sptr == &out->bv_val[nlen] );
3242
3243         out->bv_len = nlen;
3244
3245         return 0;
3246 }
3247
3248 #define SLAP_SN_BUFLEN  (64)
3249
3250 /*
3251  * This routine is called by certificateExactNormalize when
3252  * certificateExactNormalize receives a search string instead of
3253  * a certificate. This routine checks if the search value is valid
3254  * and then returns the normalized value
3255  */
3256 static int
3257 serialNumberAndIssuerNormalize(
3258         slap_mask_t usage,
3259         Syntax *syntax,
3260         MatchingRule *mr,
3261         struct berval *in,
3262         struct berval *out,
3263         void *ctx )
3264 {
3265         struct berval sn, sn2, sn3, i, ni;
3266         char sbuf2[SLAP_SN_BUFLEN];
3267         char sbuf3[SLAP_SN_BUFLEN];
3268         char *p;
3269         int rc;
3270
3271         assert( in != NULL );
3272         assert( out != NULL );
3273
3274         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3275                 in->bv_val, 0, 0 );
3276
3277         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3278         if ( rc ) {
3279                 return rc;
3280         }
3281
3282         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3283
3284         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3285                 slap_sl_free( i.bv_val, ctx );
3286         }
3287
3288         if ( rc ) {
3289                 return LDAP_INVALID_SYNTAX;
3290         }
3291
3292         /* Convert sn to canonical hex */
3293         sn2.bv_val = sbuf2;
3294         if ( sn.bv_len > sizeof( sbuf2 ) ) {
3295                 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3296         }
3297         sn2.bv_len = sn.bv_len;
3298         if ( lutil_str2bin( &sn, &sn2, ctx )) {
3299                 rc = LDAP_INVALID_SYNTAX;
3300                 goto func_leave;
3301         }
3302
3303         sn3.bv_val = sbuf3;
3304         sn3.bv_len = sizeof(sbuf3);
3305         if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
3306                 rc = LDAP_INVALID_SYNTAX;
3307                 goto func_leave;
3308         }
3309
3310         out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3311                 + sn3.bv_len + ni.bv_len;
3312         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3313
3314         if ( out->bv_val == NULL ) {
3315                 out->bv_len = 0;
3316                 rc = LDAP_OTHER;
3317                 goto func_leave;
3318         }
3319
3320         p = out->bv_val;
3321
3322         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3323         p = lutil_strncopy( p, sn3.bv_val, sn3.bv_len );
3324         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3325         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3326         p = lutil_strcopy( p, /*{*/ "\" }" );
3327
3328         assert( p == &out->bv_val[out->bv_len] );
3329
3330 func_leave:
3331         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3332                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3333
3334         if ( sn2.bv_val != sbuf2 ) {
3335                 slap_sl_free( sn2.bv_val, ctx );
3336         }
3337
3338         if ( sn3.bv_val != sbuf3 ) {
3339                 slap_sl_free( sn3.bv_val, ctx );
3340         }
3341
3342         slap_sl_free( ni.bv_val, ctx );
3343
3344         return rc;
3345 }
3346
3347 static int
3348 certificateExactNormalize(
3349         slap_mask_t usage,
3350         Syntax *syntax,
3351         MatchingRule *mr,
3352         struct berval *val,
3353         struct berval *normalized,
3354         void *ctx )
3355 {
3356         BerElementBuffer berbuf;
3357         BerElement *ber = (BerElement *)&berbuf;
3358         ber_tag_t tag;
3359         ber_len_t len;
3360         ber_int_t i;
3361         char serialbuf2[SLAP_SN_BUFLEN];
3362         struct berval sn, sn2 = BER_BVNULL;
3363         struct berval issuer_dn = BER_BVNULL, bvdn;
3364         char *p;
3365         int rc = LDAP_INVALID_SYNTAX;
3366
3367         assert( val != NULL );
3368
3369         Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3370                 val->bv_val, val->bv_len, 0 );
3371
3372         if ( BER_BVISEMPTY( val ) ) goto done;
3373
3374         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3375                 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3376         }
3377
3378         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3379
3380         ber_init2( ber, val, LBER_USE_DER );
3381         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
3382         tag = ber_skip_tag( ber, &len );        /* Sequence */
3383         tag = ber_peek_tag( ber, &len );        /* Optional version? */
3384         if ( tag == SLAP_X509_OPT_C_VERSION ) {
3385                 tag = ber_skip_tag( ber, &len );
3386                 tag = ber_get_int( ber, &i );   /* version */
3387         }
3388
3389         /* NOTE: move the test here from certificateValidate,
3390          * so that we can validate certs with serial longer
3391          * than sizeof(ber_int_t) */
3392         tag = ber_skip_tag( ber, &len );        /* serial */
3393         sn.bv_len = len;
3394         sn.bv_val = (char *)ber->ber_ptr;
3395         sn2.bv_val = serialbuf2;
3396         sn2.bv_len = sizeof(serialbuf2);
3397         if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3398                 rc = LDAP_INVALID_SYNTAX;
3399                 goto done;
3400         }
3401         ber_skip_data( ber, len );
3402
3403         tag = ber_skip_tag( ber, &len );        /* SignatureAlg */
3404         ber_skip_data( ber, len );
3405         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
3406         len = ber_ptrlen( ber );
3407         bvdn.bv_val = val->bv_val + len;
3408         bvdn.bv_len = val->bv_len - len;
3409
3410         rc = dnX509normalize( &bvdn, &issuer_dn );
3411         if ( rc != LDAP_SUCCESS ) goto done;
3412
3413         normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3414                 + sn2.bv_len + issuer_dn.bv_len;
3415         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3416
3417         p = normalized->bv_val;
3418
3419         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3420         p = lutil_strncopy( p, sn2.bv_val, sn2.bv_len );
3421         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3422         p = lutil_strncopy( p, issuer_dn.bv_val, issuer_dn.bv_len );
3423         p = lutil_strcopy( p, /*{*/ "\" }" );
3424
3425         rc = LDAP_SUCCESS;
3426
3427 done:
3428         Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3429                 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3430
3431         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3432         if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3433
3434         return rc;
3435 }
3436
3437 /* X.509 PKI certificateList stuff */
3438 static int
3439 checkTime( struct berval *in, struct berval *out )
3440 {
3441         int rc;
3442         ber_len_t i;
3443         char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3444         struct berval bv;
3445
3446         assert( in != NULL );
3447         assert( !BER_BVISNULL( in ) );
3448         assert( !BER_BVISEMPTY( in ) );
3449
3450         if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3451                 return -1;
3452         }
3453
3454         if ( out != NULL ) {
3455                 assert( !BER_BVISNULL( out ) );
3456                 assert( out->bv_len >= sizeof( buf ) );
3457                 bv.bv_val = out->bv_val;
3458
3459         } else {
3460                 bv.bv_val = buf;
3461         }
3462
3463         for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3464                 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3465         }
3466
3467         if ( in->bv_val[i] != 'Z' ) {
3468                 return -1;
3469         }
3470         i++;
3471
3472         if ( i != in->bv_len ) {
3473                 return -1;
3474         }
3475
3476         if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3477                 lutil_strncopy( bv.bv_val, in->bv_val, i );
3478                 bv.bv_len = i;
3479                 
3480         } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3481                 char *p = bv.bv_val;
3482                 if ( in->bv_val[0] < '7' ) {
3483                         p = lutil_strcopy( p, "20" );
3484
3485                 } else {
3486                         p = lutil_strcopy( p, "19" );
3487                 }
3488                 lutil_strncopy( p, in->bv_val, i );
3489                 bv.bv_len = 2 + i;
3490
3491         } else {
3492                 return -1;
3493         }
3494
3495         rc = generalizedTimeValidate( NULL, &bv );
3496         if ( rc == LDAP_SUCCESS && out != NULL ) {
3497                 out->bv_len = bv.bv_len;
3498         }
3499
3500         return rc != LDAP_SUCCESS;
3501 }
3502
3503 static int
3504 issuerAndThisUpdateCheck(
3505         struct berval *in,
3506         struct berval *is,
3507         struct berval *tu,
3508         void *ctx )
3509 {
3510         int numdquotes = 0;
3511         struct berval x = *in;
3512         struct berval ni = BER_BVNULL;
3513         /* Parse GSER format */ 
3514         enum {
3515                 HAVE_NONE = 0x0,
3516                 HAVE_ISSUER = 0x1,
3517                 HAVE_THISUPDATE = 0x2,
3518                 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3519         } have = HAVE_NONE;
3520
3521
3522         if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3523
3524         if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3525                 return LDAP_INVALID_SYNTAX;
3526         }
3527
3528         x.bv_val++;
3529         x.bv_len -= STRLENOF("{}");
3530
3531         do {
3532                 /* eat leading spaces */
3533                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3534                         /* empty */;
3535                 }
3536
3537                 /* should be at issuer or thisUpdate */
3538                 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3539                         if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3540
3541                         /* parse issuer */
3542                         x.bv_val += STRLENOF("issuer");
3543                         x.bv_len -= STRLENOF("issuer");
3544
3545                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3546                         x.bv_val++;
3547                         x.bv_len--;
3548
3549                         /* eat leading spaces */
3550                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3551                                 /* empty */;
3552                         }
3553
3554                         /* For backward compatibility, this part is optional */
3555                         if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3556                                 return LDAP_INVALID_SYNTAX;
3557                         }
3558                         x.bv_val += STRLENOF("rdnSequence:");
3559                         x.bv_len -= STRLENOF("rdnSequence:");
3560
3561                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3562                         x.bv_val++;
3563                         x.bv_len--;
3564
3565                         is->bv_val = x.bv_val;
3566                         is->bv_len = 0;
3567
3568                         for ( ; is->bv_len < x.bv_len; ) {
3569                                 if ( is->bv_val[is->bv_len] != '"' ) {
3570                                         is->bv_len++;
3571                                         continue;
3572                                 }
3573                                 if ( is->bv_val[is->bv_len+1] == '"' ) {
3574                                         /* double dquote */
3575                                         is->bv_len += 2;
3576                                         continue;
3577                                 }
3578                                 break;
3579                         }
3580                         x.bv_val += is->bv_len + 1;
3581                         x.bv_len -= is->bv_len + 1;
3582
3583                         have |= HAVE_ISSUER;
3584
3585                 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3586                 {
3587                         if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3588
3589                         /* parse thisUpdate */
3590                         x.bv_val += STRLENOF("thisUpdate");
3591                         x.bv_len -= STRLENOF("thisUpdate");
3592
3593                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3594                         x.bv_val++;
3595                         x.bv_len--;
3596
3597                         /* eat leading spaces */
3598                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3599                                 /* empty */;
3600                         }
3601
3602                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3603                         x.bv_val++;
3604                         x.bv_len--;
3605
3606                         tu->bv_val = x.bv_val;
3607                         tu->bv_len = 0;
3608
3609                         for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3610                                 if ( tu->bv_val[tu->bv_len] == '"' ) {
3611                                         break;
3612                                 }
3613                         }
3614                         x.bv_val += tu->bv_len + 1;
3615                         x.bv_len -= tu->bv_len + 1;
3616
3617                         have |= HAVE_THISUPDATE;
3618
3619                 } else {
3620                         return LDAP_INVALID_SYNTAX;
3621                 }
3622
3623                 /* eat leading spaces */
3624                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3625                         /* empty */;
3626                 }
3627
3628                 if ( have == HAVE_ALL ) {
3629                         break;
3630                 }
3631
3632                 if ( x.bv_val[0] != ',' ) {
3633                         return LDAP_INVALID_SYNTAX;
3634                 }
3635
3636                 x.bv_val++;
3637                 x.bv_len--;
3638         } while ( 1 );
3639
3640         /* should have no characters left... */
3641         if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3642
3643         if ( numdquotes == 0 ) {
3644                 ber_dupbv_x( &ni, is, ctx );
3645
3646         } else {
3647                 ber_len_t src, dst;
3648
3649                 ni.bv_len = is->bv_len - numdquotes;
3650                 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3651                 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3652                         if ( is->bv_val[src] == '"' ) {
3653                                 src++;
3654                         }
3655                         ni.bv_val[dst] = is->bv_val[src];
3656                 }
3657                 ni.bv_val[dst] = '\0';
3658         }
3659                 
3660         *is = ni;
3661
3662         return 0;
3663 }
3664
3665 static int
3666 issuerAndThisUpdateValidate(
3667         Syntax *syntax,
3668         struct berval *in )
3669 {
3670         int rc;
3671         struct berval i, tu;
3672
3673         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
3674                 in->bv_val, 0, 0 );
3675
3676         rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
3677         if ( rc ) {
3678                 goto done;
3679         }
3680
3681         /* validate DN -- doesn't handle double dquote */ 
3682         rc = dnValidate( NULL, &i );
3683         if ( rc ) {
3684                 rc = LDAP_INVALID_SYNTAX;
3685
3686         } else if ( checkTime( &tu, NULL ) ) {
3687                 rc = LDAP_INVALID_SYNTAX;
3688         }
3689
3690         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3691                 slap_sl_free( i.bv_val, NULL );
3692         }
3693
3694         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
3695                 in->bv_val, rc, 0 );
3696
3697 done:;
3698         return rc;
3699 }
3700
3701 static int
3702 issuerAndThisUpdatePretty(
3703         Syntax *syntax,
3704         struct berval *in,
3705         struct berval *out,
3706         void *ctx )
3707 {
3708         int rc;
3709         struct berval i, tu, ni = BER_BVNULL;
3710         char *p;
3711
3712         assert( in != NULL );
3713         assert( out != NULL );
3714
3715         BER_BVZERO( out );
3716
3717         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
3718                 in->bv_val, 0, 0 );
3719
3720         rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3721         if ( rc ) {
3722                 goto done;
3723         }
3724
3725         rc = dnPretty( syntax, &i, &ni, ctx );
3726
3727         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3728                 slap_sl_free( i.bv_val, ctx );
3729         }
3730
3731         if ( rc || checkTime( &tu, NULL ) ) {
3732                 rc = LDAP_INVALID_SYNTAX;
3733                 goto done;
3734         }
3735
3736         /* make room */
3737         out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
3738                 + ni.bv_len + tu.bv_len;
3739         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3740
3741         if ( out->bv_val == NULL ) {
3742                 out->bv_len = 0;
3743                 rc = LDAP_OTHER;
3744                 goto done;
3745         }
3746
3747         p = out->bv_val;
3748         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
3749         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3750         p = lutil_strcopy( p, "\", thisUpdate \"" );
3751         p = lutil_strncopy( p, tu.bv_val, tu.bv_len );
3752         p = lutil_strcopy( p, /*{*/ "\" }" );
3753
3754         assert( p == &out->bv_val[out->bv_len] );
3755
3756 done:;
3757         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
3758                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3759
3760         slap_sl_free( ni.bv_val, ctx );
3761
3762         return rc; 
3763 }
3764
3765 static int
3766 issuerAndThisUpdateNormalize(
3767         slap_mask_t usage,
3768         Syntax *syntax,
3769         MatchingRule *mr,
3770         struct berval *in,
3771         struct berval *out,
3772         void *ctx )
3773 {
3774         struct berval i, ni, tu, tu2;
3775         char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3776         char *p;
3777         int rc;
3778
3779         assert( in != NULL );
3780         assert( out != NULL );
3781
3782         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
3783                 in->bv_val, 0, 0 );
3784
3785         rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3786         if ( rc ) {
3787                 return rc;
3788         }
3789
3790         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3791
3792         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3793                 slap_sl_free( i.bv_val, ctx );
3794         }
3795
3796         tu2.bv_val = sbuf;
3797         tu2.bv_len = sizeof( sbuf );
3798         if ( rc || checkTime( &tu, &tu2 ) ) {
3799                 return LDAP_INVALID_SYNTAX;
3800         }
3801
3802         out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
3803                 + ni.bv_len + tu2.bv_len;
3804         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3805
3806         if ( out->bv_val == NULL ) {
3807                 out->bv_len = 0;
3808                 rc = LDAP_OTHER;
3809                 goto func_leave;
3810         }
3811
3812         p = out->bv_val;
3813
3814         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
3815         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3816         p = lutil_strcopy( p, "\", thisUpdate \"" );
3817         p = lutil_strncopy( p, tu2.bv_val, tu2.bv_len );
3818         p = lutil_strcopy( p, /*{*/ "\" }" );
3819
3820         assert( p == & out->bv_val[out->bv_len] );
3821
3822 func_leave:
3823         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
3824                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3825
3826         slap_sl_free( ni.bv_val, ctx );
3827
3828         return rc;
3829 }
3830
3831 static int
3832 certificateListExactNormalize(
3833         slap_mask_t usage,
3834         Syntax *syntax,
3835         MatchingRule *mr,
3836         struct berval *val,
3837         struct berval *normalized,
3838         void *ctx )
3839 {
3840         BerElementBuffer berbuf;
3841         BerElement *ber = (BerElement *)&berbuf;
3842         ber_tag_t tag;
3843         ber_len_t len;
3844         ber_int_t version;
3845         struct berval issuer_dn = BER_BVNULL, bvdn,
3846                 thisUpdate, bvtu;
3847         char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3848         int rc = LDAP_INVALID_SYNTAX;
3849
3850         assert( val != NULL );
3851
3852         Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
3853                 val->bv_val, val->bv_len, 0 );
3854
3855         if ( BER_BVISEMPTY( val ) ) goto done;
3856
3857         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3858                 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
3859         }
3860
3861         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3862
3863         ber_init2( ber, val, LBER_USE_DER );
3864         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
3865         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
3866         tag = ber_skip_tag( ber, &len );        /* Sequence */
3867         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
3868         tag = ber_peek_tag( ber, &len );
3869         /* Optional version */
3870         if ( tag == LBER_INTEGER ) {
3871                 tag = ber_get_int( ber, &version );
3872                 assert( tag == LBER_INTEGER );
3873                 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
3874         }
3875         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
3876         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
3877         ber_skip_data( ber, len );
3878
3879         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
3880         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
3881         len = ber_ptrlen( ber );
3882         bvdn.bv_val = val->bv_val + len;
3883         bvdn.bv_len = val->bv_len - len;
3884         tag = ber_skip_tag( ber, &len );
3885         ber_skip_data( ber, len );
3886
3887         tag = ber_skip_tag( ber, &len );        /* thisUpdate */
3888         /* Time is a CHOICE { UTCTime, GeneralizedTime } */
3889         if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
3890         bvtu.bv_val = (char *)ber->ber_ptr;
3891         bvtu.bv_len = len;
3892
3893         rc = dnX509normalize( &bvdn, &issuer_dn );
3894         if ( rc != LDAP_SUCCESS ) goto done;
3895
3896         thisUpdate.bv_val = tubuf;
3897         thisUpdate.bv_len = sizeof(tubuf);
3898         if ( checkTime( &bvtu, &thisUpdate ) ) {
3899                 rc = LDAP_INVALID_SYNTAX;
3900                 goto done;
3901         }
3902
3903         normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
3904                 + issuer_dn.bv_len + thisUpdate.bv_len;
3905         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3906
3907         p = normalized->bv_val;
3908
3909         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
3910         p = lutil_strncopy( p, issuer_dn.bv_val, issuer_dn.bv_len );
3911         p = lutil_strcopy( p, "\", thisUpdate \"" );
3912         p = lutil_strncopy( p, thisUpdate.bv_val, thisUpdate.bv_len );
3913         p = lutil_strcopy( p, /*{*/ "\" }" );
3914
3915         rc = LDAP_SUCCESS;
3916
3917 done:
3918         Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
3919                 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3920
3921         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3922
3923         return rc;
3924 }
3925
3926 static int
3927 hexValidate(
3928         Syntax *syntax,
3929         struct berval *in )
3930 {
3931         ber_len_t       i;
3932
3933         assert( in != NULL );
3934         assert( !BER_BVISNULL( in ) );
3935
3936         for ( i = 0; i < in->bv_len; i++ ) {
3937                 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
3938                         return LDAP_INVALID_SYNTAX;
3939                 }
3940         }
3941
3942         return LDAP_SUCCESS;
3943 }
3944
3945 /* Normalize a SID as used inside a CSN:
3946  * three-digit numeric string */
3947 static int
3948 hexNormalize(
3949         slap_mask_t usage,
3950         Syntax *syntax,
3951         MatchingRule *mr,
3952         struct berval *val,
3953         struct berval *normalized,
3954         void *ctx )
3955 {
3956         ber_len_t       i;
3957
3958         assert( val != NULL );
3959         assert( normalized != NULL );
3960
3961         ber_dupbv_x( normalized, val, ctx );
3962
3963         for ( i = 0; i < normalized->bv_len; i++ ) {
3964                 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
3965                         ber_memfree_x( normalized->bv_val, ctx );
3966                         BER_BVZERO( normalized );
3967                         return LDAP_INVALID_SYNTAX;
3968                 }
3969
3970                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3971         }
3972
3973         return LDAP_SUCCESS;
3974 }
3975
3976 static int
3977 sidValidate (
3978         Syntax *syntax,
3979         struct berval *in )
3980 {
3981         assert( in != NULL );
3982         assert( !BER_BVISNULL( in ) );
3983
3984         if ( in->bv_len != 3 ) {
3985                 return LDAP_INVALID_SYNTAX;
3986         }
3987
3988         return hexValidate( NULL, in );
3989 }
3990
3991 /* Normalize a SID as used inside a CSN:
3992  * three-digit numeric string */
3993 static int
3994 sidNormalize(
3995         slap_mask_t usage,
3996         Syntax *syntax,
3997         MatchingRule *mr,
3998         struct berval *val,
3999         struct berval *normalized,
4000         void *ctx )
4001 {
4002         if ( val->bv_len != 3 ) {
4003                 return LDAP_INVALID_SYNTAX;
4004         }
4005
4006         return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
4007 }
4008
4009 static int
4010 sidPretty(
4011         Syntax *syntax,
4012         struct berval *val,
4013         struct berval *out,
4014         void *ctx )
4015 {
4016         return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
4017 }
4018
4019 /* Normalize a SID as used inside a CSN, either as-is
4020  * (assertion value) or extracted from the CSN
4021  * (attribute value) */
4022 static int
4023 csnSidNormalize(
4024         slap_mask_t usage,
4025         Syntax *syntax,
4026         MatchingRule *mr,
4027         struct berval *val,
4028         struct berval *normalized,
4029         void *ctx )
4030 {
4031         struct berval   bv;
4032         char            *ptr,
4033                         buf[ 4 ];
4034
4035
4036         if ( BER_BVISEMPTY( val ) ) {
4037                 return LDAP_INVALID_SYNTAX;
4038         }
4039
4040         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4041                 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
4042         }
4043
4044         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4045
4046         ptr = ber_bvchr( val, '#' );
4047         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4048                 return LDAP_INVALID_SYNTAX;
4049         }
4050
4051         bv.bv_val = ptr + 1;
4052         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
4053
4054         ptr = ber_bvchr( &bv, '#' );
4055         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4056                 return LDAP_INVALID_SYNTAX;
4057         }
4058
4059         bv.bv_val = ptr + 1;
4060         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
4061                 
4062         ptr = ber_bvchr( &bv, '#' );
4063         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4064                 return LDAP_INVALID_SYNTAX;
4065         }
4066
4067         bv.bv_len = ptr - bv.bv_val;
4068
4069         if ( bv.bv_len == 2 ) {
4070                 /* OpenLDAP 2.3 SID */
4071                 buf[ 0 ] = '0';
4072                 buf[ 1 ] = bv.bv_val[ 0 ];
4073                 buf[ 2 ] = bv.bv_val[ 1 ];
4074                 buf[ 3 ] = '\0';
4075
4076                 bv.bv_val = buf;
4077                 bv.bv_len = 3;
4078         }
4079
4080         return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
4081 }
4082
4083 static int
4084 csnValidate(
4085         Syntax *syntax,
4086         struct berval *in )
4087 {
4088         struct berval   bv;
4089         char            *ptr;
4090         int             rc;
4091
4092         assert( in != NULL );
4093         assert( !BER_BVISNULL( in ) );
4094
4095         if ( BER_BVISEMPTY( in ) ) {
4096                 return LDAP_INVALID_SYNTAX;
4097         }
4098
4099         bv = *in;
4100
4101         ptr = ber_bvchr( &bv, '#' );
4102         if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
4103                 return LDAP_INVALID_SYNTAX;
4104         }
4105
4106         bv.bv_len = ptr - bv.bv_val;
4107         if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
4108                 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
4109         {
4110                 return LDAP_INVALID_SYNTAX;
4111         }
4112
4113         rc = generalizedTimeValidate( NULL, &bv );
4114         if ( rc != LDAP_SUCCESS ) {
4115                 return rc;
4116         }
4117
4118         bv.bv_val = ptr + 1;
4119         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
4120
4121         ptr = ber_bvchr( &bv, '#' );
4122         if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
4123                 return LDAP_INVALID_SYNTAX;
4124         }
4125
4126         bv.bv_len = ptr - bv.bv_val;
4127         if ( bv.bv_len != 6 ) {
4128                 return LDAP_INVALID_SYNTAX;
4129         }
4130
4131         rc = hexValidate( NULL, &bv );
4132         if ( rc != LDAP_SUCCESS ) {
4133                 return rc;
4134         }
4135
4136         bv.bv_val = ptr + 1;
4137         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
4138
4139         ptr = ber_bvchr( &bv, '#' );
4140         if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
4141                 return LDAP_INVALID_SYNTAX;
4142         }
4143
4144         bv.bv_len = ptr - bv.bv_val;
4145         if ( bv.bv_len == 2 ) {
4146                 /* tolerate old 2-digit replica-id */
4147                 rc = hexValidate( NULL, &bv );
4148
4149         } else {
4150                 rc = sidValidate( NULL, &bv );
4151         }
4152         if ( rc != LDAP_SUCCESS ) {
4153                 return rc;
4154         }
4155
4156         bv.bv_val = ptr + 1;
4157         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
4158
4159         if ( bv.bv_len != 6 ) {
4160                 return LDAP_INVALID_SYNTAX;
4161         }
4162
4163         return hexValidate( NULL, &bv );
4164 }
4165
4166 /* Normalize a CSN in OpenLDAP 2.1 format */
4167 static int
4168 csnNormalize21(
4169         slap_mask_t usage,
4170         Syntax *syntax,
4171         MatchingRule *mr,
4172         struct berval *val,
4173         struct berval *normalized,
4174         void *ctx )
4175 {
4176         struct berval   gt, cnt, sid, mod;
4177         struct berval   bv;
4178         char            buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
4179         char            *ptr;
4180         ber_len_t       i;
4181
4182         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
4183         assert( !BER_BVISEMPTY( val ) );
4184
4185         gt = *val;
4186
4187         ptr = ber_bvchr( &gt, '#' );
4188         if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
4189                 return LDAP_INVALID_SYNTAX;
4190         }
4191
4192         gt.bv_len = ptr - gt.bv_val;
4193         if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
4194                 return LDAP_INVALID_SYNTAX;
4195         }
4196
4197         if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
4198                 return LDAP_INVALID_SYNTAX;
4199         }
4200
4201         cnt.bv_val = ptr + 1;
4202         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
4203
4204         ptr = ber_bvchr( &cnt, '#' );
4205         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4206                 return LDAP_INVALID_SYNTAX;
4207         }
4208
4209         cnt.bv_len = ptr - cnt.bv_val;
4210         if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
4211                 return LDAP_INVALID_SYNTAX;
4212         }
4213
4214         if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
4215                 return LDAP_INVALID_SYNTAX;
4216         }
4217
4218         cnt.bv_val += STRLENOF( "0x" );
4219         cnt.bv_len -= STRLENOF( "0x" );
4220
4221         sid.bv_val = ptr + 1;
4222         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
4223                 
4224         ptr = ber_bvchr( &sid, '#' );
4225         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4226                 return LDAP_INVALID_SYNTAX;
4227         }
4228
4229         sid.bv_len = ptr - sid.bv_val;
4230         if ( sid.bv_len != STRLENOF( "0" ) ) {
4231                 return LDAP_INVALID_SYNTAX;
4232         }
4233
4234         mod.bv_val = ptr + 1;
4235         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
4236         if ( mod.bv_len != STRLENOF( "0000" ) ) {
4237                 return LDAP_INVALID_SYNTAX;
4238         }
4239
4240         bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
4241         bv.bv_val = buf;
4242
4243         ptr = bv.bv_val;
4244         ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
4245         ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
4246                 STRLENOF( "MM" ) );
4247         ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
4248                 STRLENOF( "SS" ) );
4249         ptr = lutil_strcopy( ptr, ".000000Z#00" );
4250         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
4251         *ptr++ = '#';
4252         *ptr++ = '0';
4253         *ptr++ = '0';
4254         *ptr++ = sid.bv_val[ 0 ];
4255         *ptr++ = '#';
4256         *ptr++ = '0';
4257         *ptr++ = '0';
4258         for ( i = 0; i < mod.bv_len; i++ ) {
4259                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
4260         }
4261         *ptr = '\0';
4262
4263         assert( ptr == &bv.bv_val[bv.bv_len] );
4264
4265         if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
4266                 return LDAP_INVALID_SYNTAX;
4267         }
4268
4269         ber_dupbv_x( normalized, &bv, ctx );
4270
4271         return LDAP_SUCCESS;
4272 }
4273
4274 /* Normalize a CSN in OpenLDAP 2.3 format */
4275 static int
4276 csnNormalize23(
4277         slap_mask_t usage,
4278         Syntax *syntax,
4279         MatchingRule *mr,
4280         struct berval *val,
4281         struct berval *normalized,
4282         void *ctx )
4283 {
4284         struct berval   gt, cnt, sid, mod;
4285         struct berval   bv;
4286         char            buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
4287         char            *ptr;
4288         ber_len_t       i;
4289
4290         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
4291         assert( !BER_BVISEMPTY( val ) );
4292
4293         gt = *val;
4294
4295         ptr = ber_bvchr( &gt, '#' );
4296         if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
4297                 return LDAP_INVALID_SYNTAX;
4298         }
4299
4300         gt.bv_len = ptr - gt.bv_val;
4301         if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
4302                 return LDAP_INVALID_SYNTAX;
4303         }
4304
4305         cnt.bv_val = ptr + 1;
4306         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
4307
4308         ptr = ber_bvchr( &cnt, '#' );
4309         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4310                 return LDAP_INVALID_SYNTAX;
4311         }
4312
4313         cnt.bv_len = ptr - cnt.bv_val;
4314         if ( cnt.bv_len != STRLENOF( "000000" ) ) {
4315                 return LDAP_INVALID_SYNTAX;
4316         }
4317
4318         sid.bv_val = ptr + 1;
4319         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
4320                 
4321         ptr = ber_bvchr( &sid, '#' );
4322         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4323                 return LDAP_INVALID_SYNTAX;
4324         }
4325
4326         sid.bv_len = ptr - sid.bv_val;
4327         if ( sid.bv_len != STRLENOF( "00" ) ) {
4328                 return LDAP_INVALID_SYNTAX;
4329         }
4330
4331         mod.bv_val = ptr + 1;
4332         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
4333         if ( mod.bv_len != STRLENOF( "000000" ) ) {
4334                 return LDAP_INVALID_SYNTAX;
4335         }
4336
4337         bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
4338         bv.bv_val = buf;
4339
4340         ptr = bv.bv_val;
4341         ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
4342         ptr = lutil_strcopy( ptr, ".000000Z#" );
4343         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
4344         *ptr++ = '#';
4345         *ptr++ = '0';
4346         for ( i = 0; i < sid.bv_len; i++ ) {
4347                 *ptr++ = TOLOWER( sid.bv_val[ i ] );
4348         }
4349         *ptr++ = '#';
4350         for ( i = 0; i < mod.bv_len; i++ ) {
4351                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
4352         }
4353         *ptr = '\0';
4354
4355         assert( ptr == &bv.bv_val[bv.bv_len] );
4356         if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
4357                 return LDAP_INVALID_SYNTAX;
4358         }
4359
4360         ber_dupbv_x( normalized, &bv, ctx );
4361
4362         return LDAP_SUCCESS;
4363 }
4364
4365 /* Normalize a CSN */
4366 static int
4367 csnNormalize(
4368         slap_mask_t usage,
4369         Syntax *syntax,
4370         MatchingRule *mr,
4371         struct berval *val,
4372         struct berval *normalized,
4373         void *ctx )
4374 {
4375         struct berval   cnt, sid, mod;
4376         char            *ptr;
4377         ber_len_t       i;
4378
4379         assert( val != NULL );
4380         assert( normalized != NULL );
4381
4382         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
4383
4384         if ( BER_BVISEMPTY( val ) ) {
4385                 return LDAP_INVALID_SYNTAX;
4386         }
4387
4388         if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
4389                 /* Openldap <= 2.3 */
4390
4391                 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
4392         }
4393
4394         if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
4395                 /* Openldap 2.1 */
4396
4397                 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
4398         }
4399
4400         if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
4401                 return LDAP_INVALID_SYNTAX;
4402         }
4403
4404         ptr = ber_bvchr( val, '#' );
4405         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4406                 return LDAP_INVALID_SYNTAX;
4407         }
4408
4409         if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
4410                 return LDAP_INVALID_SYNTAX;
4411         }
4412
4413         cnt.bv_val = ptr + 1;
4414         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
4415
4416         ptr = ber_bvchr( &cnt, '#' );
4417         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4418                 return LDAP_INVALID_SYNTAX;
4419         }
4420
4421         if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
4422                 return LDAP_INVALID_SYNTAX;
4423         }
4424
4425         sid.bv_val = ptr + 1;
4426         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
4427                 
4428         ptr = ber_bvchr( &sid, '#' );
4429         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4430                 return LDAP_INVALID_SYNTAX;
4431         }
4432
4433         sid.bv_len = ptr - sid.bv_val;
4434         if ( sid.bv_len != STRLENOF( "000" ) ) {
4435                 return LDAP_INVALID_SYNTAX;
4436         }
4437
4438         mod.bv_val = ptr + 1;
4439         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
4440
4441         if ( mod.bv_len != STRLENOF( "000000" ) ) {
4442                 return LDAP_INVALID_SYNTAX;
4443         }
4444
4445         ber_dupbv_x( normalized, val, ctx );
4446
4447         for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
4448                 i < normalized->bv_len; i++ )
4449         {
4450                 /* assume it's already validated that's all hex digits */
4451                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
4452         }
4453
4454         return LDAP_SUCCESS;
4455 }
4456
4457 static int
4458 csnPretty(
4459         Syntax *syntax,
4460         struct berval *val,
4461         struct berval *out,
4462         void *ctx )
4463 {
4464         return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
4465 }
4466
4467 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
4468 /* slight optimization - does not need the start parameter */
4469 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
4470 enum { start = 0 };
4471 #endif
4472
4473 static int
4474 check_time_syntax (struct berval *val,
4475         int start,
4476         int *parts,
4477         struct berval *fraction)
4478 {
4479         /*
4480          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
4481          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
4482          * GeneralizedTime supports leap seconds, UTCTime does not.
4483          */
4484         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
4485         static const int mdays[2][12] = {
4486                 /* non-leap years */
4487                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
4488                 /* leap years */
4489                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
4490         };
4491         char *p, *e;
4492         int part, c, c1, c2, tzoffset, leapyear = 0;
4493
4494         p = val->bv_val;
4495         e = p + val->bv_len;
4496
4497 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4498         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
4499 #endif
4500         for (part = start; part < 7 && p < e; part++) {
4501                 c1 = *p;
4502                 if (!ASCII_DIGIT(c1)) {
4503                         break;
4504                 }
4505                 p++;
4506                 if (p == e) {
4507                         return LDAP_INVALID_SYNTAX;
4508                 }
4509                 c = *p++;
4510                 if (!ASCII_DIGIT(c)) {
4511                         return LDAP_INVALID_SYNTAX;
4512                 }
4513                 c += c1 * 10 - '0' * 11;
4514                 if ((part | 1) == 3) {
4515                         --c;
4516                         if (c < 0) {
4517                                 return LDAP_INVALID_SYNTAX;
4518                         }
4519                 }
4520                 if (c >= ceiling[part]) {
4521                         if (! (c == 60 && part == 6 && start == 0))
4522                                 return LDAP_INVALID_SYNTAX;
4523                 }
4524                 parts[part] = c;
4525         }
4526         if (part < 5 + start) {
4527                 return LDAP_INVALID_SYNTAX;
4528         }
4529         for (; part < 9; part++) {
4530                 parts[part] = 0;
4531         }
4532
4533         /* leapyear check for the Gregorian calendar (year>1581) */
4534         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
4535                 leapyear = 1;
4536         }
4537
4538         if (parts[3] >= mdays[leapyear][parts[2]]) {
4539                 return LDAP_INVALID_SYNTAX;
4540         }
4541
4542         if (start == 0) {
4543                 fraction->bv_val = p;
4544                 fraction->bv_len = 0;
4545                 if (p < e && (*p == '.' || *p == ',')) {
4546                         char *end_num;
4547                         while (++p < e && ASCII_DIGIT(*p)) {
4548                                 /* EMTPY */;
4549                         }
4550                         if (p - fraction->bv_val == 1) {
4551                                 return LDAP_INVALID_SYNTAX;
4552                         }
4553                         for (end_num = p; end_num[-1] == '0'; --end_num) {
4554                                 /* EMPTY */;
4555                         }
4556                         c = end_num - fraction->bv_val;
4557                         if (c != 1) fraction->bv_len = c;
4558                 }
4559         }
4560
4561         if (p == e) {
4562                 /* no time zone */
4563                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
4564         }
4565
4566         tzoffset = *p++;
4567         switch (tzoffset) {
4568         default:
4569                 return LDAP_INVALID_SYNTAX;
4570         case 'Z':
4571                 /* UTC */
4572                 break;
4573         case '+':
4574         case '-':
4575                 for (part = 7; part < 9 && p < e; part++) {
4576                         c1 = *p;
4577                         if (!ASCII_DIGIT(c1)) {
4578                                 break;
4579                         }
4580                         p++;
4581                         if (p == e) {
4582                                 return LDAP_INVALID_SYNTAX;
4583                         }
4584                         c2 = *p++;
4585                         if (!ASCII_DIGIT(c2)) {
4586                                 return LDAP_INVALID_SYNTAX;
4587                         }
4588                         parts[part] = c1 * 10 + c2 - '0' * 11;
4589                         if (parts[part] >= ceiling[part]) {
4590                                 return LDAP_INVALID_SYNTAX;
4591                         }
4592                 }
4593                 if (part < 8 + start) {
4594                         return LDAP_INVALID_SYNTAX;
4595                 }
4596
4597                 if (tzoffset == '-') {
4598                         /* negative offset to UTC, ie west of Greenwich */
4599                         parts[4] += parts[7];
4600                         parts[5] += parts[8];
4601                         /* offset is just hhmm, no seconds */
4602                         for (part = 6; --part >= 0; ) {
4603                                 if (part != 3) {
4604                                         c = ceiling[part];
4605                                 } else {
4606                                         c = mdays[leapyear][parts[2]];
4607                                 }
4608                                 if (parts[part] >= c) {
4609                                         if (part == 0) {
4610                                                 return LDAP_INVALID_SYNTAX;
4611                                         }
4612                                         parts[part] -= c;
4613                                         parts[part - 1]++;
4614                                         continue;
4615                                 } else if (part != 5) {
4616                                         break;
4617                                 }
4618                         }
4619                 } else {
4620                         /* positive offset to UTC, ie east of Greenwich */
4621                         parts[4] -= parts[7];
4622                         parts[5] -= parts[8];
4623                         for (part = 6; --part >= 0; ) {
4624                                 if (parts[part] < 0) {
4625                                         if (part == 0) {
4626                                                 return LDAP_INVALID_SYNTAX;
4627                                         }
4628                                         if (part != 3) {
4629                                                 c = ceiling[part];
4630                                         } else {
4631                                                 /* make first arg to % non-negative */
4632                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
4633                                         }
4634                                         parts[part] += c;
4635                                         parts[part - 1]--;
4636                                         continue;
4637                                 } else if (part != 5) {
4638                                         break;
4639                                 }
4640                         }
4641                 }
4642         }
4643
4644         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
4645 }
4646
4647 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4648
4649 #if 0
4650 static int
4651 xutcTimeNormalize(
4652         Syntax *syntax,
4653         struct berval *val,
4654         struct berval *normalized )
4655 {
4656         int parts[9], rc;
4657
4658         rc = check_time_syntax(val, 1, parts, NULL);
4659         if (rc != LDAP_SUCCESS) {
4660                 return rc;
4661         }
4662
4663         normalized->bv_val = ch_malloc( 14 );
4664         if ( normalized->bv_val == NULL ) {
4665                 return LBER_ERROR_MEMORY;
4666         }
4667
4668         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
4669                 parts[1], parts[2] + 1, parts[3] + 1,
4670                 parts[4], parts[5], parts[6] );
4671         normalized->bv_len = 13;
4672
4673         return LDAP_SUCCESS;
4674 }
4675 #endif /* 0 */
4676
4677 static int
4678 utcTimeValidate(
4679         Syntax *syntax,
4680         struct berval *in )
4681 {
4682         int parts[9];
4683         return check_time_syntax(in, 1, parts, NULL);
4684 }
4685
4686 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
4687
4688 static int
4689 generalizedTimeValidate(
4690         Syntax *syntax,
4691         struct berval *in )
4692 {
4693         int parts[9];
4694         struct berval fraction;
4695         return check_time_syntax(in, 0, parts, &fraction);
4696 }
4697
4698 static int
4699 generalizedTimeNormalize(
4700         slap_mask_t usage,
4701         Syntax *syntax,
4702         MatchingRule *mr,
4703         struct berval *val,
4704         struct berval *normalized,
4705         void *ctx )
4706 {
4707         int parts[9], rc;
4708         unsigned int len;
4709         struct berval fraction;
4710
4711         rc = check_time_syntax(val, 0, parts, &fraction);
4712         if (rc != LDAP_SUCCESS) {
4713                 return rc;
4714         }
4715
4716         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
4717         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
4718         if ( BER_BVISNULL( normalized ) ) {
4719                 return LBER_ERROR_MEMORY;
4720         }
4721
4722         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
4723                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
4724                 parts[4], parts[5], parts[6] );
4725         if ( !BER_BVISEMPTY( &fraction ) ) {
4726                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
4727                         fraction.bv_val, fraction.bv_len );
4728                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
4729         }
4730         strcpy( normalized->bv_val + len-1, "Z" );
4731         normalized->bv_len = len;
4732
4733         return LDAP_SUCCESS;
4734 }
4735
4736 static int
4737 generalizedTimeOrderingMatch(
4738         int *matchp,
4739         slap_mask_t flags,
4740         Syntax *syntax,
4741         MatchingRule *mr,
4742         struct berval *value,
4743         void *assertedValue )
4744 {
4745         struct berval *asserted = (struct berval *) assertedValue;
4746         ber_len_t v_len  = value->bv_len;
4747         ber_len_t av_len = asserted->bv_len;
4748
4749         /* ignore trailing 'Z' when comparing */
4750         int match = memcmp( value->bv_val, asserted->bv_val,
4751                 (v_len < av_len ? v_len : av_len) - 1 );
4752         if ( match == 0 ) match = v_len - av_len;
4753
4754         *matchp = match;
4755         return LDAP_SUCCESS;
4756 }
4757
4758 /* Index generation function */
4759 int generalizedTimeIndexer(
4760         slap_mask_t use,
4761         slap_mask_t flags,
4762         Syntax *syntax,
4763         MatchingRule *mr,
4764         struct berval *prefix,
4765         BerVarray values,
4766         BerVarray *keysp,
4767         void *ctx )
4768 {
4769         int i, j;
4770         BerVarray keys;
4771         char tmp[5];
4772         BerValue bvtmp; /* 40 bit index */
4773         struct lutil_tm tm;
4774         struct lutil_timet tt;
4775
4776         bvtmp.bv_len = sizeof(tmp);
4777         bvtmp.bv_val = tmp;
4778         for( i=0; values[i].bv_val != NULL; i++ ) {
4779                 /* just count them */
4780         }
4781
4782         /* we should have at least one value at this point */
4783         assert( i > 0 );
4784
4785         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
4786
4787         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4788         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
4789                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
4790                 /* Use 40 bits of time for key */
4791                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
4792                         lutil_tm2time( &tm, &tt );
4793                         tmp[0] = tt.tt_gsec & 0xff;
4794                         tmp[4] = tt.tt_sec & 0xff;
4795                         tt.tt_sec >>= 8;
4796                         tmp[3] = tt.tt_sec & 0xff;
4797                         tt.tt_sec >>= 8;
4798                         tmp[2] = tt.tt_sec & 0xff;
4799                         tt.tt_sec >>= 8;
4800                         tmp[1] = tt.tt_sec & 0xff;
4801                         
4802                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
4803                 }
4804         }
4805
4806         keys[j].bv_val = NULL;
4807         keys[j].bv_len = 0;
4808
4809         *keysp = keys;
4810
4811         return LDAP_SUCCESS;
4812 }
4813
4814 /* Index generation function */
4815 int generalizedTimeFilter(
4816         slap_mask_t use,
4817         slap_mask_t flags,
4818         Syntax *syntax,
4819         MatchingRule *mr,
4820         struct berval *prefix,
4821         void * assertedValue,
4822         BerVarray *keysp,
4823         void *ctx )
4824 {
4825         BerVarray keys;
4826         char tmp[5];
4827         BerValue bvtmp; /* 40 bit index */
4828         BerValue *value = (BerValue *) assertedValue;
4829         struct lutil_tm tm;
4830         struct lutil_timet tt;
4831         
4832         bvtmp.bv_len = sizeof(tmp);
4833         bvtmp.bv_val = tmp;
4834         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4835         /* Use 40 bits of time for key */
4836         if ( value->bv_val && value->bv_len >= 10 &&
4837                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
4838
4839                 lutil_tm2time( &tm, &tt );
4840                 tmp[0] = tt.tt_gsec & 0xff;
4841                 tmp[4] = tt.tt_sec & 0xff;
4842                 tt.tt_sec >>= 8;
4843                 tmp[3] = tt.tt_sec & 0xff;
4844                 tt.tt_sec >>= 8;
4845                 tmp[2] = tt.tt_sec & 0xff;
4846                 tt.tt_sec >>= 8;
4847                 tmp[1] = tt.tt_sec & 0xff;
4848
4849                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
4850                 ber_dupbv_x(keys, &bvtmp, ctx );
4851                 keys[1].bv_val = NULL;
4852                 keys[1].bv_len = 0;
4853         } else {
4854                 keys = NULL;
4855         }
4856
4857         *keysp = keys;
4858
4859         return LDAP_SUCCESS;
4860 }
4861
4862 static int
4863 deliveryMethodValidate(
4864         Syntax *syntax,
4865         struct berval *val )
4866 {
4867 #undef LENOF
4868 #define LENOF(s) (sizeof(s)-1)
4869         struct berval tmp = *val;
4870         /*
4871      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
4872          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
4873          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
4874          */
4875 again:
4876         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4877
4878         switch( tmp.bv_val[0] ) {
4879         case 'a':
4880         case 'A':
4881                 if(( tmp.bv_len >= LENOF("any") ) &&
4882                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
4883                 {
4884                         tmp.bv_len -= LENOF("any");
4885                         tmp.bv_val += LENOF("any");
4886                         break;
4887                 }
4888                 return LDAP_INVALID_SYNTAX;
4889
4890         case 'm':
4891         case 'M':
4892                 if(( tmp.bv_len >= LENOF("mhs") ) &&
4893                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
4894                 {
4895                         tmp.bv_len -= LENOF("mhs");
4896                         tmp.bv_val += LENOF("mhs");
4897                         break;
4898                 }
4899                 return LDAP_INVALID_SYNTAX;
4900
4901         case 'p':
4902         case 'P':
4903                 if(( tmp.bv_len >= LENOF("physical") ) &&
4904                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
4905                 {
4906                         tmp.bv_len -= LENOF("physical");
4907                         tmp.bv_val += LENOF("physical");
4908                         break;
4909                 }
4910                 return LDAP_INVALID_SYNTAX;
4911
4912         case 't':
4913         case 'T': /* telex or teletex or telephone */
4914                 if(( tmp.bv_len >= LENOF("telex") ) &&
4915                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
4916                 {
4917                         tmp.bv_len -= LENOF("telex");
4918                         tmp.bv_val += LENOF("telex");
4919                         break;
4920                 }
4921                 if(( tmp.bv_len >= LENOF("teletex") ) &&
4922                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
4923                 {
4924                         tmp.bv_len -= LENOF("teletex");
4925                         tmp.bv_val += LENOF("teletex");
4926                         break;
4927                 }
4928                 if(( tmp.bv_len >= LENOF("telephone") ) &&
4929                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
4930                 {
4931                         tmp.bv_len -= LENOF("telephone");
4932                         tmp.bv_val += LENOF("telephone");
4933                         break;
4934                 }
4935                 return LDAP_INVALID_SYNTAX;
4936
4937         case 'g':
4938         case 'G': /* g3fax or g4fax */
4939                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
4940                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
4941                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
4942                 {
4943                         tmp.bv_len -= LENOF("g3fax");
4944                         tmp.bv_val += LENOF("g3fax");
4945                         break;
4946                 }
4947                 return LDAP_INVALID_SYNTAX;
4948
4949         case 'i':
4950         case 'I':
4951                 if(( tmp.bv_len >= LENOF("ia5") ) &&
4952                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
4953                 {
4954                         tmp.bv_len -= LENOF("ia5");
4955                         tmp.bv_val += LENOF("ia5");
4956                         break;
4957                 }
4958                 return LDAP_INVALID_SYNTAX;
4959
4960         case 'v':
4961         case 'V':
4962                 if(( tmp.bv_len >= LENOF("videotex") ) &&
4963                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
4964                 {
4965                         tmp.bv_len -= LENOF("videotex");
4966                         tmp.bv_val += LENOF("videotex");
4967                         break;
4968                 }
4969                 return LDAP_INVALID_SYNTAX;
4970
4971         default:
4972                 return LDAP_INVALID_SYNTAX;
4973         }
4974
4975         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
4976
4977         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4978                 tmp.bv_len++;
4979                 tmp.bv_val--;
4980         }
4981         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
4982                 tmp.bv_len++;
4983                 tmp.bv_val--;
4984         } else {
4985                 return LDAP_INVALID_SYNTAX;
4986         }
4987         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4988                 tmp.bv_len++;
4989                 tmp.bv_val--;
4990         }
4991
4992         goto again;
4993 }
4994
4995 static int
4996 nisNetgroupTripleValidate(
4997         Syntax *syntax,
4998         struct berval *val )
4999 {
5000         char *p, *e;
5001         int commas = 0;
5002
5003         if ( BER_BVISEMPTY( val ) ) {
5004                 return LDAP_INVALID_SYNTAX;
5005         }
5006
5007         p = (char *)val->bv_val;
5008         e = p + val->bv_len;
5009
5010         if ( *p != '(' /*')'*/ ) {
5011                 return LDAP_INVALID_SYNTAX;
5012         }
5013
5014         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
5015                 if ( *p == ',' ) {
5016                         commas++;
5017                         if ( commas > 2 ) {
5018                                 return LDAP_INVALID_SYNTAX;
5019                         }
5020
5021                 } else if ( !AD_CHAR( *p ) ) {
5022                         return LDAP_INVALID_SYNTAX;
5023                 }
5024         }
5025
5026         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
5027                 return LDAP_INVALID_SYNTAX;
5028         }
5029
5030         p++;
5031
5032         if (p != e) {
5033                 return LDAP_INVALID_SYNTAX;
5034         }
5035
5036         return LDAP_SUCCESS;
5037 }
5038
5039 static int
5040 bootParameterValidate(
5041         Syntax *syntax,
5042         struct berval *val )
5043 {
5044         char *p, *e;
5045
5046         if ( BER_BVISEMPTY( val ) ) {
5047                 return LDAP_INVALID_SYNTAX;
5048         }
5049
5050         p = (char *)val->bv_val;
5051         e = p + val->bv_len;
5052
5053         /* key */
5054         for (; ( p < e ) && ( *p != '=' ); p++ ) {
5055                 if ( !AD_CHAR( *p ) ) {
5056                         return LDAP_INVALID_SYNTAX;
5057                 }
5058         }
5059
5060         if ( *p != '=' ) {
5061                 return LDAP_INVALID_SYNTAX;
5062         }
5063
5064         /* server */
5065         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
5066                 if ( !AD_CHAR( *p ) ) {
5067                         return LDAP_INVALID_SYNTAX;
5068                 }
5069         }
5070
5071         if ( *p != ':' ) {
5072                 return LDAP_INVALID_SYNTAX;
5073         }
5074
5075         /* path */
5076         for ( p++; p < e; p++ ) {
5077                 if ( !SLAP_PRINTABLE( *p ) ) {
5078                         return LDAP_INVALID_SYNTAX;
5079                 }
5080         }
5081
5082         return LDAP_SUCCESS;
5083 }
5084
5085 static int
5086 firstComponentNormalize(
5087         slap_mask_t usage,
5088         Syntax *syntax,
5089         MatchingRule *mr,
5090         struct berval *val,
5091         struct berval *normalized,
5092         void *ctx )
5093 {
5094         int rc;
5095         struct berval comp;
5096         ber_len_t len;
5097
5098         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
5099                 ber_dupbv_x( normalized, val, ctx );
5100                 return LDAP_SUCCESS;
5101         }
5102
5103         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5104
5105         if( ! ( val->bv_val[0] == '(' /*')'*/
5106                         && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
5107                 && ! ( val->bv_val[0] == '{' /*'}'*/
5108                         && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
5109         {
5110                 return LDAP_INVALID_SYNTAX;
5111         }
5112
5113         /* trim leading white space */
5114         for( len=1;
5115                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
5116                 len++ )
5117         {
5118                 /* empty */
5119         }
5120
5121         /* grab next word */
5122         comp.bv_val = &val->bv_val[len];
5123         len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
5124         for( comp.bv_len = 0;
5125                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
5126                 comp.bv_len++ )
5127         {
5128                 /* empty */
5129         }
5130
5131         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
5132                 rc = numericoidValidate( NULL, &comp );
5133         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
5134                 rc = integerValidate( NULL, &comp );
5135         } else {
5136                 rc = LDAP_INVALID_SYNTAX;
5137         }
5138         
5139
5140         if( rc == LDAP_SUCCESS ) {
5141                 ber_dupbv_x( normalized, &comp, ctx );
5142         }
5143
5144         return rc;
5145 }
5146
5147 static char *country_gen_syn[] = {
5148         "1.3.6.1.4.1.1466.115.121.1.15",
5149         "1.3.6.1.4.1.1466.115.121.1.26",
5150         "1.3.6.1.4.1.1466.115.121.1.44",
5151         NULL
5152 };
5153
5154 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
5155 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
5156
5157 static slap_syntax_defs_rec syntax_defs[] = {
5158         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
5159                 X_BINARY X_NOT_H_R ")",
5160                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
5161         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
5162                 0, NULL, NULL, NULL},
5163         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
5164                 0, NULL, NULL, NULL},
5165         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
5166                 X_NOT_H_R ")",
5167                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
5168         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
5169                 X_NOT_H_R ")",
5170                 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
5171         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
5172                 0, NULL, bitStringValidate, NULL },
5173         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
5174                 0, NULL, booleanValidate, NULL},
5175         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
5176                 X_BINARY X_NOT_H_R ")",
5177                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
5178                 NULL, certificateValidate, NULL},
5179         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
5180                 X_BINARY X_NOT_H_R ")",
5181                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
5182                 NULL, certificateListValidate, NULL},
5183         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
5184                 X_BINARY X_NOT_H_R ")",
5185                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
5186                 NULL, sequenceValidate, NULL},
5187 #if 0   /* need to go __after__ printableString */
5188         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
5189                 0, "1.3.6.1.4.1.1466.115.121.1.44",
5190                 countryStringValidate, NULL},
5191 #endif
5192         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
5193                 0, NULL, dnValidate, dnPretty},
5194         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
5195                 0, NULL, rdnValidate, rdnPretty},
5196 #ifdef LDAP_COMP_MATCH
5197         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
5198                 0, NULL, allComponentsValidate, NULL},
5199         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
5200                 0, NULL, componentFilterValidate, NULL},
5201 #endif
5202         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
5203                 0, NULL, NULL, NULL},
5204         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
5205                 0, NULL, deliveryMethodValidate, NULL},
5206         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
5207                 0, NULL, UTF8StringValidate, NULL},
5208         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
5209                 0, NULL, NULL, NULL},
5210         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
5211                 0, NULL, NULL, NULL},
5212         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
5213                 0, NULL, NULL, NULL},
5214         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
5215                 0, NULL, NULL, NULL},
5216         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
5217                 0, NULL, NULL, NULL},
5218         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
5219                 0, NULL, printablesStringValidate, NULL},
5220         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
5221                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
5222         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
5223                 0, NULL, generalizedTimeValidate, NULL},
5224         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
5225                 0, NULL, NULL, NULL},
5226         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
5227                 0, NULL, IA5StringValidate, NULL},
5228         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
5229                 0, NULL, integerValidate, NULL},
5230         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
5231                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
5232         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
5233                 0, NULL, NULL, NULL},
5234         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
5235                 0, NULL, NULL, NULL},
5236         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
5237                 0, NULL, NULL, NULL},
5238         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
5239                 0, NULL, NULL, NULL},
5240         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
5241                 0, NULL, NULL, NULL},
5242         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
5243                 0, NULL, nameUIDValidate, nameUIDPretty },
5244         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
5245                 0, NULL, NULL, NULL},
5246         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
5247                 0, NULL, numericStringValidate, NULL},
5248         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
5249                 0, NULL, NULL, NULL},
5250         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
5251                 0, NULL, numericoidValidate, NULL},
5252         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
5253                 0, NULL, IA5StringValidate, NULL},
5254         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
5255                 0, NULL, blobValidate, NULL},
5256         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
5257                 0, NULL, postalAddressValidate, NULL},
5258         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
5259                 0, NULL, NULL, NULL},
5260         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
5261                 0, NULL, NULL, NULL},
5262         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
5263                 0, NULL, printableStringValidate, NULL},
5264         /* moved here because now depends on Directory String, IA5 String 
5265          * and Printable String */
5266         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
5267                 0, country_gen_syn, countryStringValidate, NULL},
5268         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
5269 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
5270                 0, NULL, subtreeSpecificationValidate, NULL},
5271         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
5272                 X_BINARY X_NOT_H_R ")",
5273                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
5274         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
5275                 0, NULL, printableStringValidate, NULL},
5276         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
5277                 0, NULL, NULL, NULL},
5278         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
5279                 0, NULL, printablesStringValidate, NULL},
5280 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5281         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
5282                 0, NULL, utcTimeValidate, NULL},
5283 #endif
5284         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
5285                 0, NULL, NULL, NULL},
5286         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
5287                 0, NULL, NULL, NULL},
5288         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
5289                 0, NULL, NULL, NULL},
5290         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
5291                 0, NULL, NULL, NULL},
5292         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
5293                 0, NULL, NULL, NULL},
5294
5295         /* RFC 2307 NIS Syntaxes */
5296         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
5297                 0, NULL, nisNetgroupTripleValidate, NULL},
5298         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
5299                 0, NULL, bootParameterValidate, NULL},
5300
5301         /* draft-zeilenga-ldap-x509 */
5302         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
5303                 SLAP_SYNTAX_HIDE, NULL,
5304                 serialNumberAndIssuerValidate,
5305                 serialNumberAndIssuerPretty},
5306         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
5307                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
5308         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
5309                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
5310         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
5311                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
5312         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
5313                 SLAP_SYNTAX_HIDE, NULL,
5314                 issuerAndThisUpdateValidate,
5315                 issuerAndThisUpdatePretty},
5316         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
5317                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
5318         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
5319                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
5320
5321 #ifdef SLAPD_AUTHPASSWD
5322         /* needs updating */
5323         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
5324                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
5325 #endif
5326
5327         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
5328                 0, NULL, UUIDValidate, UUIDPretty},
5329
5330         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
5331                 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
5332
5333         {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
5334                 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
5335
5336         /* OpenLDAP Void Syntax */
5337         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
5338                 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
5339
5340         /* FIXME: OID is unused, but not registered yet */
5341         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
5342                 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
5343
5344         {NULL, 0, NULL, NULL, NULL}
5345 };
5346
5347 char *csnSIDMatchSyntaxes[] = {
5348         "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
5349         NULL
5350 };
5351 char *certificateExactMatchSyntaxes[] = {
5352         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
5353         NULL
5354 };
5355 char *certificateListExactMatchSyntaxes[] = {
5356         "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
5357         NULL
5358 };
5359 #ifdef LDAP_COMP_MATCH
5360 char *componentFilterMatchSyntaxes[] = {
5361         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
5362         "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
5363         NULL
5364 };
5365 #endif
5366 char *directoryStringSyntaxes[] = {
5367         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
5368         NULL
5369 };
5370 char *integerFirstComponentMatchSyntaxes[] = {
5371         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
5372         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
5373         NULL
5374 };
5375 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
5376         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
5377         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
5378         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
5379         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
5380         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
5381         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
5382         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
5383         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
5384         NULL
5385 };
5386
5387 /*
5388  * Other matching rules in X.520 that we do not use (yet):
5389  *
5390  * 2.5.13.25    uTCTimeMatch
5391  * 2.5.13.26    uTCTimeOrderingMatch
5392  * 2.5.13.31*   directoryStringFirstComponentMatch
5393  * 2.5.13.32*   wordMatch
5394  * 2.5.13.33*   keywordMatch
5395  * 2.5.13.36+   certificatePairExactMatch
5396  * 2.5.13.37+   certificatePairMatch
5397  * 2.5.13.40+   algorithmIdentifierMatch
5398  * 2.5.13.41*   storedPrefixMatch
5399  * 2.5.13.42    attributeCertificateMatch
5400  * 2.5.13.43    readerAndKeyIDMatch
5401  * 2.5.13.44    attributeIntegrityMatch
5402  *
5403  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
5404  * (+) described in draft-zeilenga-ldap-x509
5405  */
5406 static slap_mrule_defs_rec mrule_defs[] = {
5407         /*
5408          * EQUALITY matching rules must be listed after associated APPROX
5409          * matching rules.  So, we list all APPROX matching rules first.
5410          */
5411         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
5412                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
5413                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
5414                 NULL, NULL, directoryStringApproxMatch,
5415                 directoryStringApproxIndexer, directoryStringApproxFilter,
5416                 NULL},
5417
5418         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
5419                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5420                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
5421                 NULL, NULL, IA5StringApproxMatch,
5422                 IA5StringApproxIndexer, IA5StringApproxFilter,
5423                 NULL},
5424
5425         /*
5426          * Other matching rules
5427          */
5428         
5429         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
5430                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
5431                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5432                 NULL, NULL, octetStringMatch,
5433                 octetStringIndexer, octetStringFilter,
5434                 NULL },
5435
5436         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
5437                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
5438                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5439                 NULL, dnNormalize, dnMatch,
5440                 octetStringIndexer, octetStringFilter,
5441                 NULL },
5442
5443         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
5444                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
5445                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
5446                 NULL, dnNormalize, dnRelativeMatch,
5447                 NULL, NULL,
5448                 NULL },
5449
5450         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
5451                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
5452                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
5453                 NULL, dnNormalize, dnRelativeMatch,
5454                 NULL, NULL,
5455                 NULL },
5456
5457         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
5458                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
5459                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
5460                 NULL, dnNormalize, dnRelativeMatch,
5461                 NULL, NULL,
5462                 NULL },
5463
5464         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
5465                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
5466                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
5467                 NULL, dnNormalize, dnRelativeMatch,
5468                 NULL, NULL,
5469                 NULL },
5470
5471         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
5472                 "SYNTAX 1.2.36.79672281.1.5.0 )",
5473                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5474                 NULL, rdnNormalize, rdnMatch,
5475                 octetStringIndexer, octetStringFilter,
5476                 NULL },
5477
5478 #ifdef LDAP_COMP_MATCH
5479         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
5480                 "SYNTAX 1.2.36.79672281.1.5.2 )",
5481                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
5482                 NULL, NULL , componentFilterMatch,
5483                 octetStringIndexer, octetStringFilter,
5484                 NULL },
5485
5486         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
5487                 "SYNTAX 1.2.36.79672281.1.5.3 )",
5488                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
5489                 NULL, NULL , allComponentsMatch,
5490                 octetStringIndexer, octetStringFilter,
5491                 NULL },
5492
5493         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
5494                 "SYNTAX 1.2.36.79672281.1.5.3 )",
5495                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
5496                 NULL, NULL , directoryComponentsMatch,
5497                 octetStringIndexer, octetStringFilter,
5498                 NULL },
5499 #endif
5500
5501         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
5502                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
5503                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
5504                 NULL, UTF8StringNormalize, octetStringMatch,
5505                 octetStringIndexer, octetStringFilter,
5506                 directoryStringApproxMatchOID },
5507
5508         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
5509                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
5510                 SLAP_MR_ORDERING, directoryStringSyntaxes,
5511                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
5512                 NULL, NULL,
5513                 "caseIgnoreMatch" },
5514
5515         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
5516                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
5517                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
5518                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
5519                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5520                 "caseIgnoreMatch" },
5521
5522         {"( 2.5.13.5 NAME 'caseExactMatch' "
5523                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
5524                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
5525                 NULL, UTF8StringNormalize, octetStringMatch,
5526                 octetStringIndexer, octetStringFilter,
5527                 directoryStringApproxMatchOID },
5528
5529         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
5530                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
5531                 SLAP_MR_ORDERING, directoryStringSyntaxes,
5532                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
5533                 NULL, NULL,
5534                 "caseExactMatch" },
5535
5536         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
5537                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
5538                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
5539                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
5540                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5541                 "caseExactMatch" },
5542
5543         {"( 2.5.13.8 NAME 'numericStringMatch' "
5544                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
5545                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5546                 NULL, numericStringNormalize, octetStringMatch,
5547                 octetStringIndexer, octetStringFilter,
5548                 NULL },
5549
5550         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
5551                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
5552                 SLAP_MR_ORDERING, NULL,
5553                 NULL, numericStringNormalize, octetStringOrderingMatch,
5554                 NULL, NULL,
5555                 "numericStringMatch" },
5556
5557         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
5558                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
5559                 SLAP_MR_SUBSTR, NULL,
5560                 NULL, numericStringNormalize, octetStringSubstringsMatch,
5561                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5562                 "numericStringMatch" },
5563
5564         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
5565                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
5566                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5567                 NULL, postalAddressNormalize, octetStringMatch,
5568                 octetStringIndexer, octetStringFilter,
5569                 NULL },
5570
5571         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
5572                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
5573                 SLAP_MR_SUBSTR, NULL,
5574                 NULL, NULL, NULL, NULL, NULL,
5575                 "caseIgnoreListMatch" },
5576
5577         {"( 2.5.13.13 NAME 'booleanMatch' "
5578                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
5579                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5580                 NULL, NULL, booleanMatch,
5581                 octetStringIndexer, octetStringFilter,
5582                 NULL },
5583
5584         {"( 2.5.13.14 NAME 'integerMatch' "
5585                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5586                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
5587                 NULL, NULL, integerMatch,
5588                 integerIndexer, integerFilter,
5589                 NULL },
5590
5591         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
5592                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5593                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5594                 NULL, NULL, integerMatch,
5595                 NULL, NULL,
5596                 "integerMatch" },
5597
5598         {"( 2.5.13.16 NAME 'bitStringMatch' "
5599                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
5600                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5601                 NULL, NULL, octetStringMatch,
5602                 octetStringIndexer, octetStringFilter,
5603                 NULL },
5604
5605         {"( 2.5.13.17 NAME 'octetStringMatch' "
5606                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5607                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5608                 NULL, NULL, octetStringMatch,
5609                 octetStringIndexer, octetStringFilter,
5610                 NULL },
5611
5612         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
5613                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5614                 SLAP_MR_ORDERING, NULL,
5615                 NULL, NULL, octetStringOrderingMatch,
5616                 NULL, NULL,
5617                 "octetStringMatch" },
5618
5619         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
5620                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5621                 SLAP_MR_SUBSTR, NULL,
5622                 NULL, NULL, octetStringSubstringsMatch,
5623                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5624                 "octetStringMatch" },
5625
5626         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
5627                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
5628                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5629                 NULL,
5630                 telephoneNumberNormalize, octetStringMatch,
5631                 octetStringIndexer, octetStringFilter,
5632                 NULL },
5633
5634         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
5635                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
5636                 SLAP_MR_SUBSTR, NULL,
5637                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
5638                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5639                 "telephoneNumberMatch" },
5640
5641         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
5642                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
5643                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5644                 NULL, NULL, NULL, NULL, NULL, NULL },
5645
5646         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
5647                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
5648                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5649                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
5650                 uniqueMemberIndexer, uniqueMemberFilter,
5651                 NULL },
5652
5653         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
5654                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
5655                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5656                 NULL, NULL, NULL, NULL, NULL, NULL },
5657
5658         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
5659                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5660                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
5661                 NULL, generalizedTimeNormalize, octetStringMatch,
5662                 generalizedTimeIndexer, generalizedTimeFilter,
5663                 NULL },
5664
5665         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
5666                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5667                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5668                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
5669                 NULL, NULL,
5670                 "generalizedTimeMatch" },
5671
5672         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
5673                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5674                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
5675                         integerFirstComponentMatchSyntaxes,
5676                 NULL, firstComponentNormalize, integerMatch,
5677                 octetStringIndexer, octetStringFilter,
5678                 NULL },
5679
5680         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
5681                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
5682                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
5683                         objectIdentifierFirstComponentMatchSyntaxes,
5684                 NULL, firstComponentNormalize, octetStringMatch,
5685                 octetStringIndexer, octetStringFilter,
5686                 NULL },
5687
5688         {"( 2.5.13.34 NAME 'certificateExactMatch' "
5689                 "SYNTAX 1.3.6.1.1.15.1 )",
5690                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
5691                 NULL, certificateExactNormalize, octetStringMatch,
5692                 octetStringIndexer, octetStringFilter,
5693                 NULL },
5694
5695         {"( 2.5.13.35 NAME 'certificateMatch' "
5696                 "SYNTAX 1.3.6.1.1.15.2 )",
5697                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5698                 NULL, NULL, NULL, NULL, NULL,
5699                 NULL },
5700
5701         {"( 2.5.13.38 NAME 'certificateListExactMatch' "
5702                 "SYNTAX 1.3.6.1.1.15.5 )",
5703                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
5704                 NULL, certificateListExactNormalize, octetStringMatch,
5705                 octetStringIndexer, octetStringFilter,
5706                 NULL },
5707
5708         {"( 2.5.13.39 NAME 'certificateListMatch' "
5709                 "SYNTAX 1.3.6.1.1.15.6 )",
5710                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5711                 NULL, NULL, NULL, NULL, NULL,
5712                 NULL },
5713
5714         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
5715                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5716                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5717                 NULL, IA5StringNormalize, octetStringMatch,
5718                 octetStringIndexer, octetStringFilter,
5719                 IA5StringApproxMatchOID },
5720
5721         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
5722                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5723                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5724                 NULL, IA5StringNormalize, octetStringMatch,
5725                 octetStringIndexer, octetStringFilter,
5726                 IA5StringApproxMatchOID },
5727
5728         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
5729                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5730                 SLAP_MR_SUBSTR, NULL,
5731                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5732                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5733                 "caseIgnoreIA5Match" },
5734
5735         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
5736                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5737                 SLAP_MR_SUBSTR, NULL,
5738                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5739                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5740                 "caseExactIA5Match" },
5741
5742 #ifdef SLAPD_AUTHPASSWD
5743         /* needs updating */
5744         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
5745                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5746                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5747                 NULL, NULL, authPasswordMatch,
5748                 NULL, NULL,
5749                 NULL},
5750 #endif
5751
5752         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
5753                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5754                 SLAP_MR_EXT, NULL,
5755                 NULL, NULL, integerBitAndMatch,
5756                 NULL, NULL,
5757                 "integerMatch" },
5758
5759         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
5760                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5761                 SLAP_MR_EXT, NULL,
5762                 NULL, NULL, integerBitOrMatch,
5763                 NULL, NULL,
5764                 "integerMatch" },
5765
5766         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
5767                 "SYNTAX 1.3.6.1.1.16.1 )",
5768                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
5769                 NULL, UUIDNormalize, octetStringMatch,
5770                 octetStringIndexer, octetStringFilter,
5771                 NULL},
5772
5773         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
5774                 "SYNTAX 1.3.6.1.1.16.1 )",
5775                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
5776                 NULL, UUIDNormalize, octetStringOrderingMatch,
5777                 octetStringIndexer, octetStringFilter,
5778                 "UUIDMatch"},
5779
5780         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
5781                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5782                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
5783                 NULL, csnNormalize, csnMatch,
5784                 csnIndexer, csnFilter,
5785                 NULL},
5786
5787         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
5788                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5789                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5790                 NULL, NULL, csnOrderingMatch,
5791                 NULL, NULL,
5792                 "CSNMatch" },
5793
5794         {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
5795                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
5796                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
5797                 NULL, csnSidNormalize, octetStringMatch,
5798                 octetStringIndexer, octetStringFilter,
5799                 NULL },
5800
5801         /* FIXME: OID is unused, but not registered yet */
5802         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
5803                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
5804                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5805                 NULL, authzNormalize, authzMatch,
5806                 NULL, NULL,
5807                 NULL},
5808
5809         {NULL, SLAP_MR_NONE, NULL,
5810                 NULL, NULL, NULL, NULL, NULL,
5811                 NULL }
5812 };
5813
5814 int
5815 slap_schema_init( void )
5816 {
5817         int             res;
5818         int             i;
5819
5820         /* we should only be called once (from main) */
5821         assert( schema_init_done == 0 );
5822
5823         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
5824                 res = register_syntax( &syntax_defs[i] );
5825
5826                 if ( res ) {
5827                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
5828                                  syntax_defs[i].sd_desc );
5829                         return LDAP_OTHER;
5830                 }
5831         }
5832
5833         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
5834                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
5835                         mrule_defs[i].mrd_compat_syntaxes == NULL )
5836                 {
5837                         fprintf( stderr,
5838                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
5839                                  mrule_defs[i].mrd_desc );
5840                         continue;
5841                 }
5842
5843                 res = register_matching_rule( &mrule_defs[i] );
5844
5845                 if ( res ) {
5846                         fprintf( stderr,
5847                                 "slap_schema_init: Error registering matching rule %s\n",
5848                                  mrule_defs[i].mrd_desc );
5849                         return LDAP_OTHER;
5850                 }
5851         }
5852
5853         res = slap_schema_load();
5854         schema_init_done = 1;
5855         return res;
5856 }
5857
5858 void
5859 schema_destroy( void )
5860 {
5861         oidm_destroy();
5862         oc_destroy();
5863         at_destroy();
5864         mr_destroy();
5865         mru_destroy();
5866         syn_destroy();
5867
5868         if( schema_init_done ) {
5869                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
5870                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
5871         }
5872 }