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