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