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