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