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