]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
ITS#5070, #5151 from HEAD - cert validate/norm fixes
[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         /* Use hex format. [-]0x123456789abcdef
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                 char sign = 0;
3395                 
3396                 tag = ber_skip_tag( ber, &len );
3397                 ptr = (unsigned char *)ber->ber_ptr;
3398                 ber_skip_data( ber, len );
3399
3400                 /* Check for minimal encodings */
3401                 if ( ptr[0] & 0x80 ) {
3402                         if (( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ))
3403                                 return LDAP_INVALID_SYNTAX;
3404                         sign = -1;
3405                 } else if ( ptr[0] == 0 ) {
3406                         if (!( ptr[1] & 0x80 ))
3407                                 return LDAP_INVALID_SYNTAX;
3408                         ptr++;
3409                         len--;
3410                 }
3411
3412                 seriallen = len * 2 + 3;        /* leading 0x, NUL */
3413                 if ( sign )
3414                         seriallen++;
3415                 if ( seriallen > sizeof( serialbuf ))
3416                         serial = slap_sl_malloc( seriallen, ctx );
3417                 sptr = serial;
3418                 if ( sign )
3419                         *sptr++ = '-';
3420                 *sptr++ = '0';
3421                 *sptr++ = 'x';
3422                 for ( i = 0; i<len; i++ ) {
3423                         sprintf( sptr, "%02x", sign ? 256 - ptr[i] : ptr[i] );
3424                         sptr += 2;
3425                 }
3426                 seriallen--;
3427
3428         } else {
3429                 tag = ber_get_int( ber, &i );   /* serial */
3430                 seriallen = snprintf( serialbuf, sizeof(serialbuf), "%d", i );
3431         }
3432         tag = ber_skip_tag( ber, &len );        /* SignatureAlg */
3433         ber_skip_data( ber, len );
3434         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
3435         len = ber_ptrlen( ber );
3436         bvdn.bv_val = val->bv_val + len;
3437         bvdn.bv_len = val->bv_len - len;
3438
3439         rc = dnX509normalize( &bvdn, &issuer_dn );
3440         if( rc != LDAP_SUCCESS ) goto done;
3441
3442         normalized->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3443                 + seriallen + issuer_dn.bv_len;
3444         normalized->bv_val = ch_malloc(normalized->bv_len+1);
3445
3446         p = (unsigned char *)normalized->bv_val;
3447
3448         AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3449         p += STRLENOF( "{ serialNumber " );
3450
3451         AC_MEMCPY(p, serial, seriallen);
3452         p += seriallen;
3453
3454         AC_MEMCPY(p, ", issuer \"", STRLENOF( ", issuer \"" ));
3455         p += STRLENOF( ", issuer \"" );
3456
3457         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3458         p += issuer_dn.bv_len;
3459
3460         AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3461         p += STRLENOF( "\" }" );
3462
3463         *p = '\0';
3464
3465         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3466                 normalized->bv_val, NULL, NULL );
3467
3468         rc = LDAP_SUCCESS;
3469
3470 done:
3471         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3472         if ( serial != serialbuf ) ber_memfree_x( serial, ctx );
3473
3474         return rc;
3475 }
3476
3477 static int
3478 hexValidate(
3479         Syntax *syntax,
3480         struct berval *in )
3481 {
3482         int     i;
3483
3484         assert( in != NULL );
3485         assert( !BER_BVISNULL( in ) );
3486
3487         for ( i = 0; i < in->bv_len; i++ ) {
3488                 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
3489                         return LDAP_INVALID_SYNTAX;
3490                 }
3491         }
3492
3493         return LDAP_SUCCESS;
3494 }
3495
3496 /* Normalize a SID as used inside a CSN:
3497  * three-digit numeric string */
3498 static int
3499 hexNormalize(
3500         slap_mask_t usage,
3501         Syntax *syntax,
3502         MatchingRule *mr,
3503         struct berval *val,
3504         struct berval *normalized,
3505         void *ctx )
3506 {
3507         int     i;
3508
3509         assert( val != NULL );
3510         assert( normalized != NULL );
3511
3512         ber_dupbv_x( normalized, val, ctx );
3513
3514         for ( i = 0; i < normalized->bv_len; i++ ) {
3515                 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
3516                         ber_memfree_x( normalized->bv_val, ctx );
3517                         BER_BVZERO( normalized );
3518                         return LDAP_INVALID_SYNTAX;
3519                 }
3520
3521                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3522         }
3523
3524         return LDAP_SUCCESS;
3525 }
3526
3527 static int
3528 sidValidate (
3529         Syntax *syntax,
3530         struct berval *in )
3531 {
3532         assert( in != NULL );
3533         assert( !BER_BVISNULL( in ) );
3534
3535         if ( in->bv_len != 3 ) {
3536                 return LDAP_INVALID_SYNTAX;
3537         }
3538
3539         return hexValidate( NULL, in );
3540 }
3541
3542 /* Normalize a SID as used inside a CSN:
3543  * three-digit numeric string */
3544 static int
3545 sidNormalize(
3546         slap_mask_t usage,
3547         Syntax *syntax,
3548         MatchingRule *mr,
3549         struct berval *val,
3550         struct berval *normalized,
3551         void *ctx )
3552 {
3553         if ( val->bv_len != 3 ) {
3554                 return LDAP_INVALID_SYNTAX;
3555         }
3556
3557         return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
3558 }
3559
3560 static int
3561 sidPretty(
3562         Syntax *syntax,
3563         struct berval *val,
3564         struct berval *out,
3565         void *ctx )
3566 {
3567         return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3568 }
3569
3570 /* Normalize a SID as used inside a CSN, either as-is
3571  * (assertion value) or extracted from the CSN
3572  * (attribute value) */
3573 static int
3574 csnSidNormalize(
3575         slap_mask_t usage,
3576         Syntax *syntax,
3577         MatchingRule *mr,
3578         struct berval *val,
3579         struct berval *normalized,
3580         void *ctx )
3581 {
3582         struct berval   bv;
3583         char            *ptr,
3584                         buf[ 4 ];
3585
3586
3587         if ( BER_BVISEMPTY( val ) ) {
3588                 return LDAP_INVALID_SYNTAX;
3589         }
3590
3591         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3592                 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
3593         }
3594
3595         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3596
3597         ptr = ber_bvchr( val, '#' );
3598         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3599                 return LDAP_INVALID_SYNTAX;
3600         }
3601
3602         bv.bv_val = ptr + 1;
3603         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3604
3605         ptr = ber_bvchr( &bv, '#' );
3606         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3607                 return LDAP_INVALID_SYNTAX;
3608         }
3609
3610         bv.bv_val = ptr + 1;
3611         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3612                 
3613         ptr = ber_bvchr( &bv, '#' );
3614         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3615                 return LDAP_INVALID_SYNTAX;
3616         }
3617
3618         bv.bv_len = ptr - bv.bv_val;
3619
3620         if ( bv.bv_len == 2 ) {
3621                 /* OpenLDAP 2.3 SID */
3622                 buf[ 0 ] = '0';
3623                 buf[ 1 ] = bv.bv_val[ 0 ];
3624                 buf[ 2 ] = bv.bv_val[ 1 ];
3625                 buf[ 3 ] = '\0';
3626
3627                 bv.bv_val = buf;
3628                 bv.bv_len = 3;
3629         }
3630
3631         return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
3632 }
3633
3634 static int
3635 csnValidate(
3636         Syntax *syntax,
3637         struct berval *in )
3638 {
3639         struct berval   bv;
3640         char            *ptr;
3641         int             rc;
3642
3643         assert( in != NULL );
3644         assert( !BER_BVISNULL( in ) );
3645
3646         if ( BER_BVISEMPTY( in ) ) {
3647                 return LDAP_INVALID_SYNTAX;
3648         }
3649
3650         bv = *in;
3651
3652         ptr = ber_bvchr( &bv, '#' );
3653         if ( ptr == NULL || ptr - bv.bv_val == bv.bv_len ) {
3654                 return LDAP_INVALID_SYNTAX;
3655         }
3656
3657         bv.bv_len = ptr - bv.bv_val;
3658         if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
3659                 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
3660         {
3661                 return LDAP_INVALID_SYNTAX;
3662         }
3663
3664         rc = generalizedTimeValidate( NULL, &bv );
3665         if ( rc != LDAP_SUCCESS ) {
3666                 return rc;
3667         }
3668
3669         bv.bv_val = ptr + 1;
3670         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3671
3672         ptr = ber_bvchr( &bv, '#' );
3673         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3674                 return LDAP_INVALID_SYNTAX;
3675         }
3676
3677         bv.bv_len = ptr - bv.bv_val;
3678         if ( bv.bv_len != 6 ) {
3679                 return LDAP_INVALID_SYNTAX;
3680         }
3681
3682         rc = hexValidate( NULL, &bv );
3683         if ( rc != LDAP_SUCCESS ) {
3684                 return rc;
3685         }
3686
3687         bv.bv_val = ptr + 1;
3688         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3689
3690         ptr = ber_bvchr( &bv, '#' );
3691         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3692                 return LDAP_INVALID_SYNTAX;
3693         }
3694
3695         bv.bv_len = ptr - bv.bv_val;
3696         if ( bv.bv_len == 2 ) {
3697                 /* tolerate old 2-digit replica-id */
3698                 rc = hexValidate( NULL, &bv );
3699
3700         } else {
3701                 rc = sidValidate( NULL, &bv );
3702         }
3703         if ( rc != LDAP_SUCCESS ) {
3704                 return rc;
3705         }
3706
3707         bv.bv_val = ptr + 1;
3708         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3709
3710         if ( bv.bv_len != 6 ) {
3711                 return LDAP_INVALID_SYNTAX;
3712         }
3713
3714         return hexValidate( NULL, &bv );
3715 }
3716
3717 /* Normalize a CSN in OpenLDAP 2.3 format */
3718 static int
3719 csnNormalize23(
3720         slap_mask_t usage,
3721         Syntax *syntax,
3722         MatchingRule *mr,
3723         struct berval *val,
3724         struct berval *normalized,
3725         void *ctx )
3726 {
3727         struct berval   gt, cnt, sid, mod;
3728         char            *ptr;
3729         int             i;
3730
3731         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3732         assert( !BER_BVISEMPTY( val ) );
3733
3734         gt = *val;
3735
3736         ptr = ber_bvchr( &gt, '#' );
3737         if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3738                 return LDAP_INVALID_SYNTAX;
3739         }
3740
3741         gt.bv_len = ptr - gt.bv_val;
3742         assert( gt.bv_len == STRLENOF( "YYYYmmddHHMMSSZ" ) );
3743
3744         cnt.bv_val = ptr + 1;
3745         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3746
3747         ptr = ber_bvchr( &cnt, '#' );
3748         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3749                 return LDAP_INVALID_SYNTAX;
3750         }
3751
3752         cnt.bv_len = ptr - cnt.bv_val;
3753         assert( cnt.bv_len == STRLENOF( "000000" ) );
3754
3755         sid.bv_val = ptr + 1;
3756         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3757                 
3758         ptr = ber_bvchr( &sid, '#' );
3759         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3760                 return LDAP_INVALID_SYNTAX;
3761         }
3762
3763         sid.bv_len = ptr - sid.bv_val;
3764         assert( sid.bv_len == STRLENOF( "00" ) );
3765
3766         mod.bv_val = ptr + 1;
3767         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3768         assert( mod.bv_len == STRLENOF( "000000" ) );
3769
3770         normalized->bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3771         normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
3772
3773         ptr = normalized->bv_val;
3774         ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
3775         ptr = lutil_strcopy( ptr, ".000000Z#" );
3776         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3777         *ptr++ = '#';
3778         *ptr++ = '0';
3779         for ( i = 0; i < sid.bv_len; i++ ) {
3780                 *ptr++ = TOLOWER( sid.bv_val[ i ] );
3781         }
3782         *ptr++ = '#';
3783         for ( i = 0; i < mod.bv_len; i++ ) {
3784                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
3785         }
3786         *ptr = '\0';
3787
3788         assert( ptr - normalized->bv_val == normalized->bv_len );
3789
3790         return LDAP_SUCCESS;
3791 }
3792
3793 /* Normalize a CSN */
3794 static int
3795 csnNormalize(
3796         slap_mask_t usage,
3797         Syntax *syntax,
3798         MatchingRule *mr,
3799         struct berval *val,
3800         struct berval *normalized,
3801         void *ctx )
3802 {
3803         struct berval   cnt, sid, mod;
3804         char            *ptr;
3805         int             i;
3806
3807         assert( val != NULL );
3808         assert( normalized != NULL );
3809
3810         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3811
3812         if ( BER_BVISEMPTY( val ) ) {
3813                 return LDAP_INVALID_SYNTAX;
3814         }
3815
3816         if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
3817                 /* Openldap <= 2.3 */
3818
3819                 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
3820         }
3821
3822         assert( val->bv_len == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) );
3823
3824         ptr = ber_bvchr( val, '#' );
3825         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3826                 return LDAP_INVALID_SYNTAX;
3827         }
3828
3829         assert( ptr - val->bv_val == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) );
3830
3831         cnt.bv_val = ptr + 1;
3832         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3833
3834         ptr = ber_bvchr( &cnt, '#' );
3835         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3836                 return LDAP_INVALID_SYNTAX;
3837         }
3838
3839         assert( ptr - cnt.bv_val == STRLENOF( "000000" ) );
3840
3841         sid.bv_val = ptr + 1;
3842         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3843                 
3844         ptr = ber_bvchr( &sid, '#' );
3845         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3846                 return LDAP_INVALID_SYNTAX;
3847         }
3848
3849         sid.bv_len = ptr - sid.bv_val;
3850         assert( sid.bv_len == STRLENOF( "000" ) );
3851
3852         mod.bv_val = ptr + 1;
3853         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3854
3855         assert( mod.bv_len == STRLENOF( "000000" ) );
3856
3857         ber_dupbv_x( normalized, val, ctx );
3858
3859         for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
3860                 i < normalized->bv_len; i++ )
3861         {
3862                 /* assume it's already validated that's all hex digits */
3863                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3864         }
3865
3866         return LDAP_SUCCESS;
3867 }
3868
3869 static int
3870 csnPretty(
3871         Syntax *syntax,
3872         struct berval *val,
3873         struct berval *out,
3874         void *ctx )
3875 {
3876         return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3877 }
3878
3879 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3880 /* slight optimization - does not need the start parameter */
3881 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3882 enum { start = 0 };
3883 #endif
3884
3885 static int
3886 check_time_syntax (struct berval *val,
3887         int start,
3888         int *parts,
3889         struct berval *fraction)
3890 {
3891         /*
3892          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3893          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
3894          * GeneralizedTime supports leap seconds, UTCTime does not.
3895          */
3896         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3897         static const int mdays[2][12] = {
3898                 /* non-leap years */
3899                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3900                 /* leap years */
3901                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3902         };
3903         char *p, *e;
3904         int part, c, c1, c2, tzoffset, leapyear = 0;
3905
3906         p = val->bv_val;
3907         e = p + val->bv_len;
3908
3909 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3910         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3911 #endif
3912         for (part = start; part < 7 && p < e; part++) {
3913                 c1 = *p;
3914                 if (!ASCII_DIGIT(c1)) {
3915                         break;
3916                 }
3917                 p++;
3918                 if (p == e) {
3919                         return LDAP_INVALID_SYNTAX;
3920                 }
3921                 c = *p++;
3922                 if (!ASCII_DIGIT(c)) {
3923                         return LDAP_INVALID_SYNTAX;
3924                 }
3925                 c += c1 * 10 - '0' * 11;
3926                 if ((part | 1) == 3) {
3927                         --c;
3928                         if (c < 0) {
3929                                 return LDAP_INVALID_SYNTAX;
3930                         }
3931                 }
3932                 if (c >= ceiling[part]) {
3933                         if (! (c == 60 && part == 6 && start == 0))
3934                                 return LDAP_INVALID_SYNTAX;
3935                 }
3936                 parts[part] = c;
3937         }
3938         if (part < 5 + start) {
3939                 return LDAP_INVALID_SYNTAX;
3940         }
3941         for (; part < 9; part++) {
3942                 parts[part] = 0;
3943         }
3944
3945         /* leapyear check for the Gregorian calendar (year>1581) */
3946         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3947                 leapyear = 1;
3948         }
3949
3950         if (parts[3] >= mdays[leapyear][parts[2]]) {
3951                 return LDAP_INVALID_SYNTAX;
3952         }
3953
3954         if (start == 0) {
3955                 fraction->bv_val = p;
3956                 fraction->bv_len = 0;
3957                 if (p < e && (*p == '.' || *p == ',')) {
3958                         char *end_num;
3959                         while (++p < e && ASCII_DIGIT(*p)) {
3960                                 /* EMTPY */;
3961                         }
3962                         if (p - fraction->bv_val == 1) {
3963                                 return LDAP_INVALID_SYNTAX;
3964                         }
3965                         for (end_num = p; end_num[-1] == '0'; --end_num) {
3966                                 /* EMPTY */;
3967                         }
3968                         c = end_num - fraction->bv_val;
3969                         if (c != 1) fraction->bv_len = c;
3970                 }
3971         }
3972
3973         if (p == e) {
3974                 /* no time zone */
3975                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3976         }
3977
3978         tzoffset = *p++;
3979         switch (tzoffset) {
3980         default:
3981                 return LDAP_INVALID_SYNTAX;
3982         case 'Z':
3983                 /* UTC */
3984                 break;
3985         case '+':
3986         case '-':
3987                 for (part = 7; part < 9 && p < e; part++) {
3988                         c1 = *p;
3989                         if (!ASCII_DIGIT(c1)) {
3990                                 break;
3991                         }
3992                         p++;
3993                         if (p == e) {
3994                                 return LDAP_INVALID_SYNTAX;
3995                         }
3996                         c2 = *p++;
3997                         if (!ASCII_DIGIT(c2)) {
3998                                 return LDAP_INVALID_SYNTAX;
3999                         }
4000                         parts[part] = c1 * 10 + c2 - '0' * 11;
4001                         if (parts[part] >= ceiling[part]) {
4002                                 return LDAP_INVALID_SYNTAX;
4003                         }
4004                 }
4005                 if (part < 8 + start) {
4006                         return LDAP_INVALID_SYNTAX;
4007                 }
4008
4009                 if (tzoffset == '-') {
4010                         /* negative offset to UTC, ie west of Greenwich */
4011                         parts[4] += parts[7];
4012                         parts[5] += parts[8];
4013                         /* offset is just hhmm, no seconds */
4014                         for (part = 6; --part >= 0; ) {
4015                                 if (part != 3) {
4016                                         c = ceiling[part];
4017                                 } else {
4018                                         c = mdays[leapyear][parts[2]];
4019                                 }
4020                                 if (parts[part] >= c) {
4021                                         if (part == 0) {
4022                                                 return LDAP_INVALID_SYNTAX;
4023                                         }
4024                                         parts[part] -= c;
4025                                         parts[part - 1]++;
4026                                         continue;
4027                                 } else if (part != 5) {
4028                                         break;
4029                                 }
4030                         }
4031                 } else {
4032                         /* positive offset to UTC, ie east of Greenwich */
4033                         parts[4] -= parts[7];
4034                         parts[5] -= parts[8];
4035                         for (part = 6; --part >= 0; ) {
4036                                 if (parts[part] < 0) {
4037                                         if (part == 0) {
4038                                                 return LDAP_INVALID_SYNTAX;
4039                                         }
4040                                         if (part != 3) {
4041                                                 c = ceiling[part];
4042                                         } else {
4043                                                 /* make first arg to % non-negative */
4044                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
4045                                         }
4046                                         parts[part] += c;
4047                                         parts[part - 1]--;
4048                                         continue;
4049                                 } else if (part != 5) {
4050                                         break;
4051                                 }
4052                         }
4053                 }
4054         }
4055
4056         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
4057 }
4058
4059 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4060
4061 #if 0
4062 static int
4063 xutcTimeNormalize(
4064         Syntax *syntax,
4065         struct berval *val,
4066         struct berval *normalized )
4067 {
4068         int parts[9], rc;
4069
4070         rc = check_time_syntax(val, 1, parts, NULL);
4071         if (rc != LDAP_SUCCESS) {
4072                 return rc;
4073         }
4074
4075         normalized->bv_val = ch_malloc( 14 );
4076         if ( normalized->bv_val == NULL ) {
4077                 return LBER_ERROR_MEMORY;
4078         }
4079
4080         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
4081                 parts[1], parts[2] + 1, parts[3] + 1,
4082                 parts[4], parts[5], parts[6] );
4083         normalized->bv_len = 13;
4084
4085         return LDAP_SUCCESS;
4086 }
4087 #endif /* 0 */
4088
4089 static int
4090 utcTimeValidate(
4091         Syntax *syntax,
4092         struct berval *in )
4093 {
4094         int parts[9];
4095         return check_time_syntax(in, 1, parts, NULL);
4096 }
4097
4098 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
4099
4100 static int
4101 generalizedTimeValidate(
4102         Syntax *syntax,
4103         struct berval *in )
4104 {
4105         int parts[9];
4106         struct berval fraction;
4107         return check_time_syntax(in, 0, parts, &fraction);
4108 }
4109
4110 static int
4111 generalizedTimeNormalize(
4112         slap_mask_t usage,
4113         Syntax *syntax,
4114         MatchingRule *mr,
4115         struct berval *val,
4116         struct berval *normalized,
4117         void *ctx )
4118 {
4119         int parts[9], rc;
4120         unsigned int len;
4121         struct berval fraction;
4122
4123         rc = check_time_syntax(val, 0, parts, &fraction);
4124         if (rc != LDAP_SUCCESS) {
4125                 return rc;
4126         }
4127
4128         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
4129         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
4130         if ( BER_BVISNULL( normalized ) ) {
4131                 return LBER_ERROR_MEMORY;
4132         }
4133
4134         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
4135                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
4136                 parts[4], parts[5], parts[6] );
4137         if ( !BER_BVISEMPTY( &fraction ) ) {
4138                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
4139                         fraction.bv_val, fraction.bv_len );
4140                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
4141         }
4142         strcpy( normalized->bv_val + len-1, "Z" );
4143         normalized->bv_len = len;
4144
4145         return LDAP_SUCCESS;
4146 }
4147
4148 static int
4149 generalizedTimeOrderingMatch(
4150         int *matchp,
4151         slap_mask_t flags,
4152         Syntax *syntax,
4153         MatchingRule *mr,
4154         struct berval *value,
4155         void *assertedValue )
4156 {
4157         struct berval *asserted = (struct berval *) assertedValue;
4158         ber_len_t v_len  = value->bv_len;
4159         ber_len_t av_len = asserted->bv_len;
4160
4161         /* ignore trailing 'Z' when comparing */
4162         int match = memcmp( value->bv_val, asserted->bv_val,
4163                 (v_len < av_len ? v_len : av_len) - 1 );
4164         if ( match == 0 ) match = v_len - av_len;
4165
4166         *matchp = match;
4167         return LDAP_SUCCESS;
4168 }
4169
4170 /* Index generation function */
4171 int generalizedTimeIndexer(
4172         slap_mask_t use,
4173         slap_mask_t flags,
4174         Syntax *syntax,
4175         MatchingRule *mr,
4176         struct berval *prefix,
4177         BerVarray values,
4178         BerVarray *keysp,
4179         void *ctx )
4180 {
4181         int i, j;
4182         BerVarray keys;
4183         char tmp[5];
4184         BerValue bvtmp; /* 40 bit index */
4185         struct lutil_tm tm;
4186         struct lutil_timet tt;
4187
4188         bvtmp.bv_len = sizeof(tmp);
4189         bvtmp.bv_val = tmp;
4190         for( i=0; values[i].bv_val != NULL; i++ ) {
4191                 /* just count them */
4192         }
4193
4194         /* we should have at least one value at this point */
4195         assert( i > 0 );
4196
4197         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
4198
4199         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4200         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
4201                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
4202                 /* Use 40 bits of time for key */
4203                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
4204                         lutil_tm2time( &tm, &tt );
4205                         tmp[0] = tt.tt_gsec & 0xff;
4206                         tmp[4] = tt.tt_sec & 0xff;
4207                         tt.tt_sec >>= 8;
4208                         tmp[3] = tt.tt_sec & 0xff;
4209                         tt.tt_sec >>= 8;
4210                         tmp[2] = tt.tt_sec & 0xff;
4211                         tt.tt_sec >>= 8;
4212                         tmp[1] = tt.tt_sec & 0xff;
4213                         
4214                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
4215                 }
4216         }
4217
4218         keys[j].bv_val = NULL;
4219         keys[j].bv_len = 0;
4220
4221         *keysp = keys;
4222
4223         return LDAP_SUCCESS;
4224 }
4225
4226 /* Index generation function */
4227 int generalizedTimeFilter(
4228         slap_mask_t use,
4229         slap_mask_t flags,
4230         Syntax *syntax,
4231         MatchingRule *mr,
4232         struct berval *prefix,
4233         void * assertedValue,
4234         BerVarray *keysp,
4235         void *ctx )
4236 {
4237         BerVarray keys;
4238         char tmp[5];
4239         BerValue bvtmp; /* 40 bit index */
4240         BerValue *value = (BerValue *) assertedValue;
4241         struct lutil_tm tm;
4242         struct lutil_timet tt;
4243         
4244         bvtmp.bv_len = sizeof(tmp);
4245         bvtmp.bv_val = tmp;
4246         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4247         /* Use 40 bits of time for key */
4248         if ( value->bv_val && value->bv_len >= 10 &&
4249                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
4250
4251                 lutil_tm2time( &tm, &tt );
4252                 tmp[0] = tt.tt_gsec & 0xff;
4253                 tmp[4] = tt.tt_sec & 0xff;
4254                 tt.tt_sec >>= 8;
4255                 tmp[3] = tt.tt_sec & 0xff;
4256                 tt.tt_sec >>= 8;
4257                 tmp[2] = tt.tt_sec & 0xff;
4258                 tt.tt_sec >>= 8;
4259                 tmp[1] = tt.tt_sec & 0xff;
4260
4261                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
4262                 ber_dupbv_x(keys, &bvtmp, ctx );
4263                 keys[1].bv_val = NULL;
4264                 keys[1].bv_len = 0;
4265         } else {
4266                 keys = NULL;
4267         }
4268
4269         *keysp = keys;
4270
4271         return LDAP_SUCCESS;
4272 }
4273
4274 static int
4275 deliveryMethodValidate(
4276         Syntax *syntax,
4277         struct berval *val )
4278 {
4279 #undef LENOF
4280 #define LENOF(s) (sizeof(s)-1)
4281         struct berval tmp = *val;
4282         /*
4283      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
4284          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
4285          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
4286          */
4287 again:
4288         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4289
4290         switch( tmp.bv_val[0] ) {
4291         case 'a':
4292         case 'A':
4293                 if(( tmp.bv_len >= LENOF("any") ) &&
4294                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
4295                 {
4296                         tmp.bv_len -= LENOF("any");
4297                         tmp.bv_val += LENOF("any");
4298                         break;
4299                 }
4300                 return LDAP_INVALID_SYNTAX;
4301
4302         case 'm':
4303         case 'M':
4304                 if(( tmp.bv_len >= LENOF("mhs") ) &&
4305                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
4306                 {
4307                         tmp.bv_len -= LENOF("mhs");
4308                         tmp.bv_val += LENOF("mhs");
4309                         break;
4310                 }
4311                 return LDAP_INVALID_SYNTAX;
4312
4313         case 'p':
4314         case 'P':
4315                 if(( tmp.bv_len >= LENOF("physical") ) &&
4316                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
4317                 {
4318                         tmp.bv_len -= LENOF("physical");
4319                         tmp.bv_val += LENOF("physical");
4320                         break;
4321                 }
4322                 return LDAP_INVALID_SYNTAX;
4323
4324         case 't':
4325         case 'T': /* telex or teletex or telephone */
4326                 if(( tmp.bv_len >= LENOF("telex") ) &&
4327                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
4328                 {
4329                         tmp.bv_len -= LENOF("telex");
4330                         tmp.bv_val += LENOF("telex");
4331                         break;
4332                 }
4333                 if(( tmp.bv_len >= LENOF("teletex") ) &&
4334                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
4335                 {
4336                         tmp.bv_len -= LENOF("teletex");
4337                         tmp.bv_val += LENOF("teletex");
4338                         break;
4339                 }
4340                 if(( tmp.bv_len >= LENOF("telephone") ) &&
4341                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
4342                 {
4343                         tmp.bv_len -= LENOF("telephone");
4344                         tmp.bv_val += LENOF("telephone");
4345                         break;
4346                 }
4347                 return LDAP_INVALID_SYNTAX;
4348
4349         case 'g':
4350         case 'G': /* g3fax or g4fax */
4351                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
4352                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
4353                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
4354                 {
4355                         tmp.bv_len -= LENOF("g3fax");
4356                         tmp.bv_val += LENOF("g3fax");
4357                         break;
4358                 }
4359                 return LDAP_INVALID_SYNTAX;
4360
4361         case 'i':
4362         case 'I':
4363                 if(( tmp.bv_len >= LENOF("ia5") ) &&
4364                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
4365                 {
4366                         tmp.bv_len -= LENOF("ia5");
4367                         tmp.bv_val += LENOF("ia5");
4368                         break;
4369                 }
4370                 return LDAP_INVALID_SYNTAX;
4371
4372         case 'v':
4373         case 'V':
4374                 if(( tmp.bv_len >= LENOF("videotex") ) &&
4375                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
4376                 {
4377                         tmp.bv_len -= LENOF("videotex");
4378                         tmp.bv_val += LENOF("videotex");
4379                         break;
4380                 }
4381                 return LDAP_INVALID_SYNTAX;
4382
4383         default:
4384                 return LDAP_INVALID_SYNTAX;
4385         }
4386
4387         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
4388
4389         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4390                 tmp.bv_len++;
4391                 tmp.bv_val--;
4392         }
4393         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
4394                 tmp.bv_len++;
4395                 tmp.bv_val--;
4396         } else {
4397                 return LDAP_INVALID_SYNTAX;
4398         }
4399         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4400                 tmp.bv_len++;
4401                 tmp.bv_val--;
4402         }
4403
4404         goto again;
4405 }
4406
4407 static int
4408 nisNetgroupTripleValidate(
4409         Syntax *syntax,
4410         struct berval *val )
4411 {
4412         char *p, *e;
4413         int commas = 0;
4414
4415         if ( BER_BVISEMPTY( val ) ) {
4416                 return LDAP_INVALID_SYNTAX;
4417         }
4418
4419         p = (char *)val->bv_val;
4420         e = p + val->bv_len;
4421
4422         if ( *p != '(' /*')'*/ ) {
4423                 return LDAP_INVALID_SYNTAX;
4424         }
4425
4426         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
4427                 if ( *p == ',' ) {
4428                         commas++;
4429                         if ( commas > 2 ) {
4430                                 return LDAP_INVALID_SYNTAX;
4431                         }
4432
4433                 } else if ( !AD_CHAR( *p ) ) {
4434                         return LDAP_INVALID_SYNTAX;
4435                 }
4436         }
4437
4438         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4439                 return LDAP_INVALID_SYNTAX;
4440         }
4441
4442         p++;
4443
4444         if (p != e) {
4445                 return LDAP_INVALID_SYNTAX;
4446         }
4447
4448         return LDAP_SUCCESS;
4449 }
4450
4451 static int
4452 bootParameterValidate(
4453         Syntax *syntax,
4454         struct berval *val )
4455 {
4456         char *p, *e;
4457
4458         if ( BER_BVISEMPTY( val ) ) {
4459                 return LDAP_INVALID_SYNTAX;
4460         }
4461
4462         p = (char *)val->bv_val;
4463         e = p + val->bv_len;
4464
4465         /* key */
4466         for (; ( p < e ) && ( *p != '=' ); p++ ) {
4467                 if ( !AD_CHAR( *p ) ) {
4468                         return LDAP_INVALID_SYNTAX;
4469                 }
4470         }
4471
4472         if ( *p != '=' ) {
4473                 return LDAP_INVALID_SYNTAX;
4474         }
4475
4476         /* server */
4477         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4478                 if ( !AD_CHAR( *p ) ) {
4479                         return LDAP_INVALID_SYNTAX;
4480                 }
4481         }
4482
4483         if ( *p != ':' ) {
4484                 return LDAP_INVALID_SYNTAX;
4485         }
4486
4487         /* path */
4488         for ( p++; p < e; p++ ) {
4489                 if ( !SLAP_PRINTABLE( *p ) ) {
4490                         return LDAP_INVALID_SYNTAX;
4491                 }
4492         }
4493
4494         return LDAP_SUCCESS;
4495 }
4496
4497 static int
4498 firstComponentNormalize(
4499         slap_mask_t usage,
4500         Syntax *syntax,
4501         MatchingRule *mr,
4502         struct berval *val,
4503         struct berval *normalized,
4504         void *ctx )
4505 {
4506         int rc;
4507         struct berval comp;
4508         ber_len_t len;
4509
4510         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
4511                 ber_dupbv_x( normalized, val, ctx );
4512                 return LDAP_SUCCESS;
4513         }
4514
4515         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4516
4517         if( val->bv_val[0] != '(' /*')'*/ &&
4518                 val->bv_val[0] != '{' /*'}'*/ )
4519         {
4520                 return LDAP_INVALID_SYNTAX;
4521         }
4522
4523         /* trim leading white space */
4524         for( len=1;
4525                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
4526                 len++ )
4527         {
4528                 /* empty */
4529         }
4530
4531         /* grab next word */
4532         comp.bv_val = &val->bv_val[len];
4533         len = val->bv_len - len;
4534         for( comp.bv_len = 0;
4535                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
4536                 comp.bv_len++ )
4537         {
4538                 /* empty */
4539         }
4540
4541         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
4542                 rc = numericoidValidate( NULL, &comp );
4543         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
4544                 rc = integerValidate( NULL, &comp );
4545         } else {
4546                 rc = LDAP_INVALID_SYNTAX;
4547         }
4548         
4549
4550         if( rc == LDAP_SUCCESS ) {
4551                 ber_dupbv_x( normalized, &comp, ctx );
4552         }
4553
4554         return rc;
4555 }
4556
4557 static char *country_gen_syn[] = {
4558         "1.3.6.1.4.1.1466.115.121.1.15",
4559         "1.3.6.1.4.1.1466.115.121.1.26",
4560         "1.3.6.1.4.1.1466.115.121.1.44",
4561         NULL
4562 };
4563
4564 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4565 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4566
4567 static slap_syntax_defs_rec syntax_defs[] = {
4568         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4569                 X_BINARY X_NOT_H_R ")",
4570                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4571         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4572                 0, NULL, NULL, NULL},
4573         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4574                 0, NULL, NULL, NULL},
4575         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4576                 X_NOT_H_R ")",
4577                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4578         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4579                 X_NOT_H_R ")",
4580                 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4581         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4582                 0, NULL, bitStringValidate, NULL },
4583         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4584                 0, NULL, booleanValidate, NULL},
4585         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4586                 X_BINARY X_NOT_H_R ")",
4587                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4588                 NULL, certificateValidate, NULL},
4589         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4590                 X_BINARY X_NOT_H_R ")",
4591                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4592                 NULL, certificateListValidate, NULL},
4593         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4594                 X_BINARY X_NOT_H_R ")",
4595                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4596                 NULL, sequenceValidate, NULL},
4597 #if 0   /* need to go __after__ printableString */
4598         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4599                 0, "1.3.6.1.4.1.1466.115.121.1.44",
4600                 countryStringValidate, NULL},
4601 #endif
4602         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4603                 0, NULL, dnValidate, dnPretty},
4604         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4605                 0, NULL, rdnValidate, rdnPretty},
4606 #ifdef LDAP_COMP_MATCH
4607         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4608                 0, NULL, allComponentsValidate, NULL},
4609         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4610                 0, NULL, componentFilterValidate, NULL},
4611 #endif
4612         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4613                 0, NULL, NULL, NULL},
4614         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4615                 0, NULL, deliveryMethodValidate, NULL},
4616         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4617                 0, NULL, UTF8StringValidate, NULL},
4618         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4619                 0, NULL, NULL, NULL},
4620         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4621                 0, NULL, NULL, NULL},
4622         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4623                 0, NULL, NULL, NULL},
4624         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4625                 0, NULL, NULL, NULL},
4626         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4627                 0, NULL, NULL, NULL},
4628         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4629                 0, NULL, printablesStringValidate, NULL},
4630         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4631                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4632         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4633                 0, NULL, generalizedTimeValidate, NULL},
4634         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4635                 0, NULL, NULL, NULL},
4636         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4637                 0, NULL, IA5StringValidate, NULL},
4638         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4639                 0, NULL, integerValidate, NULL},
4640         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4641                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4642         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4643                 0, NULL, NULL, NULL},
4644         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4645                 0, NULL, NULL, NULL},
4646         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4647                 0, NULL, NULL, NULL},
4648         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4649                 0, NULL, NULL, NULL},
4650         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4651                 0, NULL, NULL, NULL},
4652         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4653                 0, NULL, nameUIDValidate, nameUIDPretty },
4654         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4655                 0, NULL, NULL, NULL},
4656         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4657                 0, NULL, numericStringValidate, NULL},
4658         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4659                 0, NULL, NULL, NULL},
4660         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4661                 0, NULL, numericoidValidate, NULL},
4662         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4663                 0, NULL, IA5StringValidate, NULL},
4664         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4665                 0, NULL, blobValidate, NULL},
4666         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4667                 0, NULL, UTF8StringValidate, NULL},
4668         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4669                 0, NULL, NULL, NULL},
4670         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4671                 0, NULL, NULL, NULL},
4672         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4673                 0, NULL, printableStringValidate, NULL},
4674         /* moved here because now depends on Directory String, IA5 String 
4675          * and Printable String */
4676         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4677                 0, country_gen_syn, countryStringValidate, NULL},
4678         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4679 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4680                 0, NULL, subtreeSpecificationValidate, NULL},
4681         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4682                 X_BINARY X_NOT_H_R ")",
4683                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4684         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4685                 0, NULL, printableStringValidate, NULL},
4686         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4687                 0, NULL, NULL, NULL},
4688         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4689                 0, NULL, printablesStringValidate, NULL},
4690 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4691         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4692                 0, NULL, utcTimeValidate, NULL},
4693 #endif
4694         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4695                 0, NULL, NULL, NULL},
4696         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4697                 0, NULL, NULL, NULL},
4698         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4699                 0, NULL, NULL, NULL},
4700         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4701                 0, NULL, NULL, NULL},
4702         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4703                 0, NULL, NULL, NULL},
4704
4705         /* RFC 2307 NIS Syntaxes */
4706         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4707                 0, NULL, nisNetgroupTripleValidate, NULL},
4708         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4709                 0, NULL, bootParameterValidate, NULL},
4710
4711         /* draft-zeilenga-ldap-x509 */
4712         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4713                 SLAP_SYNTAX_HIDE, NULL,
4714                 serialNumberAndIssuerValidate,
4715                 serialNumberAndIssuerPretty},
4716         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4717                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4718         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4719                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4720         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4721                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4722         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4723                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4724         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4725                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4726         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4727                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4728
4729 #ifdef SLAPD_AUTHPASSWD
4730         /* needs updating */
4731         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4732                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4733 #endif
4734
4735         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4736                 0, NULL, UUIDValidate, UUIDPretty},
4737
4738         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4739                 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
4740
4741         {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
4742                 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
4743
4744         /* OpenLDAP Void Syntax */
4745         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4746                 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
4747
4748         /* FIXME: OID is unused, but not registered yet */
4749         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4750                 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
4751
4752         {NULL, 0, NULL, NULL, NULL}
4753 };
4754
4755 char *csnSIDMatchSyntaxes[] = {
4756         "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
4757         NULL
4758 };
4759 char *certificateExactMatchSyntaxes[] = {
4760         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4761         NULL
4762 };
4763 #ifdef LDAP_COMP_MATCH
4764 char *componentFilterMatchSyntaxes[] = {
4765         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4766         NULL
4767 };
4768 #endif
4769 char *directoryStringSyntaxes[] = {
4770         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4771         NULL
4772 };
4773 char *integerFirstComponentMatchSyntaxes[] = {
4774         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4775         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4776         NULL
4777 };
4778 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4779         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4780         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
4781         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4782         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4783         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4784         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4785         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4786         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4787         NULL
4788 };
4789
4790 /*
4791  * Other matching rules in X.520 that we do not use (yet):
4792  *
4793  * 2.5.13.25    uTCTimeMatch
4794  * 2.5.13.26    uTCTimeOrderingMatch
4795  * 2.5.13.31*   directoryStringFirstComponentMatch
4796  * 2.5.13.32*   wordMatch
4797  * 2.5.13.33*   keywordMatch
4798  * 2.5.13.36+   certificatePairExactMatch
4799  * 2.5.13.37+   certificatePairMatch
4800  * 2.5.13.38+   certificateListExactMatch
4801  * 2.5.13.39+   certificateListMatch
4802  * 2.5.13.40+   algorithmIdentifierMatch
4803  * 2.5.13.41*   storedPrefixMatch
4804  * 2.5.13.42    attributeCertificateMatch
4805  * 2.5.13.43    readerAndKeyIDMatch
4806  * 2.5.13.44    attributeIntegrityMatch
4807  *
4808  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4809  * (+) described in draft-zeilenga-ldap-x509
4810  */
4811 static slap_mrule_defs_rec mrule_defs[] = {
4812         /*
4813          * EQUALITY matching rules must be listed after associated APPROX
4814          * matching rules.  So, we list all APPROX matching rules first.
4815          */
4816         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4817                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4818                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4819                 NULL, NULL, directoryStringApproxMatch,
4820                 directoryStringApproxIndexer, directoryStringApproxFilter,
4821                 NULL},
4822
4823         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4824                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4825                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4826                 NULL, NULL, IA5StringApproxMatch,
4827                 IA5StringApproxIndexer, IA5StringApproxFilter,
4828                 NULL},
4829
4830         /*
4831          * Other matching rules
4832          */
4833         
4834         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4835                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4836                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4837                 NULL, NULL, octetStringMatch,
4838                 octetStringIndexer, octetStringFilter,
4839                 NULL },
4840
4841         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4842                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4843                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4844                 NULL, dnNormalize, dnMatch,
4845                 octetStringIndexer, octetStringFilter,
4846                 NULL },
4847
4848         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4849                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4850                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4851                 NULL, dnNormalize, dnRelativeMatch,
4852                 NULL, NULL,
4853                 NULL },
4854
4855         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4856                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4857                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4858                 NULL, dnNormalize, dnRelativeMatch,
4859                 NULL, NULL,
4860                 NULL },
4861
4862         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4863                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4864                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4865                 NULL, dnNormalize, dnRelativeMatch,
4866                 NULL, NULL,
4867                 NULL },
4868
4869         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4870                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4871                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4872                 NULL, dnNormalize, dnRelativeMatch,
4873                 NULL, NULL,
4874                 NULL },
4875
4876         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4877                 "SYNTAX 1.2.36.79672281.1.5.0 )",
4878                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4879                 NULL, rdnNormalize, rdnMatch,
4880                 octetStringIndexer, octetStringFilter,
4881                 NULL },
4882
4883 #ifdef LDAP_COMP_MATCH
4884         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4885                 "SYNTAX 1.2.36.79672281.1.5.2 )",
4886                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4887                 NULL, NULL , componentFilterMatch,
4888                 octetStringIndexer, octetStringFilter,
4889                 NULL },
4890
4891         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4892                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4893                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4894                 NULL, NULL , allComponentsMatch,
4895                 octetStringIndexer, octetStringFilter,
4896                 NULL },
4897
4898         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4899                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4900                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4901                 NULL, NULL , directoryComponentsMatch,
4902                 octetStringIndexer, octetStringFilter,
4903                 NULL },
4904 #endif
4905
4906         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4907                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4908                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4909                 NULL, UTF8StringNormalize, octetStringMatch,
4910                 octetStringIndexer, octetStringFilter,
4911                 directoryStringApproxMatchOID },
4912
4913         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4914                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4915                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4916                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4917                 NULL, NULL,
4918                 "caseIgnoreMatch" },
4919
4920         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4921                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4922                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4923                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4924                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4925                 "caseIgnoreMatch" },
4926
4927         {"( 2.5.13.5 NAME 'caseExactMatch' "
4928                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4929                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4930                 NULL, UTF8StringNormalize, octetStringMatch,
4931                 octetStringIndexer, octetStringFilter,
4932                 directoryStringApproxMatchOID },
4933
4934         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4935                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4936                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4937                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4938                 NULL, NULL,
4939                 "caseExactMatch" },
4940
4941         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4942                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4943                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4944                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4945                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4946                 "caseExactMatch" },
4947
4948         {"( 2.5.13.8 NAME 'numericStringMatch' "
4949                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4950                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4951                 NULL, numericStringNormalize, octetStringMatch,
4952                 octetStringIndexer, octetStringFilter,
4953                 NULL },
4954
4955         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4956                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4957                 SLAP_MR_ORDERING, NULL,
4958                 NULL, numericStringNormalize, octetStringOrderingMatch,
4959                 NULL, NULL,
4960                 "numericStringMatch" },
4961
4962         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4963                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4964                 SLAP_MR_SUBSTR, NULL,
4965                 NULL, numericStringNormalize, octetStringSubstringsMatch,
4966                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4967                 "numericStringMatch" },
4968
4969         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4970                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4971                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4972                 NULL, NULL, NULL, NULL, NULL, NULL },
4973
4974         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4975                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4976                 SLAP_MR_SUBSTR, NULL,
4977                 NULL, NULL, NULL, NULL, NULL,
4978                 "caseIgnoreListMatch" },
4979
4980         {"( 2.5.13.13 NAME 'booleanMatch' "
4981                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4982                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4983                 NULL, NULL, booleanMatch,
4984                 octetStringIndexer, octetStringFilter,
4985                 NULL },
4986
4987         {"( 2.5.13.14 NAME 'integerMatch' "
4988                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4989                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4990                 NULL, NULL, integerMatch,
4991                 octetStringIndexer, octetStringFilter,
4992                 NULL },
4993
4994         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4995                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4996                 SLAP_MR_ORDERING, NULL,
4997                 NULL, NULL, integerMatch,
4998                 NULL, NULL,
4999                 "integerMatch" },
5000
5001         {"( 2.5.13.16 NAME 'bitStringMatch' "
5002                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
5003                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5004                 NULL, NULL, octetStringMatch,
5005                 octetStringIndexer, octetStringFilter,
5006                 NULL },
5007
5008         {"( 2.5.13.17 NAME 'octetStringMatch' "
5009                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5010                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5011                 NULL, NULL, octetStringMatch,
5012                 octetStringIndexer, octetStringFilter,
5013                 NULL },
5014
5015         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
5016                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5017                 SLAP_MR_ORDERING, NULL,
5018                 NULL, NULL, octetStringOrderingMatch,
5019                 NULL, NULL,
5020                 "octetStringMatch" },
5021
5022         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
5023                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5024                 SLAP_MR_SUBSTR, NULL,
5025                 NULL, NULL, octetStringSubstringsMatch,
5026                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5027                 "octetStringMatch" },
5028
5029         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
5030                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
5031                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5032                 NULL,
5033                 telephoneNumberNormalize, octetStringMatch,
5034                 octetStringIndexer, octetStringFilter,
5035                 NULL },
5036
5037         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
5038                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
5039                 SLAP_MR_SUBSTR, NULL,
5040                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
5041                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5042                 "telephoneNumberMatch" },
5043
5044         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
5045                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
5046                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5047                 NULL, NULL, NULL, NULL, NULL, NULL },
5048
5049         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
5050                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
5051                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5052                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
5053                 uniqueMemberIndexer, uniqueMemberFilter,
5054                 NULL },
5055
5056         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
5057                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
5058                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5059                 NULL, NULL, NULL, NULL, NULL, NULL },
5060
5061         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
5062                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5063                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
5064                 NULL, generalizedTimeNormalize, octetStringMatch,
5065                 generalizedTimeIndexer, generalizedTimeFilter,
5066                 NULL },
5067
5068         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
5069                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5070                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5071                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
5072                 NULL, NULL,
5073                 "generalizedTimeMatch" },
5074
5075         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
5076                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5077                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
5078                         integerFirstComponentMatchSyntaxes,
5079                 NULL, firstComponentNormalize, integerMatch,
5080                 octetStringIndexer, octetStringFilter,
5081                 NULL },
5082
5083         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
5084                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
5085                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
5086                         objectIdentifierFirstComponentMatchSyntaxes,
5087                 NULL, firstComponentNormalize, octetStringMatch,
5088                 octetStringIndexer, octetStringFilter,
5089                 NULL },
5090
5091         {"( 2.5.13.34 NAME 'certificateExactMatch' "
5092                 "SYNTAX 1.3.6.1.1.15.1 )",
5093                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
5094                 NULL, certificateExactNormalize, octetStringMatch,
5095                 octetStringIndexer, octetStringFilter,
5096                 NULL },
5097
5098         {"( 2.5.13.35 NAME 'certificateMatch' "
5099                 "SYNTAX 1.3.6.1.1.15.2 )",
5100                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5101                 NULL, NULL, NULL, NULL, NULL,
5102                 NULL },
5103
5104         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
5105                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5106                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5107                 NULL, IA5StringNormalize, octetStringMatch,
5108                 octetStringIndexer, octetStringFilter,
5109                 IA5StringApproxMatchOID },
5110
5111         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
5112                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5113                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5114                 NULL, IA5StringNormalize, octetStringMatch,
5115                 octetStringIndexer, octetStringFilter,
5116                 IA5StringApproxMatchOID },
5117
5118         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
5119                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5120                 SLAP_MR_SUBSTR, NULL,
5121                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5122                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5123                 "caseIgnoreIA5Match" },
5124
5125         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
5126                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5127                 SLAP_MR_SUBSTR, NULL,
5128                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5129                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5130                 "caseExactIA5Match" },
5131
5132 #ifdef SLAPD_AUTHPASSWD
5133         /* needs updating */
5134         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
5135                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5136                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5137                 NULL, NULL, authPasswordMatch,
5138                 NULL, NULL,
5139                 NULL},
5140 #endif
5141
5142         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
5143                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5144                 SLAP_MR_EXT, NULL,
5145                 NULL, NULL, integerBitAndMatch,
5146                 NULL, NULL,
5147                 "integerMatch" },
5148
5149         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
5150                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5151                 SLAP_MR_EXT, NULL,
5152                 NULL, NULL, integerBitOrMatch,
5153                 NULL, NULL,
5154                 "integerMatch" },
5155
5156         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
5157                 "SYNTAX 1.3.6.1.1.16.1 )",
5158                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
5159                 NULL, UUIDNormalize, octetStringMatch,
5160                 octetStringIndexer, octetStringFilter,
5161                 NULL},
5162
5163         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
5164                 "SYNTAX 1.3.6.1.1.16.1 )",
5165                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
5166                 NULL, UUIDNormalize, octetStringOrderingMatch,
5167                 octetStringIndexer, octetStringFilter,
5168                 "UUIDMatch"},
5169
5170         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
5171                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5172                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
5173                 NULL, csnNormalize, csnMatch,
5174                 csnIndexer, csnFilter,
5175                 NULL},
5176
5177         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
5178                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5179                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5180                 NULL, NULL, csnOrderingMatch,
5181                 NULL, NULL,
5182                 "CSNMatch" },
5183
5184         {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
5185                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
5186                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
5187                 NULL, csnSidNormalize, octetStringMatch,
5188                 octetStringIndexer, octetStringFilter,
5189                 NULL },
5190
5191         /* FIXME: OID is unused, but not registered yet */
5192         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
5193                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
5194                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5195                 NULL, authzNormalize, authzMatch,
5196                 NULL, NULL,
5197                 NULL},
5198
5199         {NULL, SLAP_MR_NONE, NULL,
5200                 NULL, NULL, NULL, NULL, NULL,
5201                 NULL }
5202 };
5203
5204 int
5205 slap_schema_init( void )
5206 {
5207         int             res;
5208         int             i;
5209
5210         /* we should only be called once (from main) */
5211         assert( schema_init_done == 0 );
5212
5213         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
5214                 res = register_syntax( &syntax_defs[i] );
5215
5216                 if ( res ) {
5217                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
5218                                  syntax_defs[i].sd_desc );
5219                         return LDAP_OTHER;
5220                 }
5221         }
5222
5223         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
5224                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
5225                         mrule_defs[i].mrd_compat_syntaxes == NULL )
5226                 {
5227                         fprintf( stderr,
5228                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
5229                                  mrule_defs[i].mrd_desc );
5230                         continue;
5231                 }
5232
5233                 res = register_matching_rule( &mrule_defs[i] );
5234
5235                 if ( res ) {
5236                         fprintf( stderr,
5237                                 "slap_schema_init: Error registering matching rule %s\n",
5238                                  mrule_defs[i].mrd_desc );
5239                         return LDAP_OTHER;
5240                 }
5241         }
5242
5243         res = slap_schema_load();
5244         schema_init_done = 1;
5245         return res;
5246 }
5247
5248 void
5249 schema_destroy( void )
5250 {
5251         oidm_destroy();
5252         oc_destroy();
5253         at_destroy();
5254         mr_destroy();
5255         mru_destroy();
5256         syn_destroy();
5257
5258         if( schema_init_done ) {
5259                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
5260                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
5261         }
5262 }