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