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