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