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