]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
Fixed bug in caseExactSubstringsIndexer() and caseIgnoreSubstringsIndexer().
[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,
1226                 UTF8_NOCASEFOLD ) );
1227         /* This usually happens if filter contains bad UTF8 */
1228         if( value == NULL ) {
1229                 keys = ch_malloc( sizeof( struct berval * ) );
1230                 keys[0] = NULL;
1231                 return LDAP_SUCCESS;
1232         }
1233 #else
1234         value = (struct berval *) assertValue;
1235 #endif
1236
1237         keys = ch_malloc( sizeof( struct berval * ) * 2 );
1238
1239         HASH_Init( &HASHcontext );
1240         if( prefix != NULL && prefix->bv_len > 0 ) {
1241                 HASH_Update( &HASHcontext,
1242                         prefix->bv_val, prefix->bv_len );
1243         }
1244         HASH_Update( &HASHcontext,
1245                 syntax->ssyn_oid, slen );
1246         HASH_Update( &HASHcontext,
1247                 mr->smr_oid, mlen );
1248         HASH_Update( &HASHcontext,
1249                 value->bv_val, value->bv_len );
1250         HASH_Final( HASHdigest, &HASHcontext );
1251
1252         keys[0] = ber_bvdup( &digest );
1253         keys[1] = NULL;
1254
1255 #if UTF8MATCH
1256         ber_bvfree( value );
1257 #endif
1258
1259         *keysp = keys;
1260         return LDAP_SUCCESS;
1261 }
1262
1263 /* Substrings Index generation function */
1264 int caseExactSubstringsIndexer(
1265         slap_mask_t use,
1266         slap_mask_t flags,
1267         Syntax *syntax,
1268         MatchingRule *mr,
1269         struct berval *prefix,
1270         struct berval **values,
1271         struct berval ***keysp )
1272 {
1273         ber_len_t i, nkeys;
1274         size_t slen, mlen;
1275         struct berval **keys;
1276 #if UTF8MATCH
1277         struct berval **nvalues;
1278 #endif
1279
1280         HASH_CONTEXT   HASHcontext;
1281         unsigned char   HASHdigest[HASH_BYTES];
1282         struct berval digest;
1283         digest.bv_val = HASHdigest;
1284         digest.bv_len = sizeof(HASHdigest);
1285
1286         /* we should have at least one value at this point */
1287         assert( values != NULL && values[0] != NULL );
1288
1289         nkeys=0;
1290
1291 #if UTF8MATCH
1292         /* create normalized copy of values */
1293         for( i=0; values[i] != NULL; i++ ) {
1294                 /* empty */
1295         }
1296         nvalues = ch_malloc( sizeof( struct berval * ) * (i+1) );
1297         for( i=0; values[i] != NULL; i++ ) {
1298                 nvalues[i] = ber_bvstr( UTF8normalize( values[i]->bv_val, UTF8_NOCASEFOLD ) );
1299         }
1300         nvalues[i] = NULL;
1301         values = nvalues;
1302 #endif
1303
1304         for( i=0; values[i] != NULL; i++ ) {
1305                 /* count number of indices to generate */
1306                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
1307                         continue;
1308                 }
1309
1310                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1311                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1312                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
1313                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
1314                         } else {
1315                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
1316                         }
1317                 }
1318
1319                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
1320                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1321                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
1322                         }
1323                 }
1324
1325                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1326                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1327                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
1328                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
1329                         } else {
1330                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
1331                         }
1332                 }
1333         }
1334
1335         if( nkeys == 0 ) {
1336                 /* no keys to generate */
1337                 *keysp = NULL;
1338                 return LDAP_SUCCESS;
1339         }
1340
1341         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
1342
1343         slen = strlen( syntax->ssyn_oid );
1344         mlen = strlen( mr->smr_oid );
1345
1346         nkeys=0;
1347         for( i=0; values[i] != NULL; i++ ) {
1348                 ber_len_t j,max;
1349                 struct berval *value;
1350
1351                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
1352
1353                 value = values[i];
1354
1355                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
1356                         ( value->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
1357                 {
1358                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
1359                         max = value->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
1360
1361                         for( j=0; j<max; j++ ) {
1362                                 HASH_Init( &HASHcontext );
1363                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1364                                         HASH_Update( &HASHcontext,
1365                                                 prefix->bv_val, prefix->bv_len );
1366                                 }
1367
1368                                 HASH_Update( &HASHcontext,
1369                                         &pre, sizeof( pre ) );
1370                                 HASH_Update( &HASHcontext,
1371                                         syntax->ssyn_oid, slen );
1372                                 HASH_Update( &HASHcontext,
1373                                         mr->smr_oid, mlen );
1374                                 HASH_Update( &HASHcontext,
1375                                         &value->bv_val[j],
1376                                         SLAP_INDEX_SUBSTR_MAXLEN );
1377                                 HASH_Final( HASHdigest, &HASHcontext );
1378
1379                                 keys[nkeys++] = ber_bvdup( &digest );
1380                         }
1381                 }
1382
1383                 max = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
1384                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
1385
1386                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
1387                         char pre;
1388
1389                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1390                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1391                                 HASH_Init( &HASHcontext );
1392                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1393                                         HASH_Update( &HASHcontext,
1394                                                 prefix->bv_val, prefix->bv_len );
1395                                 }
1396                                 HASH_Update( &HASHcontext,
1397                                         &pre, sizeof( pre ) );
1398                                 HASH_Update( &HASHcontext,
1399                                         syntax->ssyn_oid, slen );
1400                                 HASH_Update( &HASHcontext,
1401                                         mr->smr_oid, mlen );
1402                                 HASH_Update( &HASHcontext,
1403                                         value->bv_val, j );
1404                                 HASH_Final( HASHdigest, &HASHcontext );
1405
1406                                 keys[nkeys++] = ber_bvdup( &digest );
1407                         }
1408
1409                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1410                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1411                                 HASH_Init( &HASHcontext );
1412                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1413                                         HASH_Update( &HASHcontext,
1414                                                 prefix->bv_val, prefix->bv_len );
1415                                 }
1416                                 HASH_Update( &HASHcontext,
1417                                         &pre, sizeof( pre ) );
1418                                 HASH_Update( &HASHcontext,
1419                                         syntax->ssyn_oid, slen );
1420                                 HASH_Update( &HASHcontext,
1421                                         mr->smr_oid, mlen );
1422                                 HASH_Update( &HASHcontext,
1423                                         &value->bv_val[value->bv_len-j], j );
1424                                 HASH_Final( HASHdigest, &HASHcontext );
1425
1426                                 keys[nkeys++] = ber_bvdup( &digest );
1427                         }
1428
1429                 }
1430
1431         }
1432
1433         if( nkeys > 0 ) {
1434                 keys[nkeys] = NULL;
1435                 *keysp = keys;
1436         } else {
1437                 ch_free( keys );
1438                 *keysp = NULL;
1439         }
1440
1441 #if UTF8MATCH
1442         ber_bvecfree( nvalues );
1443 #endif
1444
1445         return LDAP_SUCCESS;
1446 }
1447
1448 int caseExactSubstringsFilter(
1449         slap_mask_t use,
1450         slap_mask_t flags,
1451         Syntax *syntax,
1452         MatchingRule *mr,
1453         struct berval *prefix,
1454         void * assertValue,
1455         struct berval ***keysp )
1456 {
1457         SubstringsAssertion *sa = assertValue;
1458         char pre;
1459         ber_len_t nkeys = 0;
1460         size_t slen, mlen, klen;
1461         struct berval **keys;
1462         HASH_CONTEXT   HASHcontext;
1463         unsigned char   HASHdigest[HASH_BYTES];
1464         struct berval *value;
1465         struct berval digest;
1466
1467         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial != NULL &&
1468                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1469         {
1470                 nkeys++;
1471         }
1472
1473         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1474                 ber_len_t i;
1475                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
1476                         if( sa->sa_any[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1477                                 /* don't bother accounting for stepping */
1478                                 nkeys += sa->sa_any[i]->bv_len -
1479                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
1480                         }
1481                 }
1482         }
1483
1484         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final != NULL &&
1485                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1486         {
1487                 nkeys++;
1488         }
1489
1490         if( nkeys == 0 ) {
1491                 *keysp = NULL;
1492                 return LDAP_SUCCESS;
1493         }
1494
1495         digest.bv_val = HASHdigest;
1496         digest.bv_len = sizeof(HASHdigest);
1497
1498         slen = strlen( syntax->ssyn_oid );
1499         mlen = strlen( mr->smr_oid );
1500
1501         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
1502         nkeys = 0;
1503
1504         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial != NULL &&
1505                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1506         {
1507                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1508 #if UTF8MATCH
1509                 value = ber_bvstr( UTF8normalize( sa->sa_initial->bv_val,
1510                         UTF8_NOCASEFOLD ) );
1511 #else
1512                 value = sa->sa_initial;
1513 #endif
1514
1515                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
1516                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
1517
1518                 HASH_Init( &HASHcontext );
1519                 if( prefix != NULL && prefix->bv_len > 0 ) {
1520                         HASH_Update( &HASHcontext,
1521                                 prefix->bv_val, prefix->bv_len );
1522                 }
1523                 HASH_Update( &HASHcontext,
1524                         &pre, sizeof( pre ) );
1525                 HASH_Update( &HASHcontext,
1526                         syntax->ssyn_oid, slen );
1527                 HASH_Update( &HASHcontext,
1528                         mr->smr_oid, mlen );
1529                 HASH_Update( &HASHcontext,
1530                         value->bv_val, klen );
1531                 HASH_Final( HASHdigest, &HASHcontext );
1532
1533 #if UTF8MATCH
1534                 ber_bvfree( value );
1535 #endif
1536                 keys[nkeys++] = ber_bvdup( &digest );
1537         }
1538
1539         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1540                 ber_len_t i, j;
1541                 pre = SLAP_INDEX_SUBSTR_PREFIX;
1542                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
1543
1544                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
1545                         if( sa->sa_any[i]->bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
1546                                 continue;
1547                         }
1548
1549 #if UTF8MATCH
1550                 value = ber_bvstr( UTF8normalize( sa->sa_any[i]->bv_val,
1551                                 UTF8_NOCASEFOLD ) );
1552 #else
1553                         value = sa->sa_any[i];
1554 #endif
1555
1556                         for(j=0;
1557                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
1558                                 j += SLAP_INDEX_SUBSTR_STEP )
1559                         {
1560                                 HASH_Init( &HASHcontext );
1561                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1562                                         HASH_Update( &HASHcontext,
1563                                                 prefix->bv_val, prefix->bv_len );
1564                                 }
1565                                 HASH_Update( &HASHcontext,
1566                                         &pre, sizeof( pre ) );
1567                                 HASH_Update( &HASHcontext,
1568                                         syntax->ssyn_oid, slen );
1569                                 HASH_Update( &HASHcontext,
1570                                         mr->smr_oid, mlen );
1571                                 HASH_Update( &HASHcontext,
1572                                         &value->bv_val[j], klen ); 
1573                                 HASH_Final( HASHdigest, &HASHcontext );
1574
1575                                 keys[nkeys++] = ber_bvdup( &digest );
1576                         }
1577
1578 #if UTF8MATCH
1579                         ber_bvfree( value );
1580 #endif
1581                 }
1582         }
1583
1584         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final != NULL &&
1585                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1586         {
1587                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1588 #if UTF8MATCH
1589                 value = ber_bvstr( UTF8normalize( sa->sa_final->bv_val,
1590                         UTF8_NOCASEFOLD ) );
1591 #else
1592                 value = sa->sa_final;
1593 #endif
1594
1595                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
1596                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
1597
1598                 HASH_Init( &HASHcontext );
1599                 if( prefix != NULL && prefix->bv_len > 0 ) {
1600                         HASH_Update( &HASHcontext,
1601                                 prefix->bv_val, prefix->bv_len );
1602                 }
1603                 HASH_Update( &HASHcontext,
1604                         &pre, sizeof( pre ) );
1605                 HASH_Update( &HASHcontext,
1606                         syntax->ssyn_oid, slen );
1607                 HASH_Update( &HASHcontext,
1608                         mr->smr_oid, mlen );
1609                 HASH_Update( &HASHcontext,
1610                         &value->bv_val[value->bv_len-klen], klen );
1611                 HASH_Final( HASHdigest, &HASHcontext );
1612
1613 #if UTF8MATCH
1614                 ber_bvfree( value );
1615 #endif
1616                 keys[nkeys++] = ber_bvdup( &digest );
1617         }
1618
1619         if( nkeys > 0 ) {
1620                 keys[nkeys] = NULL;
1621                 *keysp = keys;
1622         } else {
1623                 ch_free( keys );
1624                 *keysp = NULL;
1625         }
1626
1627         return LDAP_SUCCESS;
1628 }
1629         
1630 static int
1631 caseIgnoreMatch(
1632         int *matchp,
1633         slap_mask_t flags,
1634         Syntax *syntax,
1635         MatchingRule *mr,
1636         struct berval *value,
1637         void *assertedValue )
1638 {
1639 #if UTF8MATCH
1640         *matchp = UTF8normcmp( value->bv_val,
1641                 ((struct berval *) assertedValue)->bv_val,
1642                 UTF8_CASEFOLD );
1643 #else
1644         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
1645
1646         if( match == 0 ) {
1647                 match = strncasecmp( value->bv_val,
1648                         ((struct berval *) assertedValue)->bv_val,
1649                         value->bv_len );
1650         }
1651
1652         *matchp = match;
1653 #endif
1654         return LDAP_SUCCESS;
1655 }
1656
1657 static int
1658 caseIgnoreSubstringsMatch(
1659         int *matchp,
1660         slap_mask_t flags,
1661         Syntax *syntax,
1662         MatchingRule *mr,
1663         struct berval *value,
1664         void *assertedValue )
1665 {
1666         int match = 0;
1667         SubstringsAssertion *sub = assertedValue;
1668         struct berval left = *value;
1669         int i;
1670         ber_len_t inlen=0;
1671
1672         /* Add up asserted input length */
1673         if( sub->sa_initial ) {
1674                 inlen += sub->sa_initial->bv_len;
1675         }
1676         if( sub->sa_any ) {
1677                 for(i=0; sub->sa_any[i] != NULL; i++) {
1678                         inlen += sub->sa_any[i]->bv_len;
1679                 }
1680         }
1681         if( sub->sa_final ) {
1682                 inlen += sub->sa_final->bv_len;
1683         }
1684
1685         if( sub->sa_initial ) {
1686                 if( inlen > left.bv_len ) {
1687                         match = 1;
1688                         goto done;
1689                 }
1690
1691 #if UTF8MATCH
1692                 match = UTF8oncasecmp( sub->sa_initial, &left,
1693                         sub->sa_initial->bv_len, 0 );
1694 #else           
1695                 match = strncasecmp( sub->sa_initial->bv_val, left.bv_val,
1696                         sub->sa_initial->bv_len );
1697 #endif
1698
1699                 if( match != 0 ) {
1700                         goto done;
1701                 }
1702
1703                 left.bv_val += sub->sa_initial->bv_len;
1704                 left.bv_len -= sub->sa_initial->bv_len;
1705                 inlen -= sub->sa_initial->bv_len;
1706         }
1707
1708         if( sub->sa_final ) {
1709                 if( inlen > left.bv_len ) {
1710                         match = 1;
1711                         goto done;
1712                 }
1713
1714 #if UTF8MATCH
1715                 match = UTF8oncasecmp( sub->sa_final, &left,
1716                         sub->sa_final->bv_len,
1717                         left.bv_len - sub->sa_final->bv_len );
1718 #else           
1719                 match = strncasecmp( sub->sa_final->bv_val,
1720                         &left.bv_val[left.bv_len - sub->sa_final->bv_len],
1721                         sub->sa_final->bv_len );
1722 #endif
1723
1724                 if( match != 0 ) {
1725                         goto done;
1726                 }
1727
1728                 left.bv_len -= sub->sa_final->bv_len;
1729                 inlen -= sub->sa_final->bv_len;
1730         }
1731
1732         if( sub->sa_any ) {
1733                 for(i=0; sub->sa_any[i]; i++) {
1734                         ber_len_t idx;
1735                         char *p;
1736
1737 retry:
1738                         if( inlen > left.bv_len ) {
1739                                 /* not enough length */
1740                                 match = 1;
1741                                 goto done;
1742                         }
1743
1744                         if( sub->sa_any[i]->bv_len == 0 ) {
1745                                 continue;
1746                         }
1747
1748 #if UTF8MATCH
1749                         p = UTF8casechr( left.bv_val, sub->sa_any[i]->bv_val );
1750 #else
1751                         p = strcasechr( left.bv_val, *sub->sa_any[i]->bv_val );
1752 #endif
1753
1754                         if( p == NULL ) {
1755                                 match = 1;
1756                                 goto done;
1757                         }
1758
1759                         idx = p - left.bv_val;
1760                         assert( idx < left.bv_len );
1761
1762                         if( idx >= left.bv_len ) {
1763                                 /* this shouldn't happen */
1764                                 return LDAP_OTHER;
1765                         }
1766
1767                         left.bv_val = p;
1768                         left.bv_len -= idx;
1769
1770                         if( sub->sa_any[i]->bv_len > left.bv_len ) {
1771                                 /* not enough left */
1772                                 match = 1;
1773                                 goto done;
1774                         }
1775
1776 #if UTF8MATCH
1777                         match = UTF8oncasecmp( &left, sub->sa_any[i],
1778                                 sub->sa_any[i]->bv_len, 0 );
1779
1780                         if( match != 0 ) {
1781                                 int len = LDAP_UTF8_CHARLEN( left.bv_val );
1782                                 left.bv_val += len;
1783                                 left.bv_len -= len;
1784                                 goto retry;
1785                         }
1786 #else                   
1787                         match = strncasecmp( left.bv_val,
1788                                 sub->sa_any[i]->bv_val,
1789                                 sub->sa_any[i]->bv_len );
1790
1791                         if( match != 0 ) {
1792                                 left.bv_val++;
1793                                 left.bv_len--;
1794
1795                                 goto retry;
1796                         }
1797 #endif
1798
1799                         left.bv_val += sub->sa_any[i]->bv_len;
1800                         left.bv_len -= sub->sa_any[i]->bv_len;
1801                         inlen -= sub->sa_any[i]->bv_len;
1802                 }
1803         }
1804
1805 done:
1806         *matchp = match;
1807         return LDAP_SUCCESS;
1808 }
1809
1810 /* Index generation function */
1811 int caseIgnoreIndexer(
1812         slap_mask_t use,
1813         slap_mask_t flags,
1814         Syntax *syntax,
1815         MatchingRule *mr,
1816         struct berval *prefix,
1817         struct berval **values,
1818         struct berval ***keysp )
1819 {
1820         int i;
1821         size_t slen, mlen;
1822         struct berval **keys;
1823         HASH_CONTEXT   HASHcontext;
1824         unsigned char   HASHdigest[HASH_BYTES];
1825         struct berval digest;
1826         digest.bv_val = HASHdigest;
1827         digest.bv_len = sizeof(HASHdigest);
1828
1829         /* we should have at least one value at this point */
1830         assert( values != NULL && values[0] != NULL );
1831
1832         for( i=0; values[i] != NULL; i++ ) {
1833                 /* just count them */
1834         }
1835
1836         keys = ch_malloc( sizeof( struct berval * ) * (i+1) );
1837
1838         slen = strlen( syntax->ssyn_oid );
1839         mlen = strlen( mr->smr_oid );
1840
1841         for( i=0; values[i] != NULL; i++ ) {
1842                 struct berval *value;
1843 #if UTF8MATCH
1844                 value = ber_bvstr( UTF8normalize( values[i]->bv_val, UTF8_CASEFOLD ) );
1845 #else
1846                 value = ber_bvdup( values[i] );
1847                 ldap_pvt_str2upper( value->bv_val );
1848 #endif
1849                 HASH_Init( &HASHcontext );
1850                 if( prefix != NULL && prefix->bv_len > 0 ) {
1851                         HASH_Update( &HASHcontext,
1852                                 prefix->bv_val, prefix->bv_len );
1853                 }
1854                 HASH_Update( &HASHcontext,
1855                         syntax->ssyn_oid, slen );
1856                 HASH_Update( &HASHcontext,
1857                         mr->smr_oid, mlen );
1858                 HASH_Update( &HASHcontext,
1859                         value->bv_val, value->bv_len );
1860                 HASH_Final( HASHdigest, &HASHcontext );
1861
1862                 ber_bvfree( value );
1863
1864                 keys[i] = ber_bvdup( &digest );
1865         }
1866
1867         keys[i] = NULL;
1868         *keysp = keys;
1869         return LDAP_SUCCESS;
1870 }
1871
1872 /* Index generation function */
1873 int caseIgnoreFilter(
1874         slap_mask_t use,
1875         slap_mask_t flags,
1876         Syntax *syntax,
1877         MatchingRule *mr,
1878         struct berval *prefix,
1879         void * assertValue,
1880         struct berval ***keysp )
1881 {
1882         size_t slen, mlen;
1883         struct berval **keys;
1884         HASH_CONTEXT   HASHcontext;
1885         unsigned char   HASHdigest[HASH_BYTES];
1886         struct berval *value;
1887         struct berval digest;
1888         digest.bv_val = HASHdigest;
1889         digest.bv_len = sizeof(HASHdigest);
1890
1891         slen = strlen( syntax->ssyn_oid );
1892         mlen = strlen( mr->smr_oid );
1893
1894 #if UTF8MATCH
1895         value = ber_bvstr( UTF8normalize( ((struct berval *) assertValue)->bv_val,
1896                 UTF8_CASEFOLD ) );
1897         /* This usually happens if filter contains bad UTF8 */
1898         if( value == NULL ) {
1899                 keys = ch_malloc( sizeof( struct berval * ) );
1900                 keys[0] = NULL;
1901                 return LDAP_SUCCESS;
1902         }
1903 #else
1904         value = ber_bvdup( (struct berval *) assertValue );
1905         ldap_pvt_str2upper( value->bv_val );
1906 #endif
1907
1908         keys = ch_malloc( sizeof( struct berval * ) * 2 );
1909
1910         HASH_Init( &HASHcontext );
1911         if( prefix != NULL && prefix->bv_len > 0 ) {
1912                 HASH_Update( &HASHcontext,
1913                         prefix->bv_val, prefix->bv_len );
1914         }
1915         HASH_Update( &HASHcontext,
1916                 syntax->ssyn_oid, slen );
1917         HASH_Update( &HASHcontext,
1918                 mr->smr_oid, mlen );
1919         HASH_Update( &HASHcontext,
1920                 value->bv_val, value->bv_len );
1921         HASH_Final( HASHdigest, &HASHcontext );
1922
1923         keys[0] = ber_bvdup( &digest );
1924         keys[1] = NULL;
1925
1926         ber_bvfree( value );
1927
1928         *keysp = keys;
1929
1930         return LDAP_SUCCESS;
1931 }
1932
1933 /* Substrings Index generation function */
1934 int caseIgnoreSubstringsIndexer(
1935         slap_mask_t use,
1936         slap_mask_t flags,
1937         Syntax *syntax,
1938         MatchingRule *mr,
1939         struct berval *prefix,
1940         struct berval **values,
1941         struct berval ***keysp )
1942 {
1943         ber_len_t i, nkeys;
1944         size_t slen, mlen;
1945         struct berval **keys;
1946 #if UTF8MATCH
1947         struct berval **nvalues;
1948 #endif
1949
1950         HASH_CONTEXT   HASHcontext;
1951         unsigned char   HASHdigest[HASH_BYTES];
1952         struct berval digest;
1953         digest.bv_val = HASHdigest;
1954         digest.bv_len = sizeof(HASHdigest);
1955
1956         /* we should have at least one value at this point */
1957         assert( values != NULL && values[0] != NULL );
1958
1959         nkeys=0;
1960
1961 #if UTF8MATCH
1962         /* create normalized copy of values */
1963         for( i=0; values[i] != NULL; i++ ) {
1964                 /* empty */
1965         }
1966         nvalues = ch_malloc( sizeof( struct berval * ) * (i+1) );
1967         for( i=0; values[i] != NULL; i++ ) {
1968                 nvalues[i] = ber_bvstr( UTF8normalize( values[i]->bv_val, UTF8_CASEFOLD ) );
1969         }
1970         nvalues[i] = NULL;
1971         values = nvalues;
1972 #endif
1973
1974         for( i=0; values[i] != NULL; i++ ) {
1975                 /* count number of indices to generate */
1976                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
1977                         continue;
1978                 }
1979
1980                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1981                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1982                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
1983                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
1984                         } else {
1985                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
1986                         }
1987                 }
1988
1989                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
1990                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1991                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
1992                         }
1993                 }
1994
1995                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1996                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1997                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
1998                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
1999                         } else {
2000                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
2001                         }
2002                 }
2003         }
2004
2005         if( nkeys == 0 ) {
2006                 /* no keys to generate */
2007                 *keysp = NULL;
2008                 return LDAP_SUCCESS;
2009         }
2010
2011         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
2012
2013         slen = strlen( syntax->ssyn_oid );
2014         mlen = strlen( mr->smr_oid );
2015
2016         nkeys=0;
2017         for( i=0; values[i] != NULL; i++ ) {
2018                 int j,max;
2019                 struct berval *value;
2020
2021                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
2022
2023 #if UTF8MATCH
2024                 value = values[i];
2025 #else
2026                 value = ber_bvdup( values[i] );
2027                 ldap_pvt_str2upper( value->bv_val );
2028 #endif
2029
2030                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
2031                         ( value->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
2032                 {
2033                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
2034                         max = value->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
2035
2036                         for( j=0; j<max; j++ ) {
2037                                 HASH_Init( &HASHcontext );
2038                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2039                                         HASH_Update( &HASHcontext,
2040                                                 prefix->bv_val, prefix->bv_len );
2041                                 }
2042
2043                                 HASH_Update( &HASHcontext,
2044                                         &pre, sizeof( pre ) );
2045                                 HASH_Update( &HASHcontext,
2046                                         syntax->ssyn_oid, slen );
2047                                 HASH_Update( &HASHcontext,
2048                                         mr->smr_oid, mlen );
2049                                 HASH_Update( &HASHcontext,
2050                                         &value->bv_val[j],
2051                                         SLAP_INDEX_SUBSTR_MAXLEN );
2052                                 HASH_Final( HASHdigest, &HASHcontext );
2053
2054                                 keys[nkeys++] = ber_bvdup( &digest );
2055                         }
2056                 }
2057
2058                 max = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2059                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2060
2061                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
2062                         char pre;
2063
2064                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
2065                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
2066                                 HASH_Init( &HASHcontext );
2067                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2068                                         HASH_Update( &HASHcontext,
2069                                                 prefix->bv_val, prefix->bv_len );
2070                                 }
2071                                 HASH_Update( &HASHcontext,
2072                                         &pre, sizeof( pre ) );
2073                                 HASH_Update( &HASHcontext,
2074                                         syntax->ssyn_oid, slen );
2075                                 HASH_Update( &HASHcontext,
2076                                         mr->smr_oid, mlen );
2077                                 HASH_Update( &HASHcontext,
2078                                         value->bv_val, j );
2079                                 HASH_Final( HASHdigest, &HASHcontext );
2080
2081                                 keys[nkeys++] = ber_bvdup( &digest );
2082                         }
2083
2084                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
2085                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
2086                                 HASH_Init( &HASHcontext );
2087                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2088                                         HASH_Update( &HASHcontext,
2089                                                 prefix->bv_val, prefix->bv_len );
2090                                 }
2091                                 HASH_Update( &HASHcontext,
2092                                         &pre, sizeof( pre ) );
2093                                 HASH_Update( &HASHcontext,
2094                                         syntax->ssyn_oid, slen );
2095                                 HASH_Update( &HASHcontext,
2096                                         mr->smr_oid, mlen );
2097                                 HASH_Update( &HASHcontext,
2098                                         &value->bv_val[value->bv_len-j], j );
2099                                 HASH_Final( HASHdigest, &HASHcontext );
2100
2101                                 keys[nkeys++] = ber_bvdup( &digest );
2102                         }
2103
2104                 }
2105 #if !UTF8MATCH
2106                 ber_bvfree( value );
2107 #endif
2108         }
2109
2110         if( nkeys > 0 ) {
2111                 keys[nkeys] = NULL;
2112                 *keysp = keys;
2113         } else {
2114                 ch_free( keys );
2115                 *keysp = NULL;
2116         }
2117
2118 #if UTF8MATCH
2119         ber_bvecfree( nvalues );
2120 #endif
2121         return LDAP_SUCCESS;
2122 }
2123
2124 int caseIgnoreSubstringsFilter(
2125         slap_mask_t use,
2126         slap_mask_t flags,
2127         Syntax *syntax,
2128         MatchingRule *mr,
2129         struct berval *prefix,
2130         void * assertValue,
2131         struct berval ***keysp )
2132 {
2133         SubstringsAssertion *sa = assertValue;
2134         char pre;
2135         ber_len_t nkeys = 0;
2136         size_t slen, mlen, klen;
2137         struct berval **keys;
2138         HASH_CONTEXT   HASHcontext;
2139         unsigned char   HASHdigest[HASH_BYTES];
2140         struct berval *value;
2141         struct berval digest;
2142
2143         if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial != NULL &&
2144                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2145         {
2146                 nkeys++;
2147         }
2148
2149         if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
2150                 ber_len_t i;
2151                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
2152                         if( sa->sa_any[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2153                                 /* don't bother accounting for stepping */
2154                                 nkeys += sa->sa_any[i]->bv_len -
2155                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
2156                         }
2157                 }
2158         }
2159
2160         if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final != NULL &&
2161                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2162         {
2163                 nkeys++;
2164         }
2165
2166         if( nkeys == 0 ) {
2167                 *keysp = NULL;
2168                 return LDAP_SUCCESS;
2169         }
2170
2171         digest.bv_val = HASHdigest;
2172         digest.bv_len = sizeof(HASHdigest);
2173
2174         slen = strlen( syntax->ssyn_oid );
2175         mlen = strlen( mr->smr_oid );
2176
2177         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
2178         nkeys = 0;
2179
2180         if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial != NULL &&
2181                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2182         {
2183                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
2184 #if UTF8MATCH
2185                 value = ber_bvstr( UTF8normalize( sa->sa_initial->bv_val, UTF8_CASEFOLD ) );
2186 #else
2187                 value = ber_bvdup( sa->sa_initial );
2188                 ldap_pvt_str2upper( value->bv_val );
2189 #endif
2190
2191                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2192                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2193
2194                 HASH_Init( &HASHcontext );
2195                 if( prefix != NULL && prefix->bv_len > 0 ) {
2196                         HASH_Update( &HASHcontext,
2197                                 prefix->bv_val, prefix->bv_len );
2198                 }
2199                 HASH_Update( &HASHcontext,
2200                         &pre, sizeof( pre ) );
2201                 HASH_Update( &HASHcontext,
2202                         syntax->ssyn_oid, slen );
2203                 HASH_Update( &HASHcontext,
2204                         mr->smr_oid, mlen );
2205                 HASH_Update( &HASHcontext,
2206                         value->bv_val, klen );
2207                 HASH_Final( HASHdigest, &HASHcontext );
2208
2209                 ber_bvfree( value );
2210                 keys[nkeys++] = ber_bvdup( &digest );
2211         }
2212
2213         if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
2214                 ber_len_t i, j;
2215                 pre = SLAP_INDEX_SUBSTR_PREFIX;
2216                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
2217
2218                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
2219                         if( sa->sa_any[i]->bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
2220                                 continue;
2221                         }
2222
2223 #if UTF8MATCH
2224                         value = ber_bvstr( UTF8normalize( sa->sa_any[i]->bv_val, UTF8_CASEFOLD ) );
2225 #else
2226                         value = ber_bvdup( sa->sa_any[i] );
2227                         ldap_pvt_str2upper( value->bv_val );
2228 #endif
2229
2230                         for(j=0;
2231                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
2232                                 j += SLAP_INDEX_SUBSTR_STEP )
2233                         {
2234                                 HASH_Init( &HASHcontext );
2235                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2236                                         HASH_Update( &HASHcontext,
2237                                                 prefix->bv_val, prefix->bv_len );
2238                                 }
2239                                 HASH_Update( &HASHcontext,
2240                                         &pre, sizeof( pre ) );
2241                                 HASH_Update( &HASHcontext,
2242                                         syntax->ssyn_oid, slen );
2243                                 HASH_Update( &HASHcontext,
2244                                         mr->smr_oid, mlen );
2245                                 HASH_Update( &HASHcontext,
2246                                         &value->bv_val[j], klen );
2247                                 HASH_Final( HASHdigest, &HASHcontext );
2248
2249                                 keys[nkeys++] = ber_bvdup( &digest );
2250                         }
2251
2252                         ber_bvfree( value );
2253                 }
2254         }
2255
2256         if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final != NULL &&
2257                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2258         {
2259                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
2260 #if UTF8MATCH
2261                 value = ber_bvstr( UTF8normalize( sa->sa_final->bv_val, UTF8_CASEFOLD ) );
2262 #else
2263                 value = ber_bvdup( sa->sa_final );
2264                 ldap_pvt_str2upper( value->bv_val );
2265 #endif
2266
2267                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2268                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2269
2270                 HASH_Init( &HASHcontext );
2271                 if( prefix != NULL && prefix->bv_len > 0 ) {
2272                         HASH_Update( &HASHcontext,
2273                                 prefix->bv_val, prefix->bv_len );
2274                 }
2275                 HASH_Update( &HASHcontext,
2276                         &pre, sizeof( pre ) );
2277                 HASH_Update( &HASHcontext,
2278                         syntax->ssyn_oid, slen );
2279                 HASH_Update( &HASHcontext,
2280                         mr->smr_oid, mlen );
2281                 HASH_Update( &HASHcontext,
2282                         &value->bv_val[value->bv_len-klen], klen );
2283                 HASH_Final( HASHdigest, &HASHcontext );
2284
2285                 ber_bvfree( value );
2286                 keys[nkeys++] = ber_bvdup( &digest );
2287         }
2288
2289         if( nkeys > 0 ) {
2290                 keys[nkeys] = NULL;
2291                 *keysp = keys;
2292         } else {
2293                 ch_free( keys );
2294                 *keysp = NULL;
2295         }
2296
2297         return LDAP_SUCCESS;
2298 }
2299         
2300 static int
2301 oidValidate(
2302         Syntax *syntax,
2303         struct berval *val )
2304 {
2305         ber_len_t i;
2306
2307         if( val->bv_len == 0 ) {
2308                 /* disallow empty strings */
2309                 return LDAP_INVALID_SYNTAX;
2310         }
2311
2312         if( OID_LEADCHAR(val->bv_val[0]) ) {
2313                 int dot = 0;
2314                 for(i=1; i < val->bv_len; i++) {
2315                         if( OID_SEPARATOR( val->bv_val[i] ) ) {
2316                                 if( dot++ ) return 1;
2317                         } else if ( OID_CHAR( val->bv_val[i] ) ) {
2318                                 dot = 0;
2319                         } else {
2320                                 return LDAP_INVALID_SYNTAX;
2321                         }
2322                 }
2323
2324                 return !dot ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
2325
2326         } else if( DESC_LEADCHAR(val->bv_val[0]) ) {
2327                 for(i=1; i < val->bv_len; i++) {
2328                         if( !DESC_CHAR(val->bv_val[i] ) ) {
2329                                 return LDAP_INVALID_SYNTAX;
2330                         }
2331                 }
2332
2333                 return LDAP_SUCCESS;
2334         }
2335         
2336         return LDAP_INVALID_SYNTAX;
2337 }
2338
2339 static int
2340 integerValidate(
2341         Syntax *syntax,
2342         struct berval *val )
2343 {
2344         ber_len_t i;
2345
2346         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
2347
2348         if( val->bv_val[0] == '+' || val->bv_val[0] == '-' ) {
2349                 if( val->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
2350         } else if( !ASCII_DIGIT(val->bv_val[0]) ) {
2351                 return LDAP_INVALID_SYNTAX;
2352         }
2353
2354         for(i=1; i < val->bv_len; i++) {
2355                 if( !ASCII_DIGIT(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
2356         }
2357
2358         return LDAP_SUCCESS;
2359 }
2360
2361 static int
2362 integerNormalize(
2363         Syntax *syntax,
2364         struct berval *val,
2365         struct berval **normalized )
2366 {
2367         int negative;
2368         struct berval *newval;
2369         char *p;
2370
2371         p = val->bv_val;
2372
2373         /* save sign */
2374         negative = ( *p == '-' );
2375         if( *p == '-' || *p == '+' ) p++;
2376
2377         /* Ignore leading zeros */
2378         while ( *p == '0' ) p++;
2379
2380         newval = (struct berval *) ch_malloc( sizeof(struct berval) );
2381
2382         if( *p == '\0' ) {
2383                 newval->bv_val = ch_strdup("0");
2384                 newval->bv_len = 1;
2385                 goto done;
2386         }
2387
2388         newval->bv_val = ch_malloc( val->bv_len + 1 );
2389         newval->bv_len = 0;
2390
2391         if( negative ) {
2392                 newval->bv_val[newval->bv_len++] = '-';
2393         }
2394
2395         for( ; *p != '\0'; p++ ) {
2396                 newval->bv_val[newval->bv_len++] = *p;
2397         }
2398
2399 done:
2400         *normalized = newval;
2401         return LDAP_SUCCESS;
2402 }
2403
2404 static int
2405 countryStringValidate(
2406         Syntax *syntax,
2407         struct berval *val )
2408 {
2409         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2410
2411         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2412                 return LDAP_INVALID_SYNTAX;
2413         }
2414         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2415                 return LDAP_INVALID_SYNTAX;
2416         }
2417
2418         return LDAP_SUCCESS;
2419 }
2420
2421 static int
2422 printableStringValidate(
2423         Syntax *syntax,
2424         struct berval *val )
2425 {
2426         ber_len_t i;
2427
2428         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
2429
2430         for(i=0; i < val->bv_len; i++) {
2431                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2432                         return LDAP_INVALID_SYNTAX;
2433                 }
2434         }
2435
2436         return LDAP_SUCCESS;
2437 }
2438
2439 static int
2440 printablesStringValidate(
2441         Syntax *syntax,
2442         struct berval *val )
2443 {
2444         ber_len_t i;
2445
2446         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
2447
2448         for(i=0; i < val->bv_len; i++) {
2449                 if( !SLAP_PRINTABLES(val->bv_val[i]) ) {
2450                         return LDAP_INVALID_SYNTAX;
2451                 }
2452         }
2453
2454         return LDAP_SUCCESS;
2455 }
2456
2457 static int
2458 IA5StringValidate(
2459         Syntax *syntax,
2460         struct berval *val )
2461 {
2462         ber_len_t i;
2463
2464         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
2465
2466         for(i=0; i < val->bv_len; i++) {
2467                 if( !isascii(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
2468         }
2469
2470         return LDAP_SUCCESS;
2471 }
2472
2473 static int
2474 IA5StringNormalize(
2475         Syntax *syntax,
2476         struct berval *val,
2477         struct berval **normalized )
2478 {
2479         struct berval *newval;
2480         char *p, *q;
2481
2482         newval = ch_malloc( sizeof( struct berval ) );
2483
2484         p = val->bv_val;
2485
2486         /* Ignore initial whitespace */
2487         while ( ASCII_SPACE( *p ) ) {
2488                 p++;
2489         }
2490
2491         if( *p == '\0' ) {
2492                 ch_free( newval );
2493                 return LDAP_INVALID_SYNTAX;
2494         }
2495
2496         newval->bv_val = ch_strdup( p );
2497         p = q = newval->bv_val;
2498
2499         while ( *p ) {
2500                 if ( ASCII_SPACE( *p ) ) {
2501                         *q++ = *p++;
2502
2503                         /* Ignore the extra whitespace */
2504                         while ( ASCII_SPACE( *p ) ) {
2505                                 p++;
2506                         }
2507                 } else {
2508                         *q++ = *p++;
2509                 }
2510         }
2511
2512         assert( *newval->bv_val );
2513         assert( newval->bv_val < p );
2514         assert( q <= p );
2515
2516         /* cannot start with a space */
2517         assert( !ASCII_SPACE(*newval->bv_val) );
2518
2519         /*
2520          * If the string ended in space, backup the pointer one
2521          * position.  One is enough because the above loop collapsed
2522          * all whitespace to a single space.
2523          */
2524
2525         if ( ASCII_SPACE( q[-1] ) ) {
2526                 --q;
2527         }
2528
2529         /* cannot end with a space */
2530         assert( !ASCII_SPACE( q[-1] ) );
2531
2532         /* null terminate */
2533         *q = '\0';
2534
2535         newval->bv_len = q - newval->bv_val;
2536         *normalized = newval;
2537
2538         return LDAP_SUCCESS;
2539 }
2540
2541 static int
2542 caseExactIA5Match(
2543         int *matchp,
2544         slap_mask_t flags,
2545         Syntax *syntax,
2546         MatchingRule *mr,
2547         struct berval *value,
2548         void *assertedValue )
2549 {
2550         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
2551
2552         if( match == 0 ) {
2553                 match = strncmp( value->bv_val,
2554                         ((struct berval *) assertedValue)->bv_val,
2555                         value->bv_len );
2556         }
2557
2558         *matchp = match;
2559         return LDAP_SUCCESS;
2560 }
2561
2562 static int
2563 caseExactIA5SubstringsMatch(
2564         int *matchp,
2565         slap_mask_t flags,
2566         Syntax *syntax,
2567         MatchingRule *mr,
2568         struct berval *value,
2569         void *assertedValue )
2570 {
2571         int match = 0;
2572         SubstringsAssertion *sub = assertedValue;
2573         struct berval left = *value;
2574         int i;
2575         ber_len_t inlen=0;
2576
2577         /* Add up asserted input length */
2578         if( sub->sa_initial ) {
2579                 inlen += sub->sa_initial->bv_len;
2580         }
2581         if( sub->sa_any ) {
2582                 for(i=0; sub->sa_any[i] != NULL; i++) {
2583                         inlen += sub->sa_any[i]->bv_len;
2584                 }
2585         }
2586         if( sub->sa_final ) {
2587                 inlen += sub->sa_final->bv_len;
2588         }
2589
2590         if( sub->sa_initial ) {
2591                 if( inlen > left.bv_len ) {
2592                         match = 1;
2593                         goto done;
2594                 }
2595
2596                 match = strncmp( sub->sa_initial->bv_val, left.bv_val,
2597                         sub->sa_initial->bv_len );
2598
2599                 if( match != 0 ) {
2600                         goto done;
2601                 }
2602
2603                 left.bv_val += sub->sa_initial->bv_len;
2604                 left.bv_len -= sub->sa_initial->bv_len;
2605                 inlen -= sub->sa_initial->bv_len;
2606         }
2607
2608         if( sub->sa_final ) {
2609                 if( inlen > left.bv_len ) {
2610                         match = 1;
2611                         goto done;
2612                 }
2613
2614                 match = strncmp( sub->sa_final->bv_val,
2615                         &left.bv_val[left.bv_len - sub->sa_final->bv_len],
2616                         sub->sa_final->bv_len );
2617
2618                 if( match != 0 ) {
2619                         goto done;
2620                 }
2621
2622                 left.bv_len -= sub->sa_final->bv_len;
2623                 inlen -= sub->sa_final->bv_len;
2624         }
2625
2626         if( sub->sa_any ) {
2627                 for(i=0; sub->sa_any[i]; i++) {
2628                         ber_len_t idx;
2629                         char *p;
2630
2631 retry:
2632                         if( inlen > left.bv_len ) {
2633                                 /* not enough length */
2634                                 match = 1;
2635                                 goto done;
2636                         }
2637
2638                         if( sub->sa_any[i]->bv_len == 0 ) {
2639                                 continue;
2640                         }
2641
2642                         p = strchr( left.bv_val, *sub->sa_any[i]->bv_val );
2643
2644                         if( p == NULL ) {
2645                                 match = 1;
2646                                 goto done;
2647                         }
2648
2649                         idx = p - left.bv_val;
2650                         assert( idx < left.bv_len );
2651
2652                         if( idx >= left.bv_len ) {
2653                                 /* this shouldn't happen */
2654                                 return LDAP_OTHER;
2655                         }
2656
2657                         left.bv_val = p;
2658                         left.bv_len -= idx;
2659
2660                         if( sub->sa_any[i]->bv_len > left.bv_len ) {
2661                                 /* not enough left */
2662                                 match = 1;
2663                                 goto done;
2664                         }
2665
2666                         match = strncmp( left.bv_val,
2667                                 sub->sa_any[i]->bv_val,
2668                                 sub->sa_any[i]->bv_len );
2669
2670                         if( match != 0 ) {
2671                                 left.bv_val++;
2672                                 left.bv_len--;
2673                                 goto retry;
2674                         }
2675
2676                         left.bv_val += sub->sa_any[i]->bv_len;
2677                         left.bv_len -= sub->sa_any[i]->bv_len;
2678                         inlen -= sub->sa_any[i]->bv_len;
2679                 }
2680         }
2681
2682 done:
2683         *matchp = match;
2684         return LDAP_SUCCESS;
2685 }
2686
2687 /* Index generation function */
2688 int caseExactIA5Indexer(
2689         slap_mask_t use,
2690         slap_mask_t flags,
2691         Syntax *syntax,
2692         MatchingRule *mr,
2693         struct berval *prefix,
2694         struct berval **values,
2695         struct berval ***keysp )
2696 {
2697         int i;
2698         size_t slen, mlen;
2699         struct berval **keys;
2700         HASH_CONTEXT   HASHcontext;
2701         unsigned char   HASHdigest[HASH_BYTES];
2702         struct berval digest;
2703         digest.bv_val = HASHdigest;
2704         digest.bv_len = sizeof(HASHdigest);
2705
2706         /* we should have at least one value at this point */
2707         assert( values != NULL && values[0] != NULL );
2708
2709         for( i=0; values[i] != NULL; i++ ) {
2710                 /* just count them */
2711         }
2712
2713         keys = ch_malloc( sizeof( struct berval * ) * (i+1) );
2714
2715         slen = strlen( syntax->ssyn_oid );
2716         mlen = strlen( mr->smr_oid );
2717
2718         for( i=0; values[i] != NULL; i++ ) {
2719                 struct berval *value = values[i];
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[i] = ber_bvdup( &digest );
2735         }
2736
2737         keys[i] = NULL;
2738         *keysp = keys;
2739         return LDAP_SUCCESS;
2740 }
2741
2742 /* Index generation function */
2743 int caseExactIA5Filter(
2744         slap_mask_t use,
2745         slap_mask_t flags,
2746         Syntax *syntax,
2747         MatchingRule *mr,
2748         struct berval *prefix,
2749         void * assertValue,
2750         struct berval ***keysp )
2751 {
2752         size_t slen, mlen;
2753         struct berval **keys;
2754         HASH_CONTEXT   HASHcontext;
2755         unsigned char   HASHdigest[HASH_BYTES];
2756         struct berval *value;
2757         struct berval digest;
2758         digest.bv_val = HASHdigest;
2759         digest.bv_len = sizeof(HASHdigest);
2760
2761         slen = strlen( syntax->ssyn_oid );
2762         mlen = strlen( mr->smr_oid );
2763
2764         value = (struct berval *) assertValue;
2765
2766         keys = ch_malloc( sizeof( struct berval * ) * 2 );
2767
2768         HASH_Init( &HASHcontext );
2769         if( prefix != NULL && prefix->bv_len > 0 ) {
2770                 HASH_Update( &HASHcontext,
2771                         prefix->bv_val, prefix->bv_len );
2772         }
2773         HASH_Update( &HASHcontext,
2774                 syntax->ssyn_oid, slen );
2775         HASH_Update( &HASHcontext,
2776                 mr->smr_oid, mlen );
2777         HASH_Update( &HASHcontext,
2778                 value->bv_val, value->bv_len );
2779         HASH_Final( HASHdigest, &HASHcontext );
2780
2781         keys[0] = ber_bvdup( &digest );
2782         keys[1] = NULL;
2783
2784         *keysp = keys;
2785         return LDAP_SUCCESS;
2786 }
2787
2788 /* Substrings Index generation function */
2789 int caseExactIA5SubstringsIndexer(
2790         slap_mask_t use,
2791         slap_mask_t flags,
2792         Syntax *syntax,
2793         MatchingRule *mr,
2794         struct berval *prefix,
2795         struct berval **values,
2796         struct berval ***keysp )
2797 {
2798         ber_len_t i, nkeys;
2799         size_t slen, mlen;
2800         struct berval **keys;
2801         HASH_CONTEXT   HASHcontext;
2802         unsigned char   HASHdigest[HASH_BYTES];
2803         struct berval digest;
2804         digest.bv_val = HASHdigest;
2805         digest.bv_len = sizeof(HASHdigest);
2806
2807         /* we should have at least one value at this point */
2808         assert( values != NULL && values[0] != NULL );
2809
2810         nkeys=0;
2811         for( i=0; values[i] != NULL; i++ ) {
2812                 /* count number of indices to generate */
2813                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
2814                         continue;
2815                 }
2816
2817                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
2818                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2819                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
2820                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
2821                         } else {
2822                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
2823                         }
2824                 }
2825
2826                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
2827                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2828                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
2829                         }
2830                 }
2831
2832                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
2833                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2834                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
2835                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
2836                         } else {
2837                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
2838                         }
2839                 }
2840         }
2841
2842         if( nkeys == 0 ) {
2843                 /* no keys to generate */
2844                 *keysp = NULL;
2845                 return LDAP_SUCCESS;
2846         }
2847
2848         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
2849
2850         slen = strlen( syntax->ssyn_oid );
2851         mlen = strlen( mr->smr_oid );
2852
2853         nkeys=0;
2854         for( i=0; values[i] != NULL; i++ ) {
2855                 ber_len_t j,max;
2856                 struct berval *value;
2857
2858                 value = values[i];
2859                 if( value->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
2860
2861                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
2862                         ( value->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
2863                 {
2864                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
2865                         max = value->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
2866
2867                         for( j=0; j<max; j++ ) {
2868                                 HASH_Init( &HASHcontext );
2869                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2870                                         HASH_Update( &HASHcontext,
2871                                                 prefix->bv_val, prefix->bv_len );
2872                                 }
2873
2874                                 HASH_Update( &HASHcontext,
2875                                         &pre, sizeof( pre ) );
2876                                 HASH_Update( &HASHcontext,
2877                                         syntax->ssyn_oid, slen );
2878                                 HASH_Update( &HASHcontext,
2879                                         mr->smr_oid, mlen );
2880                                 HASH_Update( &HASHcontext,
2881                                         &value->bv_val[j],
2882                                         SLAP_INDEX_SUBSTR_MAXLEN );
2883                                 HASH_Final( HASHdigest, &HASHcontext );
2884
2885                                 keys[nkeys++] = ber_bvdup( &digest );
2886                         }
2887                 }
2888
2889                 max = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2890                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2891
2892                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
2893                         char pre;
2894
2895                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
2896                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
2897                                 HASH_Init( &HASHcontext );
2898                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2899                                         HASH_Update( &HASHcontext,
2900                                                 prefix->bv_val, prefix->bv_len );
2901                                 }
2902                                 HASH_Update( &HASHcontext,
2903                                         &pre, sizeof( pre ) );
2904                                 HASH_Update( &HASHcontext,
2905                                         syntax->ssyn_oid, slen );
2906                                 HASH_Update( &HASHcontext,
2907                                         mr->smr_oid, mlen );
2908                                 HASH_Update( &HASHcontext,
2909                                         value->bv_val, j );
2910                                 HASH_Final( HASHdigest, &HASHcontext );
2911
2912                                 keys[nkeys++] = ber_bvdup( &digest );
2913                         }
2914
2915                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
2916                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
2917                                 HASH_Init( &HASHcontext );
2918                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2919                                         HASH_Update( &HASHcontext,
2920                                                 prefix->bv_val, prefix->bv_len );
2921                                 }
2922                                 HASH_Update( &HASHcontext,
2923                                         &pre, sizeof( pre ) );
2924                                 HASH_Update( &HASHcontext,
2925                                         syntax->ssyn_oid, slen );
2926                                 HASH_Update( &HASHcontext,
2927                                         mr->smr_oid, mlen );
2928                                 HASH_Update( &HASHcontext,
2929                                         &value->bv_val[value->bv_len-j], j );
2930                                 HASH_Final( HASHdigest, &HASHcontext );
2931
2932                                 keys[nkeys++] = ber_bvdup( &digest );
2933                         }
2934
2935                 }
2936         }
2937
2938         if( nkeys > 0 ) {
2939                 keys[nkeys] = NULL;
2940                 *keysp = keys;
2941         } else {
2942                 ch_free( keys );
2943                 *keysp = NULL;
2944         }
2945
2946         return LDAP_SUCCESS;
2947 }
2948
2949 int caseExactIA5SubstringsFilter(
2950         slap_mask_t use,
2951         slap_mask_t flags,
2952         Syntax *syntax,
2953         MatchingRule *mr,
2954         struct berval *prefix,
2955         void * assertValue,
2956         struct berval ***keysp )
2957 {
2958         SubstringsAssertion *sa = assertValue;
2959         char pre;
2960         ber_len_t nkeys = 0;
2961         size_t slen, mlen, klen;
2962         struct berval **keys;
2963         HASH_CONTEXT   HASHcontext;
2964         unsigned char   HASHdigest[HASH_BYTES];
2965         struct berval *value;
2966         struct berval digest;
2967
2968         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial != NULL &&
2969                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2970         {
2971                 nkeys++;
2972         }
2973
2974         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
2975                 ber_len_t i;
2976                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
2977                         if( sa->sa_any[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2978                                 /* don't bother accounting for stepping */
2979                                 nkeys += sa->sa_any[i]->bv_len -
2980                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
2981                         }
2982                 }
2983         }
2984
2985         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final != NULL &&
2986                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2987         {
2988                 nkeys++;
2989         }
2990
2991         if( nkeys == 0 ) {
2992                 *keysp = NULL;
2993                 return LDAP_SUCCESS;
2994         }
2995
2996         digest.bv_val = HASHdigest;
2997         digest.bv_len = sizeof(HASHdigest);
2998
2999         slen = strlen( syntax->ssyn_oid );
3000         mlen = strlen( mr->smr_oid );
3001
3002         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
3003         nkeys = 0;
3004
3005         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial != NULL &&
3006                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3007         {
3008                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
3009                 value = sa->sa_initial;
3010
3011                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
3012                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
3013
3014                 HASH_Init( &HASHcontext );
3015                 if( prefix != NULL && prefix->bv_len > 0 ) {
3016                         HASH_Update( &HASHcontext,
3017                                 prefix->bv_val, prefix->bv_len );
3018                 }
3019                 HASH_Update( &HASHcontext,
3020                         &pre, sizeof( pre ) );
3021                 HASH_Update( &HASHcontext,
3022                         syntax->ssyn_oid, slen );
3023                 HASH_Update( &HASHcontext,
3024                         mr->smr_oid, mlen );
3025                 HASH_Update( &HASHcontext,
3026                         value->bv_val, klen );
3027                 HASH_Final( HASHdigest, &HASHcontext );
3028
3029                 keys[nkeys++] = ber_bvdup( &digest );
3030         }
3031
3032         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
3033                 ber_len_t i, j;
3034                 pre = SLAP_INDEX_SUBSTR_PREFIX;
3035                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
3036
3037                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
3038                         if( sa->sa_any[i]->bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
3039                                 continue;
3040                         }
3041
3042                         value = sa->sa_any[i];
3043
3044                         for(j=0;
3045                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
3046                                 j += SLAP_INDEX_SUBSTR_STEP )
3047                         {
3048                                 HASH_Init( &HASHcontext );
3049                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3050                                         HASH_Update( &HASHcontext,
3051                                                 prefix->bv_val, prefix->bv_len );
3052                                 }
3053                                 HASH_Update( &HASHcontext,
3054                                         &pre, sizeof( pre ) );
3055                                 HASH_Update( &HASHcontext,
3056                                         syntax->ssyn_oid, slen );
3057                                 HASH_Update( &HASHcontext,
3058                                         mr->smr_oid, mlen );
3059                                 HASH_Update( &HASHcontext,
3060                                         &value->bv_val[j], klen ); 
3061                                 HASH_Final( HASHdigest, &HASHcontext );
3062
3063                                 keys[nkeys++] = ber_bvdup( &digest );
3064                         }
3065                 }
3066         }
3067
3068         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final != NULL &&
3069                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3070         {
3071                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
3072                 value = sa->sa_final;
3073
3074                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
3075                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
3076
3077                 HASH_Init( &HASHcontext );
3078                 if( prefix != NULL && prefix->bv_len > 0 ) {
3079                         HASH_Update( &HASHcontext,
3080                                 prefix->bv_val, prefix->bv_len );
3081                 }
3082                 HASH_Update( &HASHcontext,
3083                         &pre, sizeof( pre ) );
3084                 HASH_Update( &HASHcontext,
3085                         syntax->ssyn_oid, slen );
3086                 HASH_Update( &HASHcontext,
3087                         mr->smr_oid, mlen );
3088                 HASH_Update( &HASHcontext,
3089                         &value->bv_val[value->bv_len-klen], klen );
3090                 HASH_Final( HASHdigest, &HASHcontext );
3091
3092                 keys[nkeys++] = ber_bvdup( &digest );
3093         }
3094
3095         if( nkeys > 0 ) {
3096                 keys[nkeys] = NULL;
3097                 *keysp = keys;
3098         } else {
3099                 ch_free( keys );
3100                 *keysp = NULL;
3101         }
3102
3103         return LDAP_SUCCESS;
3104 }
3105         
3106 static int
3107 caseIgnoreIA5Match(
3108         int *matchp,
3109         slap_mask_t flags,
3110         Syntax *syntax,
3111         MatchingRule *mr,
3112         struct berval *value,
3113         void *assertedValue )
3114 {
3115         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
3116
3117         if( match == 0 && value->bv_len ) {
3118                 match = strncasecmp( value->bv_val,
3119                         ((struct berval *) assertedValue)->bv_val,
3120                         value->bv_len );
3121         }
3122
3123         *matchp = match;
3124         return LDAP_SUCCESS;
3125 }
3126
3127 static int
3128 caseIgnoreIA5SubstringsMatch(
3129         int *matchp,
3130         slap_mask_t flags,
3131         Syntax *syntax,
3132         MatchingRule *mr,
3133         struct berval *value,
3134         void *assertedValue )
3135 {
3136         int match = 0;
3137         SubstringsAssertion *sub = assertedValue;
3138         struct berval left = *value;
3139         int i;
3140         ber_len_t inlen=0;
3141
3142         /* Add up asserted input length */
3143         if( sub->sa_initial ) {
3144                 inlen += sub->sa_initial->bv_len;
3145         }
3146         if( sub->sa_any ) {
3147                 for(i=0; sub->sa_any[i] != NULL; i++) {
3148                         inlen += sub->sa_any[i]->bv_len;
3149                 }
3150         }
3151         if( sub->sa_final ) {
3152                 inlen += sub->sa_final->bv_len;
3153         }
3154
3155         if( sub->sa_initial ) {
3156                 if( inlen > left.bv_len ) {
3157                         match = 1;
3158                         goto done;
3159                 }
3160
3161                 match = strncasecmp( sub->sa_initial->bv_val, left.bv_val,
3162                         sub->sa_initial->bv_len );
3163
3164                 if( match != 0 ) {
3165                         goto done;
3166                 }
3167
3168                 left.bv_val += sub->sa_initial->bv_len;
3169                 left.bv_len -= sub->sa_initial->bv_len;
3170                 inlen -= sub->sa_initial->bv_len;
3171         }
3172
3173         if( sub->sa_final ) {
3174                 if( inlen > left.bv_len ) {
3175                         match = 1;
3176                         goto done;
3177                 }
3178
3179                 match = strncasecmp( sub->sa_final->bv_val,
3180                         &left.bv_val[left.bv_len - sub->sa_final->bv_len],
3181                         sub->sa_final->bv_len );
3182
3183                 if( match != 0 ) {
3184                         goto done;
3185                 }
3186
3187                 left.bv_len -= sub->sa_final->bv_len;
3188                 inlen -= sub->sa_final->bv_len;
3189         }
3190
3191         if( sub->sa_any ) {
3192                 for(i=0; sub->sa_any[i]; i++) {
3193                         ber_len_t idx;
3194                         char *p;
3195
3196 retry:
3197                         if( inlen > left.bv_len ) {
3198                                 /* not enough length */
3199                                 match = 1;
3200                                 goto done;
3201                         }
3202
3203                         if( sub->sa_any[i]->bv_len == 0 ) {
3204                                 continue;
3205                         }
3206
3207                         p = strcasechr( left.bv_val, *sub->sa_any[i]->bv_val );
3208
3209                         if( p == NULL ) {
3210                                 match = 1;
3211                                 goto done;
3212                         }
3213
3214                         idx = p - left.bv_val;
3215                         assert( idx < left.bv_len );
3216
3217                         if( idx >= left.bv_len ) {
3218                                 /* this shouldn't happen */
3219                                 return LDAP_OTHER;
3220                         }
3221
3222                         left.bv_val = p;
3223                         left.bv_len -= idx;
3224
3225                         if( sub->sa_any[i]->bv_len > left.bv_len ) {
3226                                 /* not enough left */
3227                                 match = 1;
3228                                 goto done;
3229                         }
3230
3231                         match = strncasecmp( left.bv_val,
3232                                 sub->sa_any[i]->bv_val,
3233                                 sub->sa_any[i]->bv_len );
3234
3235                         if( match != 0 ) {
3236                                 left.bv_val++;
3237                                 left.bv_len--;
3238
3239                                 goto retry;
3240                         }
3241
3242                         left.bv_val += sub->sa_any[i]->bv_len;
3243                         left.bv_len -= sub->sa_any[i]->bv_len;
3244                         inlen -= sub->sa_any[i]->bv_len;
3245                 }
3246         }
3247
3248 done:
3249         *matchp = match;
3250         return LDAP_SUCCESS;
3251 }
3252
3253 /* Index generation function */
3254 int caseIgnoreIA5Indexer(
3255         slap_mask_t use,
3256         slap_mask_t flags,
3257         Syntax *syntax,
3258         MatchingRule *mr,
3259         struct berval *prefix,
3260         struct berval **values,
3261         struct berval ***keysp )
3262 {
3263         int i;
3264         size_t slen, mlen;
3265         struct berval **keys;
3266         HASH_CONTEXT   HASHcontext;
3267         unsigned char   HASHdigest[HASH_BYTES];
3268         struct berval digest;
3269         digest.bv_val = HASHdigest;
3270         digest.bv_len = sizeof(HASHdigest);
3271
3272         /* we should have at least one value at this point */
3273         assert( values != NULL && values[0] != NULL );
3274
3275         for( i=0; values[i] != NULL; i++ ) {
3276                 /* just count them */
3277         }
3278
3279         keys = ch_malloc( sizeof( struct berval * ) * (i+1) );
3280
3281         slen = strlen( syntax->ssyn_oid );
3282         mlen = strlen( mr->smr_oid );
3283
3284         for( i=0; values[i] != NULL; i++ ) {
3285                 struct berval *value = ber_bvdup( values[i] );
3286                 ldap_pvt_str2upper( value->bv_val );
3287
3288                 HASH_Init( &HASHcontext );
3289                 if( prefix != NULL && prefix->bv_len > 0 ) {
3290                         HASH_Update( &HASHcontext,
3291                                 prefix->bv_val, prefix->bv_len );
3292                 }
3293                 HASH_Update( &HASHcontext,
3294                         syntax->ssyn_oid, slen );
3295                 HASH_Update( &HASHcontext,
3296                         mr->smr_oid, mlen );
3297                 HASH_Update( &HASHcontext,
3298                         value->bv_val, value->bv_len );
3299                 HASH_Final( HASHdigest, &HASHcontext );
3300
3301                 ber_bvfree( value );
3302
3303                 keys[i] = ber_bvdup( &digest );
3304         }
3305
3306         keys[i] = NULL;
3307         *keysp = keys;
3308         return LDAP_SUCCESS;
3309 }
3310
3311 /* Index generation function */
3312 int caseIgnoreIA5Filter(
3313         slap_mask_t use,
3314         slap_mask_t flags,
3315         Syntax *syntax,
3316         MatchingRule *mr,
3317         struct berval *prefix,
3318         void * assertValue,
3319         struct berval ***keysp )
3320 {
3321         size_t slen, mlen;
3322         struct berval **keys;
3323         HASH_CONTEXT   HASHcontext;
3324         unsigned char   HASHdigest[HASH_BYTES];
3325         struct berval *value;
3326         struct berval digest;
3327         digest.bv_val = HASHdigest;
3328         digest.bv_len = sizeof(HASHdigest);
3329
3330         slen = strlen( syntax->ssyn_oid );
3331         mlen = strlen( mr->smr_oid );
3332
3333         value = ber_bvdup( (struct berval *) assertValue );
3334         ldap_pvt_str2upper( value->bv_val );
3335
3336         keys = ch_malloc( sizeof( struct berval * ) * 2 );
3337
3338         HASH_Init( &HASHcontext );
3339         if( prefix != NULL && prefix->bv_len > 0 ) {
3340                 HASH_Update( &HASHcontext,
3341                         prefix->bv_val, prefix->bv_len );
3342         }
3343         HASH_Update( &HASHcontext,
3344                 syntax->ssyn_oid, slen );
3345         HASH_Update( &HASHcontext,
3346                 mr->smr_oid, mlen );
3347         HASH_Update( &HASHcontext,
3348                 value->bv_val, value->bv_len );
3349         HASH_Final( HASHdigest, &HASHcontext );
3350
3351         keys[0] = ber_bvdup( &digest );
3352         keys[1] = NULL;
3353
3354         ber_bvfree( value );
3355
3356         *keysp = keys;
3357
3358         return LDAP_SUCCESS;
3359 }
3360
3361 /* Substrings Index generation function */
3362 int caseIgnoreIA5SubstringsIndexer(
3363         slap_mask_t use,
3364         slap_mask_t flags,
3365         Syntax *syntax,
3366         MatchingRule *mr,
3367         struct berval *prefix,
3368         struct berval **values,
3369         struct berval ***keysp )
3370 {
3371         ber_len_t i, nkeys;
3372         size_t slen, mlen;
3373         struct berval **keys;
3374         HASH_CONTEXT   HASHcontext;
3375         unsigned char   HASHdigest[HASH_BYTES];
3376         struct berval digest;
3377         digest.bv_val = HASHdigest;
3378         digest.bv_len = sizeof(HASHdigest);
3379
3380         /* we should have at least one value at this point */
3381         assert( values != NULL && values[0] != NULL );
3382
3383         nkeys=0;
3384         for( i=0; values[i] != NULL; i++ ) {
3385                 /* count number of indices to generate */
3386                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
3387                         continue;
3388                 }
3389
3390                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
3391                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3392                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
3393                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
3394                         } else {
3395                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
3396                         }
3397                 }
3398
3399                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
3400                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3401                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
3402                         }
3403                 }
3404
3405                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
3406                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3407                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
3408                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
3409                         } else {
3410                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
3411                         }
3412                 }
3413         }
3414
3415         if( nkeys == 0 ) {
3416                 /* no keys to generate */
3417                 *keysp = NULL;
3418                 return LDAP_SUCCESS;
3419         }
3420
3421         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
3422
3423         slen = strlen( syntax->ssyn_oid );
3424         mlen = strlen( mr->smr_oid );
3425
3426         nkeys=0;
3427         for( i=0; values[i] != NULL; i++ ) {
3428                 int j,max;
3429                 struct berval *value;
3430
3431                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
3432
3433                 value = ber_bvdup( values[i] );
3434                 ldap_pvt_str2upper( value->bv_val );
3435
3436                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
3437                         ( value->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
3438                 {
3439                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
3440                         max = value->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
3441
3442                         for( j=0; j<max; j++ ) {
3443                                 HASH_Init( &HASHcontext );
3444                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3445                                         HASH_Update( &HASHcontext,
3446                                                 prefix->bv_val, prefix->bv_len );
3447                                 }
3448
3449                                 HASH_Update( &HASHcontext,
3450                                         &pre, sizeof( pre ) );
3451                                 HASH_Update( &HASHcontext,
3452                                         syntax->ssyn_oid, slen );
3453                                 HASH_Update( &HASHcontext,
3454                                         mr->smr_oid, mlen );
3455                                 HASH_Update( &HASHcontext,
3456                                         &value->bv_val[j],
3457                                         SLAP_INDEX_SUBSTR_MAXLEN );
3458                                 HASH_Final( HASHdigest, &HASHcontext );
3459
3460                                 keys[nkeys++] = ber_bvdup( &digest );
3461                         }
3462                 }
3463
3464                 max = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
3465                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
3466
3467                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
3468                         char pre;
3469
3470                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
3471                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
3472                                 HASH_Init( &HASHcontext );
3473                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3474                                         HASH_Update( &HASHcontext,
3475                                                 prefix->bv_val, prefix->bv_len );
3476                                 }
3477                                 HASH_Update( &HASHcontext,
3478                                         &pre, sizeof( pre ) );
3479                                 HASH_Update( &HASHcontext,
3480                                         syntax->ssyn_oid, slen );
3481                                 HASH_Update( &HASHcontext,
3482                                         mr->smr_oid, mlen );
3483                                 HASH_Update( &HASHcontext,
3484                                         value->bv_val, j );
3485                                 HASH_Final( HASHdigest, &HASHcontext );
3486
3487                                 keys[nkeys++] = ber_bvdup( &digest );
3488                         }
3489
3490                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
3491                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
3492                                 HASH_Init( &HASHcontext );
3493                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3494                                         HASH_Update( &HASHcontext,
3495                                                 prefix->bv_val, prefix->bv_len );
3496                                 }
3497                                 HASH_Update( &HASHcontext,
3498                                         &pre, sizeof( pre ) );
3499                                 HASH_Update( &HASHcontext,
3500                                         syntax->ssyn_oid, slen );
3501                                 HASH_Update( &HASHcontext,
3502                                         mr->smr_oid, mlen );
3503                                 HASH_Update( &HASHcontext,
3504                                         &value->bv_val[value->bv_len-j], j );
3505                                 HASH_Final( HASHdigest, &HASHcontext );
3506
3507                                 keys[nkeys++] = ber_bvdup( &digest );
3508                         }
3509
3510                 }
3511
3512                 ber_bvfree( value );
3513         }
3514
3515         if( nkeys > 0 ) {
3516                 keys[nkeys] = NULL;
3517                 *keysp = keys;
3518         } else {
3519                 ch_free( keys );
3520                 *keysp = NULL;
3521         }
3522
3523         return LDAP_SUCCESS;
3524 }
3525
3526 int caseIgnoreIA5SubstringsFilter(
3527         slap_mask_t use,
3528         slap_mask_t flags,
3529         Syntax *syntax,
3530         MatchingRule *mr,
3531         struct berval *prefix,
3532         void * assertValue,
3533         struct berval ***keysp )
3534 {
3535         SubstringsAssertion *sa = assertValue;
3536         char pre;
3537         ber_len_t nkeys = 0;
3538         size_t slen, mlen, klen;
3539         struct berval **keys;
3540         HASH_CONTEXT   HASHcontext;
3541         unsigned char   HASHdigest[HASH_BYTES];
3542         struct berval *value;
3543         struct berval digest;
3544
3545         if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial != NULL &&
3546                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3547         {
3548                 nkeys++;
3549         }
3550
3551         if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
3552                 ber_len_t i;
3553                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
3554                         if( sa->sa_any[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3555                                 /* don't bother accounting for stepping */
3556                                 nkeys += sa->sa_any[i]->bv_len -
3557                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
3558                         }
3559                 }
3560         }
3561
3562         if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final != NULL &&
3563                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3564         {
3565                 nkeys++;
3566         }
3567
3568         if( nkeys == 0 ) {
3569                 *keysp = NULL;
3570                 return LDAP_SUCCESS;
3571         }
3572
3573         digest.bv_val = HASHdigest;
3574         digest.bv_len = sizeof(HASHdigest);
3575
3576         slen = strlen( syntax->ssyn_oid );
3577         mlen = strlen( mr->smr_oid );
3578
3579         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
3580         nkeys = 0;
3581
3582         if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial != NULL &&
3583                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3584         {
3585                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
3586                 value = ber_bvdup( sa->sa_initial );
3587                 ldap_pvt_str2upper( value->bv_val );
3588
3589                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
3590                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
3591
3592                 HASH_Init( &HASHcontext );
3593                 if( prefix != NULL && prefix->bv_len > 0 ) {
3594                         HASH_Update( &HASHcontext,
3595                                 prefix->bv_val, prefix->bv_len );
3596                 }
3597                 HASH_Update( &HASHcontext,
3598                         &pre, sizeof( pre ) );
3599                 HASH_Update( &HASHcontext,
3600                         syntax->ssyn_oid, slen );
3601                 HASH_Update( &HASHcontext,
3602                         mr->smr_oid, mlen );
3603                 HASH_Update( &HASHcontext,
3604                         value->bv_val, klen );
3605                 HASH_Final( HASHdigest, &HASHcontext );
3606
3607                 ber_bvfree( value );
3608                 keys[nkeys++] = ber_bvdup( &digest );
3609         }
3610
3611         if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
3612                 ber_len_t i, j;
3613                 pre = SLAP_INDEX_SUBSTR_PREFIX;
3614                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
3615
3616                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
3617                         if( sa->sa_any[i]->bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
3618                                 continue;
3619                         }
3620
3621                         value = ber_bvdup( sa->sa_any[i] );
3622                         ldap_pvt_str2upper( value->bv_val );
3623
3624                         for(j=0;
3625                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
3626                                 j += SLAP_INDEX_SUBSTR_STEP )
3627                         {
3628                                 HASH_Init( &HASHcontext );
3629                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3630                                         HASH_Update( &HASHcontext,
3631                                                 prefix->bv_val, prefix->bv_len );
3632                                 }
3633                                 HASH_Update( &HASHcontext,
3634                                         &pre, sizeof( pre ) );
3635                                 HASH_Update( &HASHcontext,
3636                                         syntax->ssyn_oid, slen );
3637                                 HASH_Update( &HASHcontext,
3638                                         mr->smr_oid, mlen );
3639                                 HASH_Update( &HASHcontext,
3640                                         &value->bv_val[j], klen );
3641                                 HASH_Final( HASHdigest, &HASHcontext );
3642
3643                                 keys[nkeys++] = ber_bvdup( &digest );
3644                         }
3645
3646                         ber_bvfree( value );
3647                 }
3648         }
3649
3650         if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final != NULL &&
3651                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3652         {
3653                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
3654                 value = ber_bvdup( sa->sa_final );
3655                 ldap_pvt_str2upper( value->bv_val );
3656
3657                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
3658                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
3659
3660                 HASH_Init( &HASHcontext );
3661                 if( prefix != NULL && prefix->bv_len > 0 ) {
3662                         HASH_Update( &HASHcontext,
3663                                 prefix->bv_val, prefix->bv_len );
3664                 }
3665                 HASH_Update( &HASHcontext,
3666                         &pre, sizeof( pre ) );
3667                 HASH_Update( &HASHcontext,
3668                         syntax->ssyn_oid, slen );
3669                 HASH_Update( &HASHcontext,
3670                         mr->smr_oid, mlen );
3671                 HASH_Update( &HASHcontext,
3672                         &value->bv_val[value->bv_len-klen], klen );
3673                 HASH_Final( HASHdigest, &HASHcontext );
3674
3675                 ber_bvfree( value );
3676                 keys[nkeys++] = ber_bvdup( &digest );
3677         }
3678
3679         if( nkeys > 0 ) {
3680                 keys[nkeys] = NULL;
3681                 *keysp = keys;
3682         } else {
3683                 ch_free( keys );
3684                 *keysp = NULL;
3685         }
3686
3687         return LDAP_SUCCESS;
3688 }
3689         
3690 static int
3691 numericStringValidate(
3692         Syntax *syntax,
3693         struct berval *in )
3694 {
3695         ber_len_t i;
3696
3697         for(i=0; i < in->bv_len; i++) {
3698                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
3699                         return LDAP_INVALID_SYNTAX;
3700                 }
3701         }
3702
3703         return LDAP_SUCCESS;
3704 }
3705
3706 static int
3707 numericStringNormalize(
3708         Syntax *syntax,
3709         struct berval *val,
3710         struct berval **normalized )
3711 {
3712         /* removal all spaces */
3713         struct berval *newval;
3714         char *p, *q;
3715
3716         newval = ch_malloc( sizeof( struct berval ) );
3717         newval->bv_val = ch_malloc( val->bv_len + 1 );
3718
3719         p = val->bv_val;
3720         q = newval->bv_val;
3721
3722         while ( *p ) {
3723                 if ( ASCII_SPACE( *p ) ) {
3724                         /* Ignore whitespace */
3725                         p++;
3726                 } else {
3727                         *q++ = *p++;
3728                 }
3729         }
3730
3731         assert( newval->bv_val <= p );
3732         assert( q <= p );
3733
3734         /* null terminate */
3735         *q = '\0';
3736
3737         newval->bv_len = q - newval->bv_val;
3738         *normalized = newval;
3739
3740         return LDAP_SUCCESS;
3741 }
3742
3743 static int
3744 objectIdentifierFirstComponentMatch(
3745         int *matchp,
3746         slap_mask_t flags,
3747         Syntax *syntax,
3748         MatchingRule *mr,
3749         struct berval *value,
3750         void *assertedValue )
3751 {
3752         int rc = LDAP_SUCCESS;
3753         int match;
3754         struct berval *asserted = (struct berval *) assertedValue;
3755         ber_len_t i;
3756         struct berval oid;
3757
3758         if( value->bv_len == 0 || value->bv_val[0] != '(' /*')'*/ ) {
3759                 return LDAP_INVALID_SYNTAX;
3760         }
3761
3762         /* trim leading white space */
3763         for( i=1; ASCII_SPACE(value->bv_val[i]) && i < value->bv_len; i++ ) {
3764                 /* empty */
3765         }
3766
3767         /* grab next word */
3768         oid.bv_val = &value->bv_val[i];
3769         oid.bv_len = value->bv_len - i;
3770         for( i=1; ASCII_SPACE(value->bv_val[i]) && i < oid.bv_len; i++ ) {
3771                 /* empty */
3772         }
3773         oid.bv_len = i;
3774
3775         /* insert attributeTypes, objectclass check here */
3776         if( OID_LEADCHAR(asserted->bv_val[0]) ) {
3777                 rc = objectIdentifierMatch( &match, flags, syntax, mr, &oid, asserted );
3778
3779         } else {
3780                 char *stored = ch_malloc( oid.bv_len + 1 );
3781                 AC_MEMCPY( stored, oid.bv_val, oid.bv_len );
3782                 stored[oid.bv_len] = '\0';
3783
3784                 if ( !strcmp( syntax->ssyn_oid, SLAP_SYNTAX_MATCHINGRULES_OID ) ) {
3785                         MatchingRule *asserted_mr = mr_find( asserted->bv_val );
3786                         MatchingRule *stored_mr = mr_find( stored );
3787
3788                         if( asserted_mr == NULL ) {
3789                                 rc = SLAPD_COMPARE_UNDEFINED;
3790                         } else {
3791                                 match = asserted_mr != stored_mr;
3792                         }
3793
3794                 } else if ( !strcmp( syntax->ssyn_oid,
3795                         SLAP_SYNTAX_ATTRIBUTETYPES_OID ) )
3796                 {
3797                         AttributeType *asserted_at = at_find( asserted->bv_val );
3798                         AttributeType *stored_at = at_find( stored );
3799
3800                         if( asserted_at == NULL ) {
3801                                 rc = SLAPD_COMPARE_UNDEFINED;
3802                         } else {
3803                                 match = asserted_at != stored_at;
3804                         }
3805
3806                 } else if ( !strcmp( syntax->ssyn_oid,
3807                         SLAP_SYNTAX_OBJECTCLASSES_OID ) )
3808                 {
3809                         ObjectClass *asserted_oc = oc_find( asserted->bv_val );
3810                         ObjectClass *stored_oc = oc_find( stored );
3811
3812                         if( asserted_oc == NULL ) {
3813                                 rc = SLAPD_COMPARE_UNDEFINED;
3814                         } else {
3815                                 match = asserted_oc != stored_oc;
3816                         }
3817                 }
3818
3819                 ch_free( stored );
3820         }
3821
3822 #ifdef NEW_LOGGING
3823         LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
3824                    "objectIdentifierFirstComponentMatch: %d\n    %s\n    %s\n",
3825                    match, value->bv_val, asserted->bv_val ));
3826 #else
3827         Debug( LDAP_DEBUG_ARGS, "objectIdentifierFirstComponentMatch "
3828                 "%d\n\t\"%s\"\n\t\"%s\"\n",
3829             match, value->bv_val, asserted->bv_val );
3830 #endif
3831
3832
3833         if( rc == LDAP_SUCCESS ) *matchp = match;
3834         return rc;
3835 }
3836
3837 static int
3838 check_time_syntax (struct berval *val,
3839         int start,
3840         int *parts)
3841 {
3842         static int ceiling[9] = { 99, 99, 11, 30, 23, 59, 59, 12, 59 };
3843         static int mdays[2][12] = {
3844                 /* non-leap years */
3845                 { 30, 27, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 },
3846                 /* leap years */
3847                 { 30, 28, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 }
3848         };
3849         char *p, *e;
3850         int part, c, tzoffset, leapyear = 0 ;
3851
3852         if( val->bv_len == 0 ) {
3853                 return LDAP_INVALID_SYNTAX;
3854         }
3855
3856         p = (char *)val->bv_val;
3857         e = p + val->bv_len;
3858
3859         /* Ignore initial whitespace */
3860         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
3861                 p++;
3862         }
3863
3864         if (e - p < 13 - (2 * start)) {
3865                 return LDAP_INVALID_SYNTAX;
3866         }
3867
3868         for (part = 0; part < 9; part++) {
3869                 parts[part] = 0;
3870         }
3871
3872         for (part = start; part < 7; part++) {
3873                 c = *p;
3874                 if ((part == 6) && (c == 'Z' || c == '+' || c == '-')) {
3875                         part++;
3876                         break;
3877                 }
3878                 p++;
3879                 c -= '0';
3880                 if (p == e) {
3881                         return LDAP_INVALID_SYNTAX;
3882                 }
3883                 if (c < 0 || c > 9) {
3884                         return LDAP_INVALID_SYNTAX;
3885                 }
3886                 parts[part] = c;
3887
3888                 c = *p++ - '0';
3889                 if (p == e) {
3890                         return LDAP_INVALID_SYNTAX;
3891                 }
3892                 if (c < 0 || c > 9) {
3893                         return LDAP_INVALID_SYNTAX;
3894                 }
3895                 parts[part] *= 10;
3896                 parts[part] += c;
3897
3898                 if (part == 2 || part == 3) {
3899                         parts[part]--;
3900                 }
3901                 if (parts[part] < 0) {
3902                         return LDAP_INVALID_SYNTAX;
3903                 }
3904                 if (parts[part] > ceiling[part]) {
3905                         return LDAP_INVALID_SYNTAX;
3906                 }
3907         }
3908
3909         /* leapyear check for the Gregorian calendar (year>1581) */
3910         if (((parts[1] % 4 == 0) && (parts[1] != 0)) ||
3911                 ((parts[0] % 4 == 0) && (parts[1] == 0)))
3912         {
3913                 leapyear = 1;
3914         }
3915
3916         if (parts[3] > mdays[leapyear][parts[2]]) {
3917                 return LDAP_INVALID_SYNTAX;
3918         }
3919         
3920         c = *p++;
3921         if (c == 'Z') {
3922                 tzoffset = 0; /* UTC */
3923         } else if (c != '+' && c != '-') {
3924                 return LDAP_INVALID_SYNTAX;
3925         } else {
3926                 if (c == '-') {
3927                         tzoffset = -1;
3928                 } else /* c == '+' */ {
3929                         tzoffset = 1;
3930                 }
3931
3932                 if (p > e - 4) {
3933                         return LDAP_INVALID_SYNTAX;
3934                 }
3935
3936                 for (part = 7; part < 9; part++) {
3937                         c = *p++ - '0';
3938                         if (c < 0 || c > 9) {
3939                                 return LDAP_INVALID_SYNTAX;
3940                         }
3941                         parts[part] = c;
3942
3943                         c = *p++ - '0';
3944                         if (c < 0 || c > 9) {
3945                                 return LDAP_INVALID_SYNTAX;
3946                         }
3947                         parts[part] *= 10;
3948                         parts[part] += c;
3949                         if (parts[part] < 0 || parts[part] > ceiling[part]) {
3950                                 return LDAP_INVALID_SYNTAX;
3951                         }
3952                 }
3953         }
3954
3955         /* Ignore trailing whitespace */
3956         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
3957                 p++;
3958         }
3959         if (p != e) {
3960                 return LDAP_INVALID_SYNTAX;
3961         }
3962
3963         switch ( tzoffset ) {
3964         case -1: /* negativ offset to UTC, ie west of Greenwich  */
3965                 parts[4] += parts[7];
3966                 parts[5] += parts[8];
3967                 for (part = 6; --part > 0; ) { /* offset is just hhmm, no seconds */
3968                         if (part != 3) {
3969                                 c = ceiling[part];
3970                         } else {
3971                                 c = mdays[leapyear][parts[2]];
3972                         }
3973                         if (parts[part] > c) {
3974                                 parts[part] -= c + 1;
3975                                 parts[part - 1]++;
3976                         }
3977                 }
3978                 break;
3979         case 1: /* positive offset to UTC, ie east of Greenwich */
3980                 parts[4] -= parts[7];
3981                 parts[5] -= parts[8];
3982                 for (part = 6; --part > 0; ) {
3983                         if (part != 3) {
3984                                 c = ceiling[part];
3985                         } else {
3986                                 /* first arg to % needs to be non negativ */
3987                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
3988                         }
3989                         if (parts[part] < 0) {
3990                                 parts[part] += c + 1;
3991                                 parts[part - 1]--;
3992                         }
3993                 }
3994                 break;
3995         case 0: /* already UTC */
3996                 break;
3997         }
3998
3999         return LDAP_SUCCESS;
4000 }
4001
4002 static int
4003 utcTimeNormalize(
4004         Syntax *syntax,
4005         struct berval *val,
4006         struct berval **normalized )
4007 {
4008         struct berval *out;
4009         int parts[9], rc;
4010
4011         rc = check_time_syntax(val, 1, parts);
4012         if (rc != LDAP_SUCCESS) {
4013                 return rc;
4014         }
4015
4016         *normalized = NULL;
4017         out = ch_malloc( sizeof(struct berval) );
4018         if( out == NULL ) {
4019                 return LBER_ERROR_MEMORY;
4020         }
4021
4022         out->bv_val = ch_malloc( 14 );
4023         if ( out->bv_val == NULL ) {
4024                 ch_free( out );
4025                 return LBER_ERROR_MEMORY;
4026         }
4027
4028         sprintf( out->bv_val, "%02ld%02ld%02ld%02ld%02ld%02ldZ",
4029                 parts[1], parts[2] + 1, parts[3] + 1,
4030                 parts[4], parts[5], parts[6] );
4031         out->bv_len = 13;
4032         *normalized = out;
4033
4034         return LDAP_SUCCESS;
4035 }
4036
4037 static int
4038 utcTimeValidate(
4039         Syntax *syntax,
4040         struct berval *in )
4041 {
4042         int parts[9];
4043
4044         return check_time_syntax(in, 1, parts);
4045 }
4046
4047 static int
4048 generalizedTimeValidate(
4049         Syntax *syntax,
4050         struct berval *in )
4051 {
4052         int parts[9];
4053
4054         return check_time_syntax(in, 0, parts);
4055 }
4056
4057 static int
4058 generalizedTimeNormalize(
4059         Syntax *syntax,
4060         struct berval *val,
4061         struct berval **normalized )
4062 {
4063         struct berval *out;
4064         int parts[9], rc;
4065
4066         rc = check_time_syntax(val, 0, parts);
4067         if (rc != LDAP_SUCCESS) {
4068                 return rc;
4069         }
4070
4071         *normalized = NULL;
4072         out = ch_malloc( sizeof(struct berval) );
4073         if( out == NULL ) {
4074                 return LBER_ERROR_MEMORY;
4075         }
4076
4077         out->bv_val = ch_malloc( 16 );
4078         if ( out->bv_val == NULL ) {
4079                 ch_free( out );
4080                 return LBER_ERROR_MEMORY;
4081         }
4082
4083         sprintf( out->bv_val, "%02ld%02ld%02ld%02ld%02ld%02ld%02ldZ",
4084                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
4085                 parts[4], parts[5], parts[6] );
4086         out->bv_len = 15;
4087         *normalized = out;
4088
4089         return LDAP_SUCCESS;
4090 }
4091
4092 static int
4093 nisNetgroupTripleValidate(
4094         Syntax *syntax,
4095         struct berval *val )
4096 {
4097         char *p, *e;
4098         int commas = 0;
4099
4100         if ( val->bv_len == 0 ) {
4101                 return LDAP_INVALID_SYNTAX;
4102         }
4103
4104         p = (char *)val->bv_val;
4105         e = p + val->bv_len;
4106
4107 #if 0
4108         /* syntax does not allow leading white space */
4109         /* Ignore initial whitespace */
4110         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
4111                 p++;
4112         }
4113 #endif
4114
4115         if ( *p != '(' /*')'*/ ) {
4116                 return LDAP_INVALID_SYNTAX;
4117         }
4118
4119         for ( p++; ( p < e ) && ( *p != ')' ); p++ ) {
4120                 if ( *p == ',' ) {
4121                         commas++;
4122                         if ( commas > 2 ) {
4123                                 return LDAP_INVALID_SYNTAX;
4124                         }
4125
4126                 } else if ( !ATTR_CHAR( *p ) ) {
4127                         return LDAP_INVALID_SYNTAX;
4128                 }
4129         }
4130
4131         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4132                 return LDAP_INVALID_SYNTAX;
4133         }
4134
4135         p++;
4136
4137 #if 0
4138         /* syntax does not allow trailing white space */
4139         /* Ignore trailing whitespace */
4140         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
4141                 p++;
4142         }
4143 #endif
4144
4145         if (p != e) {
4146                 return LDAP_INVALID_SYNTAX;
4147         }
4148
4149         return LDAP_SUCCESS;
4150 }
4151
4152 static int
4153 bootParameterValidate(
4154         Syntax *syntax,
4155         struct berval *val )
4156 {
4157         char *p, *e;
4158
4159         if ( val->bv_len == 0 ) {
4160                 return LDAP_INVALID_SYNTAX;
4161         }
4162
4163         p = (char *)val->bv_val;
4164         e = p + val->bv_len;
4165
4166         /* key */
4167         for (; ( p < e ) && ( *p != '=' ); p++ ) {
4168                 if ( !ATTR_CHAR( *p ) ) {
4169                         return LDAP_INVALID_SYNTAX;
4170                 }
4171         }
4172
4173         if ( *p != '=' ) {
4174                 return LDAP_INVALID_SYNTAX;
4175         }
4176
4177         /* server */
4178         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4179                 if ( !ATTR_CHAR( *p ) ) {
4180                         return LDAP_INVALID_SYNTAX;
4181                 }
4182         }
4183
4184         if ( *p != ':' ) {
4185                 return LDAP_INVALID_SYNTAX;
4186         }
4187
4188         /* path */
4189         for ( p++; p < e; p++ ) {
4190                 if ( !ATTR_CHAR( *p ) ) {
4191                         return LDAP_INVALID_SYNTAX;
4192                 }
4193         }
4194
4195         return LDAP_SUCCESS;
4196 }
4197
4198 struct syntax_defs_rec {
4199         char *sd_desc;
4200         int sd_flags;
4201         slap_syntax_validate_func *sd_validate;
4202         slap_syntax_transform_func *sd_normalize;
4203         slap_syntax_transform_func *sd_pretty;
4204 #ifdef SLAPD_BINARY_CONVERSION
4205         slap_syntax_transform_func *sd_ber2str;
4206         slap_syntax_transform_func *sd_str2ber;
4207 #endif
4208 };
4209
4210 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4211 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4212
4213 struct syntax_defs_rec syntax_defs[] = {
4214         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' " X_BINARY X_NOT_H_R ")",
4215                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4216         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4217                 0, NULL, NULL, NULL},
4218         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4219                 0, NULL, NULL, NULL},
4220         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' " X_NOT_H_R ")",
4221                 SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
4222         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' " X_NOT_H_R ")",
4223                 SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4224         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4225                 0, bitStringValidate, NULL, NULL },
4226         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4227                 0, booleanValidate, NULL, NULL},
4228         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4229                 X_BINARY X_NOT_H_R ")",
4230                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4231         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4232                 X_BINARY X_NOT_H_R ")",
4233                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4234         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4235                 X_BINARY X_NOT_H_R ")",
4236                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4237         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4238                 0, countryStringValidate, IA5StringNormalize, NULL},
4239         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4240                 0, dnValidate, dnNormalize, dnPretty},
4241         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4242                 0, NULL, NULL, NULL},
4243         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4244                 0, NULL, NULL, NULL},
4245         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4246                 0, UTF8StringValidate, UTF8StringNormalize, NULL},
4247         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4248                 0, NULL, NULL, NULL},
4249         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4250                 0, NULL, NULL, NULL},
4251         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4252                 0, NULL, NULL, NULL},
4253         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4254                 0, NULL, NULL, NULL},
4255         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4256                 0, NULL, NULL, NULL},
4257         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4258                 0, printablesStringValidate, IA5StringNormalize, NULL},
4259         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4260                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4261         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4262                 0, generalizedTimeValidate, generalizedTimeNormalize, NULL},
4263         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4264                 0, NULL, NULL, NULL},
4265         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4266                 0, IA5StringValidate, IA5StringNormalize, NULL},
4267         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4268                 0, integerValidate, integerNormalize, integerPretty},
4269         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4270                 SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
4271         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4272                 0, NULL, NULL, NULL},
4273         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4274                 0, NULL, NULL, NULL},
4275         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4276                 0, NULL, NULL, NULL},
4277         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4278                 0, NULL, NULL, NULL},
4279         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4280                 0, NULL, NULL, NULL},
4281         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4282                 0, nameUIDValidate, nameUIDNormalize, NULL},
4283         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4284                 0, NULL, NULL, NULL},
4285         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4286                 0, numericStringValidate, numericStringNormalize, NULL},
4287         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4288                 0, NULL, NULL, NULL},
4289         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4290                 0, oidValidate, NULL, NULL},
4291         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4292                 0, IA5StringValidate, IA5StringNormalize, NULL},
4293         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4294                 0, blobValidate, NULL, NULL},
4295         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4296                 0, UTF8StringValidate, UTF8StringNormalize, NULL},
4297         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4298                 0, NULL, NULL, NULL},
4299         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4300                 0, NULL, NULL, NULL},
4301         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4302                 0, printableStringValidate, IA5StringNormalize, NULL},
4303         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4304                 X_BINARY X_NOT_H_R ")",
4305                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4306         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4307                 0, printableStringValidate, IA5StringNormalize, NULL},
4308         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4309                 0, NULL, NULL, NULL},
4310         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4311                 0, printableStringValidate, IA5StringNormalize, NULL},
4312         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4313                 0, utcTimeValidate, utcTimeNormalize, NULL},
4314         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4315                 0, NULL, NULL, NULL},
4316         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4317                 0, NULL, NULL, NULL},
4318         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4319                 0, NULL, NULL, NULL},
4320         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4321                 0, NULL, NULL, NULL},
4322         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4323                 0, NULL, NULL, NULL},
4324
4325         /* RFC 2307 NIS Syntaxes */
4326         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4327                 0, nisNetgroupTripleValidate, NULL, NULL},
4328         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4329                 0, bootParameterValidate, NULL, NULL},
4330
4331         /* OpenLDAP Experimental Syntaxes */
4332         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
4333                 0, UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
4334                 NULL, NULL},
4335         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4336                 0, NULL, NULL, NULL},
4337
4338         /* OpenLDAP Void Syntax */
4339         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4340                 SLAP_SYNTAX_HIDE, inValidate, NULL, NULL},
4341         {NULL, 0, NULL, NULL, NULL}
4342 };
4343
4344 struct mrule_defs_rec {
4345         char *                                          mrd_desc;
4346         slap_mask_t                                     mrd_usage;
4347         slap_mr_convert_func *          mrd_convert;
4348         slap_mr_normalize_func *        mrd_normalize;
4349         slap_mr_match_func *            mrd_match;
4350         slap_mr_indexer_func *          mrd_indexer;
4351         slap_mr_filter_func *           mrd_filter;
4352
4353         char *                                          mrd_associated;
4354 };
4355
4356 /*
4357  * Other matching rules in X.520 that we do not use (yet):
4358  *
4359  * 2.5.13.9             numericStringOrderingMatch
4360  * 2.5.13.15    integerOrderingMatch
4361  * 2.5.13.18    octetStringOrderingMatch
4362  * 2.5.13.19    octetStringSubstringsMatch
4363  * 2.5.13.25    uTCTimeMatch
4364  * 2.5.13.26    uTCTimeOrderingMatch
4365  * 2.5.13.31    directoryStringFirstComponentMatch
4366  * 2.5.13.32    wordMatch
4367  * 2.5.13.33    keywordMatch
4368  * 2.5.13.34    certificateExactMatch
4369  * 2.5.13.35    certificateMatch
4370  * 2.5.13.36    certificatePairExactMatch
4371  * 2.5.13.37    certificatePairMatch
4372  * 2.5.13.38    certificateListExactMatch
4373  * 2.5.13.39    certificateListMatch
4374  * 2.5.13.40    algorithmIdentifierMatch
4375  * 2.5.13.41    storedPrefixMatch
4376  * 2.5.13.42    attributeCertificateMatch
4377  * 2.5.13.43    readerAndKeyIDMatch
4378  * 2.5.13.44    attributeIntegrityMatch
4379  */
4380
4381 struct mrule_defs_rec mrule_defs[] = {
4382         /*
4383          * EQUALITY matching rules must be listed after associated APPROX
4384          * matching rules.  So, we list all APPROX matching rules first.
4385          */
4386         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4387                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4388                 SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT,
4389                 NULL, NULL,
4390                 directoryStringApproxMatch,
4391                 directoryStringApproxIndexer, 
4392                 directoryStringApproxFilter,
4393                 NULL},
4394
4395         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4396                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4397                 SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT,
4398                 NULL, NULL,
4399                 IA5StringApproxMatch,
4400                 IA5StringApproxIndexer, 
4401                 IA5StringApproxFilter,
4402                 NULL},
4403
4404         /*
4405          * Other matching rules
4406          */
4407         
4408         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4409                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4410                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4411                 NULL, NULL,
4412                 objectIdentifierMatch, caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
4413                 NULL},
4414
4415         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4416                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4417                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4418                 NULL, NULL,
4419                 dnMatch, dnIndexer, dnFilter,
4420                 NULL},
4421
4422         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4423                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4424                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4425                 NULL, NULL,
4426                 caseIgnoreMatch, caseIgnoreIndexer, caseIgnoreFilter,
4427                 directoryStringApproxMatchOID },
4428
4429         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4430                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4431                 SLAP_MR_ORDERING,
4432                 NULL, NULL,
4433                 caseIgnoreOrderingMatch, NULL, NULL,
4434                 NULL},
4435
4436         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4437                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4438                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4439                 NULL, NULL,
4440                 caseIgnoreSubstringsMatch,
4441                 caseIgnoreSubstringsIndexer,
4442                 caseIgnoreSubstringsFilter,
4443                 NULL},
4444
4445         {"( 2.5.13.5 NAME 'caseExactMatch' "
4446                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4447                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4448                 NULL, NULL,
4449                 caseExactMatch, caseExactIndexer, caseExactFilter,
4450                 directoryStringApproxMatchOID },
4451
4452         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4453                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4454                 SLAP_MR_ORDERING,
4455                 NULL, NULL,
4456                 caseExactOrderingMatch, NULL, NULL,
4457                 NULL},
4458
4459         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4460                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4461                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4462                 NULL, NULL,
4463                 caseExactSubstringsMatch,
4464                 caseExactSubstringsIndexer,
4465                 caseExactSubstringsFilter,
4466                 NULL},
4467
4468         {"( 2.5.13.8 NAME 'numericStringMatch' "
4469                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4470                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4471                 NULL, NULL,
4472                 caseIgnoreIA5Match,
4473                 caseIgnoreIA5Indexer,
4474                 caseIgnoreIA5Filter,
4475                 NULL},
4476
4477         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4478                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4479                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4480                 NULL, NULL,
4481                 caseIgnoreIA5SubstringsMatch,
4482                 caseIgnoreIA5SubstringsIndexer,
4483                 caseIgnoreIA5SubstringsFilter,
4484                 NULL},
4485
4486         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4487                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4488                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4489                 NULL, NULL,
4490                 caseIgnoreListMatch, NULL, NULL,
4491                 NULL},
4492
4493         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4494                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4495                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4496                 NULL, NULL,
4497                 caseIgnoreListSubstringsMatch, NULL, NULL,
4498                 NULL},
4499
4500         {"( 2.5.13.13 NAME 'booleanMatch' "
4501                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4502                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4503                 NULL, NULL,
4504                 booleanMatch, NULL, NULL,
4505                 NULL},
4506
4507         {"( 2.5.13.14 NAME 'integerMatch' "
4508                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4509                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4510                 NULL, NULL,
4511                 integerMatch, integerIndexer, integerFilter,
4512                 NULL},
4513
4514         {"( 2.5.13.16 NAME 'bitStringMatch' "
4515                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4516                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4517                 NULL, NULL,
4518                 bitStringMatch, NULL, NULL,
4519                 NULL},
4520
4521         {"( 2.5.13.17 NAME 'octetStringMatch' "
4522                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4523                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4524                 NULL, NULL,
4525                 octetStringMatch, octetStringIndexer, octetStringFilter,
4526                 NULL},
4527
4528         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
4529                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
4530                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4531                 NULL, NULL,
4532                 telephoneNumberMatch,
4533                 telephoneNumberIndexer,
4534                 telephoneNumberFilter,
4535                 NULL},
4536
4537         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
4538                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4539                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4540                 NULL, NULL,
4541                 telephoneNumberSubstringsMatch,
4542                 telephoneNumberSubstringsIndexer,
4543                 telephoneNumberSubstringsFilter,
4544                 NULL},
4545
4546         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
4547                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
4548                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4549                 NULL, NULL,
4550                 NULL, NULL, NULL,
4551                 NULL},
4552
4553         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
4554                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
4555                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4556                 NULL, NULL,
4557                 uniqueMemberMatch, NULL, NULL,
4558                 NULL},
4559
4560         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
4561                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
4562                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4563                 NULL, NULL,
4564                 protocolInformationMatch, NULL, NULL,
4565                 NULL},
4566
4567         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
4568                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4569                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4570                 NULL, NULL,
4571                 generalizedTimeMatch, NULL, NULL,
4572                 NULL},
4573
4574         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
4575                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4576                 SLAP_MR_ORDERING,
4577                 NULL, NULL,
4578                 generalizedTimeOrderingMatch, NULL, NULL,
4579                 NULL},
4580
4581         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
4582                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4583                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4584                 NULL, NULL,
4585                 integerFirstComponentMatch, NULL, NULL,
4586                 NULL},
4587
4588         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
4589                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4590                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4591                 NULL, NULL,
4592                 objectIdentifierFirstComponentMatch, NULL, NULL,
4593                 NULL},
4594
4595         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
4596                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4597                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4598                 NULL, NULL,
4599                 caseExactIA5Match, caseExactIA5Indexer, caseExactIA5Filter,
4600                 IA5StringApproxMatchOID },
4601
4602         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
4603                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4604                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4605                 NULL, NULL,
4606                 caseIgnoreIA5Match, caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
4607                 IA5StringApproxMatchOID },
4608
4609         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
4610                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4611                 SLAP_MR_SUBSTR,
4612                 NULL, NULL,
4613                 caseIgnoreIA5SubstringsMatch,
4614                 caseIgnoreIA5SubstringsIndexer,
4615                 caseIgnoreIA5SubstringsFilter,
4616                 NULL},
4617
4618         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
4619                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4620                 SLAP_MR_SUBSTR,
4621                 NULL, NULL,
4622                 caseExactIA5SubstringsMatch,
4623                 caseExactIA5SubstringsIndexer,
4624                 caseExactIA5SubstringsFilter,
4625                 NULL},
4626
4627         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
4628                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4629                 SLAP_MR_EQUALITY,
4630                 NULL, NULL,
4631                 authPasswordMatch, NULL, NULL,
4632                 NULL},
4633
4634         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
4635                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
4636                 SLAP_MR_EQUALITY,
4637                 NULL, NULL,
4638                 OpenLDAPaciMatch, NULL, NULL,
4639                 NULL},
4640
4641         {NULL, SLAP_MR_NONE, NULL, NULL, NULL, NULL}
4642 };
4643
4644 int
4645 schema_init( void )
4646 {
4647         int             res;
4648         int             i;
4649
4650         /* we should only be called once (from main) */
4651         assert( schema_init_done == 0 );
4652
4653         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
4654                 res = register_syntax( syntax_defs[i].sd_desc,
4655                     syntax_defs[i].sd_flags,
4656                     syntax_defs[i].sd_validate,
4657                     syntax_defs[i].sd_normalize,
4658                         syntax_defs[i].sd_pretty
4659 #ifdef SLAPD_BINARY_CONVERSION
4660                         ,
4661                     syntax_defs[i].sd_ber2str,
4662                         syntax_defs[i].sd_str2ber
4663 #endif
4664                 );
4665
4666                 if ( res ) {
4667                         fprintf( stderr, "schema_init: Error registering syntax %s\n",
4668                                  syntax_defs[i].sd_desc );
4669                         return LDAP_OTHER;
4670                 }
4671         }
4672
4673         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
4674                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE ) {
4675                         fprintf( stderr,
4676                                 "schema_init: Ingoring unusable matching rule %s\n",
4677                                  mrule_defs[i].mrd_desc );
4678                         continue;
4679                 }
4680
4681                 res = register_matching_rule(
4682                         mrule_defs[i].mrd_desc,
4683                         mrule_defs[i].mrd_usage,
4684                         mrule_defs[i].mrd_convert,
4685                         mrule_defs[i].mrd_normalize,
4686                     mrule_defs[i].mrd_match,
4687                         mrule_defs[i].mrd_indexer,
4688                         mrule_defs[i].mrd_filter,
4689                         mrule_defs[i].mrd_associated );
4690
4691                 if ( res ) {
4692                         fprintf( stderr,
4693                                 "schema_init: Error registering matching rule %s\n",
4694                                  mrule_defs[i].mrd_desc );
4695                         return LDAP_OTHER;
4696                 }
4697         }
4698         schema_init_done = 1;
4699         return LDAP_SUCCESS;
4700 }