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