]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
fix up UTF8MATCH
[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         ber_bvfree( value );
1221
1222         *keysp = keys;
1223         return LDAP_SUCCESS;
1224 }
1225
1226 /* Substrings Index generation function */
1227 int caseExactSubstringsIndexer(
1228         slap_mask_t use,
1229         slap_mask_t flags,
1230         Syntax *syntax,
1231         MatchingRule *mr,
1232         struct berval *prefix,
1233         struct berval **values,
1234         struct berval ***keysp )
1235 {
1236         ber_len_t i, nkeys;
1237         size_t slen, mlen;
1238         struct berval **keys;
1239         struct berval **nvalues;
1240
1241         HASH_CONTEXT   HASHcontext;
1242         unsigned char   HASHdigest[HASH_BYTES];
1243         struct berval digest;
1244         digest.bv_val = HASHdigest;
1245         digest.bv_len = sizeof(HASHdigest);
1246
1247         /* we should have at least one value at this point */
1248         assert( values != NULL && values[0] != NULL );
1249
1250         nkeys=0;
1251
1252         /* create normalized copy of values */
1253         for( i=0; values[i] != NULL; i++ ) {
1254                 /* empty */
1255         }
1256         nvalues = ch_malloc( sizeof( struct berval * ) * (i+1) );
1257         for( i=0; values[i] != NULL; i++ ) {
1258                 nvalues[i] = ber_bvstr( UTF8normalize( values[i]->bv_val,
1259                         UTF8_NOCASEFOLD ) );
1260         }
1261         nvalues[i] = NULL;
1262         values = nvalues;
1263
1264         for( i=0; values[i] != NULL; i++ ) {
1265                 /* count number of indices to generate */
1266                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
1267                         continue;
1268                 }
1269
1270                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1271                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1272                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
1273                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
1274                         } else {
1275                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
1276                         }
1277                 }
1278
1279                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
1280                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1281                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
1282                         }
1283                 }
1284
1285                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1286                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1287                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
1288                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
1289                         } else {
1290                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
1291                         }
1292                 }
1293         }
1294
1295         if( nkeys == 0 ) {
1296                 /* no keys to generate */
1297                 *keysp = NULL;
1298                 return LDAP_SUCCESS;
1299         }
1300
1301         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
1302
1303         slen = strlen( syntax->ssyn_oid );
1304         mlen = strlen( mr->smr_oid );
1305
1306         nkeys=0;
1307         for( i=0; values[i] != NULL; i++ ) {
1308                 ber_len_t j,max;
1309                 struct berval *value;
1310
1311                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
1312
1313                 value = values[i];
1314
1315                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
1316                         ( value->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
1317                 {
1318                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
1319                         max = value->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
1320
1321                         for( j=0; j<max; j++ ) {
1322                                 HASH_Init( &HASHcontext );
1323                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1324                                         HASH_Update( &HASHcontext,
1325                                                 prefix->bv_val, prefix->bv_len );
1326                                 }
1327
1328                                 HASH_Update( &HASHcontext,
1329                                         &pre, sizeof( pre ) );
1330                                 HASH_Update( &HASHcontext,
1331                                         syntax->ssyn_oid, slen );
1332                                 HASH_Update( &HASHcontext,
1333                                         mr->smr_oid, mlen );
1334                                 HASH_Update( &HASHcontext,
1335                                         &value->bv_val[j],
1336                                         SLAP_INDEX_SUBSTR_MAXLEN );
1337                                 HASH_Final( HASHdigest, &HASHcontext );
1338
1339                                 keys[nkeys++] = ber_bvdup( &digest );
1340                         }
1341                 }
1342
1343                 max = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
1344                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
1345
1346                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
1347                         char pre;
1348
1349                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1350                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1351                                 HASH_Init( &HASHcontext );
1352                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1353                                         HASH_Update( &HASHcontext,
1354                                                 prefix->bv_val, prefix->bv_len );
1355                                 }
1356                                 HASH_Update( &HASHcontext,
1357                                         &pre, sizeof( pre ) );
1358                                 HASH_Update( &HASHcontext,
1359                                         syntax->ssyn_oid, slen );
1360                                 HASH_Update( &HASHcontext,
1361                                         mr->smr_oid, mlen );
1362                                 HASH_Update( &HASHcontext,
1363                                         value->bv_val, j );
1364                                 HASH_Final( HASHdigest, &HASHcontext );
1365
1366                                 keys[nkeys++] = ber_bvdup( &digest );
1367                         }
1368
1369                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1370                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1371                                 HASH_Init( &HASHcontext );
1372                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1373                                         HASH_Update( &HASHcontext,
1374                                                 prefix->bv_val, prefix->bv_len );
1375                                 }
1376                                 HASH_Update( &HASHcontext,
1377                                         &pre, sizeof( pre ) );
1378                                 HASH_Update( &HASHcontext,
1379                                         syntax->ssyn_oid, slen );
1380                                 HASH_Update( &HASHcontext,
1381                                         mr->smr_oid, mlen );
1382                                 HASH_Update( &HASHcontext,
1383                                         &value->bv_val[value->bv_len-j], j );
1384                                 HASH_Final( HASHdigest, &HASHcontext );
1385
1386                                 keys[nkeys++] = ber_bvdup( &digest );
1387                         }
1388
1389                 }
1390
1391         }
1392
1393         if( nkeys > 0 ) {
1394                 keys[nkeys] = NULL;
1395                 *keysp = keys;
1396         } else {
1397                 ch_free( keys );
1398                 *keysp = NULL;
1399         }
1400
1401         ber_bvecfree( nvalues );
1402
1403         return LDAP_SUCCESS;
1404 }
1405
1406 int caseExactSubstringsFilter(
1407         slap_mask_t use,
1408         slap_mask_t flags,
1409         Syntax *syntax,
1410         MatchingRule *mr,
1411         struct berval *prefix,
1412         void * assertValue,
1413         struct berval ***keysp )
1414 {
1415         SubstringsAssertion *sa;
1416         char pre;
1417         ber_len_t nkeys = 0;
1418         size_t slen, mlen, klen;
1419         struct berval **keys;
1420         HASH_CONTEXT   HASHcontext;
1421         unsigned char   HASHdigest[HASH_BYTES];
1422         struct berval *value;
1423         struct berval digest;
1424
1425         sa = UTF8SubstringsassertionNormalize( assertValue, UTF8_NOCASEFOLD );
1426         if( sa == NULL ) {
1427                 *keysp = NULL;
1428                 return LDAP_SUCCESS;
1429         }
1430
1431         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial != NULL &&
1432                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1433         {
1434                 nkeys++;
1435         }
1436
1437         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1438                 ber_len_t i;
1439                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
1440                         if( sa->sa_any[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1441                                 /* don't bother accounting for stepping */
1442                                 nkeys += sa->sa_any[i]->bv_len -
1443                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
1444                         }
1445                 }
1446         }
1447
1448         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final != NULL &&
1449                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1450         {
1451                 nkeys++;
1452         }
1453
1454         if( nkeys == 0 ) {
1455                 *keysp = NULL;
1456                 return LDAP_SUCCESS;
1457         }
1458
1459         digest.bv_val = HASHdigest;
1460         digest.bv_len = sizeof(HASHdigest);
1461
1462         slen = strlen( syntax->ssyn_oid );
1463         mlen = strlen( mr->smr_oid );
1464
1465         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
1466         nkeys = 0;
1467
1468         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial != NULL &&
1469                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1470         {
1471                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1472                 value = sa->sa_initial;
1473
1474                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
1475                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
1476
1477                 HASH_Init( &HASHcontext );
1478                 if( prefix != NULL && prefix->bv_len > 0 ) {
1479                         HASH_Update( &HASHcontext,
1480                                 prefix->bv_val, prefix->bv_len );
1481                 }
1482                 HASH_Update( &HASHcontext,
1483                         &pre, sizeof( pre ) );
1484                 HASH_Update( &HASHcontext,
1485                         syntax->ssyn_oid, slen );
1486                 HASH_Update( &HASHcontext,
1487                         mr->smr_oid, mlen );
1488                 HASH_Update( &HASHcontext,
1489                         value->bv_val, klen );
1490                 HASH_Final( HASHdigest, &HASHcontext );
1491
1492                 keys[nkeys++] = ber_bvdup( &digest );
1493         }
1494
1495         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1496                 ber_len_t i, j;
1497                 pre = SLAP_INDEX_SUBSTR_PREFIX;
1498                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
1499
1500                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
1501                         if( sa->sa_any[i]->bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
1502                                 continue;
1503                         }
1504
1505                         value = sa->sa_any[i];
1506
1507                         for(j=0;
1508                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
1509                                 j += SLAP_INDEX_SUBSTR_STEP )
1510                         {
1511                                 HASH_Init( &HASHcontext );
1512                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1513                                         HASH_Update( &HASHcontext,
1514                                                 prefix->bv_val, prefix->bv_len );
1515                                 }
1516                                 HASH_Update( &HASHcontext,
1517                                         &pre, sizeof( pre ) );
1518                                 HASH_Update( &HASHcontext,
1519                                         syntax->ssyn_oid, slen );
1520                                 HASH_Update( &HASHcontext,
1521                                         mr->smr_oid, mlen );
1522                                 HASH_Update( &HASHcontext,
1523                                         &value->bv_val[j], klen ); 
1524                                 HASH_Final( HASHdigest, &HASHcontext );
1525
1526                                 keys[nkeys++] = ber_bvdup( &digest );
1527                         }
1528
1529                 }
1530         }
1531
1532         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final != NULL &&
1533                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1534         {
1535                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1536                 value = sa->sa_final;
1537
1538                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
1539                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
1540
1541                 HASH_Init( &HASHcontext );
1542                 if( prefix != NULL && prefix->bv_len > 0 ) {
1543                         HASH_Update( &HASHcontext,
1544                                 prefix->bv_val, prefix->bv_len );
1545                 }
1546                 HASH_Update( &HASHcontext,
1547                         &pre, sizeof( pre ) );
1548                 HASH_Update( &HASHcontext,
1549                         syntax->ssyn_oid, slen );
1550                 HASH_Update( &HASHcontext,
1551                         mr->smr_oid, mlen );
1552                 HASH_Update( &HASHcontext,
1553                         &value->bv_val[value->bv_len-klen], klen );
1554                 HASH_Final( HASHdigest, &HASHcontext );
1555
1556                 keys[nkeys++] = ber_bvdup( &digest );
1557         }
1558
1559         if( nkeys > 0 ) {
1560                 keys[nkeys] = NULL;
1561                 *keysp = keys;
1562         } else {
1563                 ch_free( keys );
1564                 *keysp = NULL;
1565         }
1566         ch_free( sa->sa_final );
1567         ber_bvecfree( sa->sa_any );
1568         ch_free( sa->sa_initial );
1569         ch_free( sa );
1570
1571         return LDAP_SUCCESS;
1572 }
1573         
1574 static int
1575 caseIgnoreMatch(
1576         int *matchp,
1577         slap_mask_t flags,
1578         Syntax *syntax,
1579         MatchingRule *mr,
1580         struct berval *value,
1581         void *assertedValue )
1582 {
1583         *matchp = UTF8normcmp( value->bv_val,
1584                 ((struct berval *) assertedValue)->bv_val,
1585                 UTF8_CASEFOLD );
1586         return LDAP_SUCCESS;
1587 }
1588
1589 static int
1590 caseIgnoreSubstringsMatch(
1591         int *matchp,
1592         slap_mask_t flags,
1593         Syntax *syntax,
1594         MatchingRule *mr,
1595         struct berval *value,
1596         void *assertedValue )
1597 {
1598         int match = 0;
1599         SubstringsAssertion *sub;
1600         struct berval left;
1601         int i;
1602         ber_len_t inlen=0;
1603         char *nav;
1604
1605         nav = UTF8normalize( value->bv_val, UTF8_CASEFOLD );
1606         if( nav == NULL ) {
1607                 match = 1;
1608                 goto done;
1609         }
1610         left.bv_val = nav;
1611         left.bv_len = strlen( nav );
1612
1613         sub = UTF8SubstringsassertionNormalize( assertedValue, UTF8_CASEFOLD );
1614         if( sub == NULL ) {
1615                 match = -1;
1616                 goto done;
1617         }
1618
1619         /* Add up asserted input length */
1620         if( sub->sa_initial ) {
1621                 inlen += sub->sa_initial->bv_len;
1622         }
1623         if( sub->sa_any ) {
1624                 for(i=0; sub->sa_any[i] != NULL; i++) {
1625                         inlen += sub->sa_any[i]->bv_len;
1626                 }
1627         }
1628         if( sub->sa_final ) {
1629                 inlen += sub->sa_final->bv_len;
1630         }
1631
1632         if( sub->sa_initial ) {
1633                 if( inlen > left.bv_len ) {
1634                         match = 1;
1635                         goto done;
1636                 }
1637
1638                 match = strncmp( sub->sa_initial->bv_val, left.bv_val,
1639                         sub->sa_initial->bv_len );
1640
1641                 if( match != 0 ) {
1642                         goto done;
1643                 }
1644
1645                 left.bv_val += sub->sa_initial->bv_len;
1646                 left.bv_len -= sub->sa_initial->bv_len;
1647                 inlen -= sub->sa_initial->bv_len;
1648         }
1649
1650         if( sub->sa_final ) {
1651                 if( inlen > left.bv_len ) {
1652                         match = 1;
1653                         goto done;
1654                 }
1655
1656                 match = strncmp( sub->sa_final->bv_val,
1657                         &left.bv_val[left.bv_len - sub->sa_final->bv_len],
1658                         sub->sa_final->bv_len );
1659
1660                 if( match != 0 ) {
1661                         goto done;
1662                 }
1663
1664                 left.bv_len -= sub->sa_final->bv_len;
1665                 inlen -= sub->sa_final->bv_len;
1666         }
1667
1668         if( sub->sa_any ) {
1669                 for(i=0; sub->sa_any[i]; i++) {
1670                         ber_len_t idx;
1671                         char *p;
1672
1673 retry:
1674                         if( inlen > left.bv_len ) {
1675                                 /* not enough length */
1676                                 match = 1;
1677                                 goto done;
1678                         }
1679
1680                         if( sub->sa_any[i]->bv_len == 0 ) {
1681                                 continue;
1682                         }
1683
1684                         p = strchr( left.bv_val, *sub->sa_any[i]->bv_val );
1685
1686                         if( p == NULL ) {
1687                                 match = 1;
1688                                 goto done;
1689                         }
1690
1691                         idx = p - left.bv_val;
1692                         assert( idx < left.bv_len );
1693
1694                         if( idx >= left.bv_len ) {
1695                                 /* this shouldn't happen */
1696                                 return LDAP_OTHER;
1697                         }
1698
1699                         left.bv_val = p;
1700                         left.bv_len -= idx;
1701
1702                         if( sub->sa_any[i]->bv_len > left.bv_len ) {
1703                                 /* not enough left */
1704                                 match = 1;
1705                                 goto done;
1706                         }
1707
1708                         match = strncmp( left.bv_val,
1709                                 sub->sa_any[i]->bv_val,
1710                                 sub->sa_any[i]->bv_len );
1711
1712                         if( match != 0 ) {
1713                                 left.bv_val++;
1714                                 left.bv_len--;
1715
1716                                 goto retry;
1717                         }
1718
1719                         left.bv_val += sub->sa_any[i]->bv_len;
1720                         left.bv_len -= sub->sa_any[i]->bv_len;
1721                         inlen -= sub->sa_any[i]->bv_len;
1722                 }
1723         }
1724
1725 done:
1726         free( nav );
1727         if( sub != NULL ) {
1728                 ch_free( sub->sa_final );
1729                 ber_bvecfree( sub->sa_any );
1730                 ch_free( sub->sa_initial );
1731                 ch_free( sub );
1732         }
1733         *matchp = match;
1734         return LDAP_SUCCESS;
1735 }
1736
1737 /* Index generation function */
1738 int caseIgnoreIndexer(
1739         slap_mask_t use,
1740         slap_mask_t flags,
1741         Syntax *syntax,
1742         MatchingRule *mr,
1743         struct berval *prefix,
1744         struct berval **values,
1745         struct berval ***keysp )
1746 {
1747         int i;
1748         size_t slen, mlen;
1749         struct berval **keys;
1750         HASH_CONTEXT   HASHcontext;
1751         unsigned char   HASHdigest[HASH_BYTES];
1752         struct berval digest;
1753         digest.bv_val = HASHdigest;
1754         digest.bv_len = sizeof(HASHdigest);
1755
1756         /* we should have at least one value at this point */
1757         assert( values != NULL && values[0] != NULL );
1758
1759         for( i=0; values[i] != NULL; i++ ) {
1760                 /* just count them */
1761         }
1762
1763         keys = ch_malloc( sizeof( struct berval * ) * (i+1) );
1764
1765         slen = strlen( syntax->ssyn_oid );
1766         mlen = strlen( mr->smr_oid );
1767
1768         for( i=0; values[i] != NULL; i++ ) {
1769                 struct berval *value;
1770                 value = ber_bvstr( UTF8normalize( values[i]->bv_val, UTF8_CASEFOLD ) );
1771                 HASH_Init( &HASHcontext );
1772                 if( prefix != NULL && prefix->bv_len > 0 ) {
1773                         HASH_Update( &HASHcontext,
1774                                 prefix->bv_val, prefix->bv_len );
1775                 }
1776                 HASH_Update( &HASHcontext,
1777                         syntax->ssyn_oid, slen );
1778                 HASH_Update( &HASHcontext,
1779                         mr->smr_oid, mlen );
1780                 HASH_Update( &HASHcontext,
1781                         value->bv_val, value->bv_len );
1782                 HASH_Final( HASHdigest, &HASHcontext );
1783
1784                 ber_bvfree( value );
1785
1786                 keys[i] = ber_bvdup( &digest );
1787         }
1788
1789         keys[i] = NULL;
1790         *keysp = keys;
1791         return LDAP_SUCCESS;
1792 }
1793
1794 /* Index generation function */
1795 int caseIgnoreFilter(
1796         slap_mask_t use,
1797         slap_mask_t flags,
1798         Syntax *syntax,
1799         MatchingRule *mr,
1800         struct berval *prefix,
1801         void * assertValue,
1802         struct berval ***keysp )
1803 {
1804         size_t slen, mlen;
1805         struct berval **keys;
1806         HASH_CONTEXT   HASHcontext;
1807         unsigned char   HASHdigest[HASH_BYTES];
1808         struct berval *value;
1809         struct berval digest;
1810         digest.bv_val = HASHdigest;
1811         digest.bv_len = sizeof(HASHdigest);
1812
1813         slen = strlen( syntax->ssyn_oid );
1814         mlen = strlen( mr->smr_oid );
1815
1816         value = ber_bvstr( UTF8normalize( ((struct berval *) assertValue)->bv_val,
1817                 UTF8_CASEFOLD ) );
1818         /* This usually happens if filter contains bad UTF8 */
1819         if( value == NULL ) {
1820                 keys = ch_malloc( sizeof( struct berval * ) );
1821                 keys[0] = NULL;
1822                 return LDAP_SUCCESS;
1823         }
1824
1825         keys = ch_malloc( sizeof( struct berval * ) * 2 );
1826
1827         HASH_Init( &HASHcontext );
1828         if( prefix != NULL && prefix->bv_len > 0 ) {
1829                 HASH_Update( &HASHcontext,
1830                         prefix->bv_val, prefix->bv_len );
1831         }
1832         HASH_Update( &HASHcontext,
1833                 syntax->ssyn_oid, slen );
1834         HASH_Update( &HASHcontext,
1835                 mr->smr_oid, mlen );
1836         HASH_Update( &HASHcontext,
1837                 value->bv_val, value->bv_len );
1838         HASH_Final( HASHdigest, &HASHcontext );
1839
1840         keys[0] = ber_bvdup( &digest );
1841         keys[1] = NULL;
1842
1843         ber_bvfree( value );
1844
1845         *keysp = keys;
1846
1847         return LDAP_SUCCESS;
1848 }
1849
1850 /* Substrings Index generation function */
1851 int caseIgnoreSubstringsIndexer(
1852         slap_mask_t use,
1853         slap_mask_t flags,
1854         Syntax *syntax,
1855         MatchingRule *mr,
1856         struct berval *prefix,
1857         struct berval **values,
1858         struct berval ***keysp )
1859 {
1860         ber_len_t i, nkeys;
1861         size_t slen, mlen;
1862         struct berval **keys;
1863         struct berval **nvalues;
1864
1865         HASH_CONTEXT   HASHcontext;
1866         unsigned char   HASHdigest[HASH_BYTES];
1867         struct berval digest;
1868         digest.bv_val = HASHdigest;
1869         digest.bv_len = sizeof(HASHdigest);
1870
1871         /* we should have at least one value at this point */
1872         assert( values != NULL && values[0] != NULL );
1873
1874         nkeys=0;
1875
1876         /* create normalized copy of values */
1877         for( i=0; values[i] != NULL; i++ ) {
1878                 /* empty */
1879         }
1880         nvalues = ch_malloc( sizeof( struct berval * ) * (i+1) );
1881         for( i=0; values[i] != NULL; i++ ) {
1882                 nvalues[i] = ber_bvstr( UTF8normalize( values[i]->bv_val,
1883                         UTF8_CASEFOLD ) );
1884         }
1885         nvalues[i] = NULL;
1886         values = nvalues;
1887
1888         for( i=0; values[i] != NULL; i++ ) {
1889                 /* count number of indices to generate */
1890                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
1891                         continue;
1892                 }
1893
1894                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1895                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1896                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
1897                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
1898                         } else {
1899                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
1900                         }
1901                 }
1902
1903                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
1904                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1905                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
1906                         }
1907                 }
1908
1909                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1910                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1911                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
1912                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
1913                         } else {
1914                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
1915                         }
1916                 }
1917         }
1918
1919         if( nkeys == 0 ) {
1920                 /* no keys to generate */
1921                 *keysp = NULL;
1922                 return LDAP_SUCCESS;
1923         }
1924
1925         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
1926
1927         slen = strlen( syntax->ssyn_oid );
1928         mlen = strlen( mr->smr_oid );
1929
1930         nkeys=0;
1931         for( i=0; values[i] != NULL; i++ ) {
1932                 int j,max;
1933                 struct berval *value;
1934
1935                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
1936
1937                 value = values[i];
1938
1939                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
1940                         ( value->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
1941                 {
1942                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
1943                         max = value->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
1944
1945                         for( j=0; j<max; j++ ) {
1946                                 HASH_Init( &HASHcontext );
1947                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1948                                         HASH_Update( &HASHcontext,
1949                                                 prefix->bv_val, prefix->bv_len );
1950                                 }
1951
1952                                 HASH_Update( &HASHcontext,
1953                                         &pre, sizeof( pre ) );
1954                                 HASH_Update( &HASHcontext,
1955                                         syntax->ssyn_oid, slen );
1956                                 HASH_Update( &HASHcontext,
1957                                         mr->smr_oid, mlen );
1958                                 HASH_Update( &HASHcontext,
1959                                         &value->bv_val[j],
1960                                         SLAP_INDEX_SUBSTR_MAXLEN );
1961                                 HASH_Final( HASHdigest, &HASHcontext );
1962
1963                                 keys[nkeys++] = ber_bvdup( &digest );
1964                         }
1965                 }
1966
1967                 max = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
1968                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
1969
1970                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
1971                         char pre;
1972
1973                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1974                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1975                                 HASH_Init( &HASHcontext );
1976                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1977                                         HASH_Update( &HASHcontext,
1978                                                 prefix->bv_val, prefix->bv_len );
1979                                 }
1980                                 HASH_Update( &HASHcontext,
1981                                         &pre, sizeof( pre ) );
1982                                 HASH_Update( &HASHcontext,
1983                                         syntax->ssyn_oid, slen );
1984                                 HASH_Update( &HASHcontext,
1985                                         mr->smr_oid, mlen );
1986                                 HASH_Update( &HASHcontext,
1987                                         value->bv_val, j );
1988                                 HASH_Final( HASHdigest, &HASHcontext );
1989
1990                                 keys[nkeys++] = ber_bvdup( &digest );
1991                         }
1992
1993                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1994                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1995                                 HASH_Init( &HASHcontext );
1996                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1997                                         HASH_Update( &HASHcontext,
1998                                                 prefix->bv_val, prefix->bv_len );
1999                                 }
2000                                 HASH_Update( &HASHcontext,
2001                                         &pre, sizeof( pre ) );
2002                                 HASH_Update( &HASHcontext,
2003                                         syntax->ssyn_oid, slen );
2004                                 HASH_Update( &HASHcontext,
2005                                         mr->smr_oid, mlen );
2006                                 HASH_Update( &HASHcontext,
2007                                         &value->bv_val[value->bv_len-j], j );
2008                                 HASH_Final( HASHdigest, &HASHcontext );
2009
2010                                 keys[nkeys++] = ber_bvdup( &digest );
2011                         }
2012
2013                 }
2014         }
2015
2016         if( nkeys > 0 ) {
2017                 keys[nkeys] = NULL;
2018                 *keysp = keys;
2019         } else {
2020                 ch_free( keys );
2021                 *keysp = NULL;
2022         }
2023
2024         ber_bvecfree( nvalues );
2025         return LDAP_SUCCESS;
2026 }
2027
2028 int caseIgnoreSubstringsFilter(
2029         slap_mask_t use,
2030         slap_mask_t flags,
2031         Syntax *syntax,
2032         MatchingRule *mr,
2033         struct berval *prefix,
2034         void * assertValue,
2035         struct berval ***keysp )
2036 {
2037         SubstringsAssertion *sa;
2038         char pre;
2039         ber_len_t nkeys = 0;
2040         size_t slen, mlen, klen;
2041         struct berval **keys;
2042         HASH_CONTEXT   HASHcontext;
2043         unsigned char   HASHdigest[HASH_BYTES];
2044         struct berval *value;
2045         struct berval digest;
2046
2047         sa = UTF8SubstringsassertionNormalize( assertValue, UTF8_CASEFOLD );
2048         if( sa == NULL ) {
2049                 *keysp = NULL;
2050                 return LDAP_SUCCESS;
2051         }
2052
2053         if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial != NULL &&
2054                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2055         {
2056                 nkeys++;
2057         }
2058
2059         if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
2060                 ber_len_t i;
2061                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
2062                         if( sa->sa_any[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2063                                 /* don't bother accounting for stepping */
2064                                 nkeys += sa->sa_any[i]->bv_len -
2065                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
2066                         }
2067                 }
2068         }
2069
2070         if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final != NULL &&
2071                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2072         {
2073                 nkeys++;
2074         }
2075
2076         if( nkeys == 0 ) {
2077                 *keysp = NULL;
2078                 return LDAP_SUCCESS;
2079         }
2080
2081         digest.bv_val = HASHdigest;
2082         digest.bv_len = sizeof(HASHdigest);
2083
2084         slen = strlen( syntax->ssyn_oid );
2085         mlen = strlen( mr->smr_oid );
2086
2087         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
2088         nkeys = 0;
2089
2090         if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial != NULL &&
2091                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2092         {
2093                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
2094                 value = sa->sa_initial;
2095
2096                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2097                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2098
2099                 HASH_Init( &HASHcontext );
2100                 if( prefix != NULL && prefix->bv_len > 0 ) {
2101                         HASH_Update( &HASHcontext,
2102                                 prefix->bv_val, prefix->bv_len );
2103                 }
2104                 HASH_Update( &HASHcontext,
2105                         &pre, sizeof( pre ) );
2106                 HASH_Update( &HASHcontext,
2107                         syntax->ssyn_oid, slen );
2108                 HASH_Update( &HASHcontext,
2109                         mr->smr_oid, mlen );
2110                 HASH_Update( &HASHcontext,
2111                         value->bv_val, klen );
2112                 HASH_Final( HASHdigest, &HASHcontext );
2113
2114                 keys[nkeys++] = ber_bvdup( &digest );
2115         }
2116
2117         if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
2118                 ber_len_t i, j;
2119                 pre = SLAP_INDEX_SUBSTR_PREFIX;
2120                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
2121
2122                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
2123                         if( sa->sa_any[i]->bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
2124                                 continue;
2125                         }
2126
2127                         value = sa->sa_any[i];
2128
2129                         for(j=0;
2130                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
2131                                 j += SLAP_INDEX_SUBSTR_STEP )
2132                         {
2133                                 HASH_Init( &HASHcontext );
2134                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2135                                         HASH_Update( &HASHcontext,
2136                                                 prefix->bv_val, prefix->bv_len );
2137                                 }
2138                                 HASH_Update( &HASHcontext,
2139                                         &pre, sizeof( pre ) );
2140                                 HASH_Update( &HASHcontext,
2141                                         syntax->ssyn_oid, slen );
2142                                 HASH_Update( &HASHcontext,
2143                                         mr->smr_oid, mlen );
2144                                 HASH_Update( &HASHcontext,
2145                                         &value->bv_val[j], klen );
2146                                 HASH_Final( HASHdigest, &HASHcontext );
2147
2148                                 keys[nkeys++] = ber_bvdup( &digest );
2149                         }
2150                 }
2151         }
2152
2153         if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final != NULL &&
2154                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2155         {
2156                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
2157                 value = sa->sa_final;
2158
2159                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2160                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2161
2162                 HASH_Init( &HASHcontext );
2163                 if( prefix != NULL && prefix->bv_len > 0 ) {
2164                         HASH_Update( &HASHcontext,
2165                                 prefix->bv_val, prefix->bv_len );
2166                 }
2167                 HASH_Update( &HASHcontext,
2168                         &pre, sizeof( pre ) );
2169                 HASH_Update( &HASHcontext,
2170                         syntax->ssyn_oid, slen );
2171                 HASH_Update( &HASHcontext,
2172                         mr->smr_oid, mlen );
2173                 HASH_Update( &HASHcontext,
2174                         &value->bv_val[value->bv_len-klen], klen );
2175                 HASH_Final( HASHdigest, &HASHcontext );
2176
2177                 keys[nkeys++] = ber_bvdup( &digest );
2178         }
2179
2180         if( nkeys > 0 ) {
2181                 keys[nkeys] = NULL;
2182                 *keysp = keys;
2183         } else {
2184                 ch_free( keys );
2185                 *keysp = NULL;
2186         }
2187         ch_free( sa->sa_final );
2188         ber_bvecfree( sa->sa_any );
2189         ch_free( sa->sa_initial );
2190         ch_free( sa );
2191
2192         return LDAP_SUCCESS;
2193 }
2194         
2195 static int
2196 oidValidate(
2197         Syntax *syntax,
2198         struct berval *val )
2199 {
2200         ber_len_t i;
2201
2202         if( val->bv_len == 0 ) {
2203                 /* disallow empty strings */
2204                 return LDAP_INVALID_SYNTAX;
2205         }
2206
2207         if( OID_LEADCHAR(val->bv_val[0]) ) {
2208                 int dot = 0;
2209                 for(i=1; i < val->bv_len; i++) {
2210                         if( OID_SEPARATOR( val->bv_val[i] ) ) {
2211                                 if( dot++ ) return 1;
2212                         } else if ( OID_CHAR( val->bv_val[i] ) ) {
2213                                 dot = 0;
2214                         } else {
2215                                 return LDAP_INVALID_SYNTAX;
2216                         }
2217                 }
2218
2219                 return !dot ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
2220
2221         } else if( DESC_LEADCHAR(val->bv_val[0]) ) {
2222                 for(i=1; i < val->bv_len; i++) {
2223                         if( !DESC_CHAR(val->bv_val[i] ) ) {
2224                                 return LDAP_INVALID_SYNTAX;
2225                         }
2226                 }
2227
2228                 return LDAP_SUCCESS;
2229         }
2230         
2231         return LDAP_INVALID_SYNTAX;
2232 }
2233
2234 static int
2235 integerValidate(
2236         Syntax *syntax,
2237         struct berval *val )
2238 {
2239         ber_len_t i;
2240
2241         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
2242
2243         if( val->bv_val[0] == '+' || val->bv_val[0] == '-' ) {
2244                 if( val->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
2245         } else if( !ASCII_DIGIT(val->bv_val[0]) ) {
2246                 return LDAP_INVALID_SYNTAX;
2247         }
2248
2249         for(i=1; i < val->bv_len; i++) {
2250                 if( !ASCII_DIGIT(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
2251         }
2252
2253         return LDAP_SUCCESS;
2254 }
2255
2256 static int
2257 integerNormalize(
2258         Syntax *syntax,
2259         struct berval *val,
2260         struct berval **normalized )
2261 {
2262         int negative;
2263         struct berval *newval;
2264         char *p;
2265
2266         p = val->bv_val;
2267
2268         /* save sign */
2269         negative = ( *p == '-' );
2270         if( *p == '-' || *p == '+' ) p++;
2271
2272         /* Ignore leading zeros */
2273         while ( *p == '0' ) p++;
2274
2275         newval = (struct berval *) ch_malloc( sizeof(struct berval) );
2276
2277         if( *p == '\0' ) {
2278                 newval->bv_val = ch_strdup("0");
2279                 newval->bv_len = 1;
2280                 goto done;
2281         }
2282
2283         newval->bv_val = ch_malloc( val->bv_len + 1 );
2284         newval->bv_len = 0;
2285
2286         if( negative ) {
2287                 newval->bv_val[newval->bv_len++] = '-';
2288         }
2289
2290         for( ; *p != '\0'; p++ ) {
2291                 newval->bv_val[newval->bv_len++] = *p;
2292         }
2293
2294 done:
2295         *normalized = newval;
2296         return LDAP_SUCCESS;
2297 }
2298
2299 static int
2300 countryStringValidate(
2301         Syntax *syntax,
2302         struct berval *val )
2303 {
2304         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2305
2306         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2307                 return LDAP_INVALID_SYNTAX;
2308         }
2309         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2310                 return LDAP_INVALID_SYNTAX;
2311         }
2312
2313         return LDAP_SUCCESS;
2314 }
2315
2316 static int
2317 printableStringValidate(
2318         Syntax *syntax,
2319         struct berval *val )
2320 {
2321         ber_len_t i;
2322
2323         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
2324
2325         for(i=0; i < val->bv_len; i++) {
2326                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2327                         return LDAP_INVALID_SYNTAX;
2328                 }
2329         }
2330
2331         return LDAP_SUCCESS;
2332 }
2333
2334 static int
2335 printablesStringValidate(
2336         Syntax *syntax,
2337         struct berval *val )
2338 {
2339         ber_len_t i;
2340
2341         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
2342
2343         for(i=0; i < val->bv_len; i++) {
2344                 if( !SLAP_PRINTABLES(val->bv_val[i]) ) {
2345                         return LDAP_INVALID_SYNTAX;
2346                 }
2347         }
2348
2349         return LDAP_SUCCESS;
2350 }
2351
2352 static int
2353 IA5StringValidate(
2354         Syntax *syntax,
2355         struct berval *val )
2356 {
2357         ber_len_t i;
2358
2359         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
2360
2361         for(i=0; i < val->bv_len; i++) {
2362                 if( !isascii(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
2363         }
2364
2365         return LDAP_SUCCESS;
2366 }
2367
2368 static int
2369 IA5StringNormalize(
2370         Syntax *syntax,
2371         struct berval *val,
2372         struct berval **normalized )
2373 {
2374         struct berval *newval;
2375         char *p, *q;
2376
2377         newval = ch_malloc( sizeof( struct berval ) );
2378
2379         p = val->bv_val;
2380
2381         /* Ignore initial whitespace */
2382         while ( ASCII_SPACE( *p ) ) {
2383                 p++;
2384         }
2385
2386         if( *p == '\0' ) {
2387                 ch_free( newval );
2388                 return LDAP_INVALID_SYNTAX;
2389         }
2390
2391         newval->bv_val = ch_strdup( p );
2392         p = q = newval->bv_val;
2393
2394         while ( *p ) {
2395                 if ( ASCII_SPACE( *p ) ) {
2396                         *q++ = *p++;
2397
2398                         /* Ignore the extra whitespace */
2399                         while ( ASCII_SPACE( *p ) ) {
2400                                 p++;
2401                         }
2402                 } else {
2403                         *q++ = *p++;
2404                 }
2405         }
2406
2407         assert( *newval->bv_val );
2408         assert( newval->bv_val < p );
2409         assert( q <= p );
2410
2411         /* cannot start with a space */
2412         assert( !ASCII_SPACE(*newval->bv_val) );
2413
2414         /*
2415          * If the string ended in space, backup the pointer one
2416          * position.  One is enough because the above loop collapsed
2417          * all whitespace to a single space.
2418          */
2419
2420         if ( ASCII_SPACE( q[-1] ) ) {
2421                 --q;
2422         }
2423
2424         /* cannot end with a space */
2425         assert( !ASCII_SPACE( q[-1] ) );
2426
2427         /* null terminate */
2428         *q = '\0';
2429
2430         newval->bv_len = q - newval->bv_val;
2431         *normalized = newval;
2432
2433         return LDAP_SUCCESS;
2434 }
2435
2436 static int
2437 caseExactIA5Match(
2438         int *matchp,
2439         slap_mask_t flags,
2440         Syntax *syntax,
2441         MatchingRule *mr,
2442         struct berval *value,
2443         void *assertedValue )
2444 {
2445         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
2446
2447         if( match == 0 ) {
2448                 match = strncmp( value->bv_val,
2449                         ((struct berval *) assertedValue)->bv_val,
2450                         value->bv_len );
2451         }
2452
2453         *matchp = match;
2454         return LDAP_SUCCESS;
2455 }
2456
2457 static int
2458 caseExactIA5SubstringsMatch(
2459         int *matchp,
2460         slap_mask_t flags,
2461         Syntax *syntax,
2462         MatchingRule *mr,
2463         struct berval *value,
2464         void *assertedValue )
2465 {
2466         int match = 0;
2467         SubstringsAssertion *sub = assertedValue;
2468         struct berval left = *value;
2469         int i;
2470         ber_len_t inlen=0;
2471
2472         /* Add up asserted input length */
2473         if( sub->sa_initial ) {
2474                 inlen += sub->sa_initial->bv_len;
2475         }
2476         if( sub->sa_any ) {
2477                 for(i=0; sub->sa_any[i] != NULL; i++) {
2478                         inlen += sub->sa_any[i]->bv_len;
2479                 }
2480         }
2481         if( sub->sa_final ) {
2482                 inlen += sub->sa_final->bv_len;
2483         }
2484
2485         if( sub->sa_initial ) {
2486                 if( inlen > left.bv_len ) {
2487                         match = 1;
2488                         goto done;
2489                 }
2490
2491                 match = strncmp( sub->sa_initial->bv_val, left.bv_val,
2492                         sub->sa_initial->bv_len );
2493
2494                 if( match != 0 ) {
2495                         goto done;
2496                 }
2497
2498                 left.bv_val += sub->sa_initial->bv_len;
2499                 left.bv_len -= sub->sa_initial->bv_len;
2500                 inlen -= sub->sa_initial->bv_len;
2501         }
2502
2503         if( sub->sa_final ) {
2504                 if( inlen > left.bv_len ) {
2505                         match = 1;
2506                         goto done;
2507                 }
2508
2509                 match = strncmp( sub->sa_final->bv_val,
2510                         &left.bv_val[left.bv_len - sub->sa_final->bv_len],
2511                         sub->sa_final->bv_len );
2512
2513                 if( match != 0 ) {
2514                         goto done;
2515                 }
2516
2517                 left.bv_len -= sub->sa_final->bv_len;
2518                 inlen -= sub->sa_final->bv_len;
2519         }
2520
2521         if( sub->sa_any ) {
2522                 for(i=0; sub->sa_any[i]; i++) {
2523                         ber_len_t idx;
2524                         char *p;
2525
2526 retry:
2527                         if( inlen > left.bv_len ) {
2528                                 /* not enough length */
2529                                 match = 1;
2530                                 goto done;
2531                         }
2532
2533                         if( sub->sa_any[i]->bv_len == 0 ) {
2534                                 continue;
2535                         }
2536
2537                         p = strchr( left.bv_val, *sub->sa_any[i]->bv_val );
2538
2539                         if( p == NULL ) {
2540                                 match = 1;
2541                                 goto done;
2542                         }
2543
2544                         idx = p - left.bv_val;
2545                         assert( idx < left.bv_len );
2546
2547                         if( idx >= left.bv_len ) {
2548                                 /* this shouldn't happen */
2549                                 return LDAP_OTHER;
2550                         }
2551
2552                         left.bv_val = p;
2553                         left.bv_len -= idx;
2554
2555                         if( sub->sa_any[i]->bv_len > left.bv_len ) {
2556                                 /* not enough left */
2557                                 match = 1;
2558                                 goto done;
2559                         }
2560
2561                         match = strncmp( left.bv_val,
2562                                 sub->sa_any[i]->bv_val,
2563                                 sub->sa_any[i]->bv_len );
2564
2565                         if( match != 0 ) {
2566                                 left.bv_val++;
2567                                 left.bv_len--;
2568                                 goto retry;
2569                         }
2570
2571                         left.bv_val += sub->sa_any[i]->bv_len;
2572                         left.bv_len -= sub->sa_any[i]->bv_len;
2573                         inlen -= sub->sa_any[i]->bv_len;
2574                 }
2575         }
2576
2577 done:
2578         *matchp = match;
2579         return LDAP_SUCCESS;
2580 }
2581
2582 /* Index generation function */
2583 int caseExactIA5Indexer(
2584         slap_mask_t use,
2585         slap_mask_t flags,
2586         Syntax *syntax,
2587         MatchingRule *mr,
2588         struct berval *prefix,
2589         struct berval **values,
2590         struct berval ***keysp )
2591 {
2592         int i;
2593         size_t slen, mlen;
2594         struct berval **keys;
2595         HASH_CONTEXT   HASHcontext;
2596         unsigned char   HASHdigest[HASH_BYTES];
2597         struct berval digest;
2598         digest.bv_val = HASHdigest;
2599         digest.bv_len = sizeof(HASHdigest);
2600
2601         /* we should have at least one value at this point */
2602         assert( values != NULL && values[0] != NULL );
2603
2604         for( i=0; values[i] != NULL; i++ ) {
2605                 /* just count them */
2606         }
2607
2608         keys = ch_malloc( sizeof( struct berval * ) * (i+1) );
2609
2610         slen = strlen( syntax->ssyn_oid );
2611         mlen = strlen( mr->smr_oid );
2612
2613         for( i=0; values[i] != NULL; i++ ) {
2614                 struct berval *value = values[i];
2615
2616                 HASH_Init( &HASHcontext );
2617                 if( prefix != NULL && prefix->bv_len > 0 ) {
2618                         HASH_Update( &HASHcontext,
2619                                 prefix->bv_val, prefix->bv_len );
2620                 }
2621                 HASH_Update( &HASHcontext,
2622                         syntax->ssyn_oid, slen );
2623                 HASH_Update( &HASHcontext,
2624                         mr->smr_oid, mlen );
2625                 HASH_Update( &HASHcontext,
2626                         value->bv_val, value->bv_len );
2627                 HASH_Final( HASHdigest, &HASHcontext );
2628
2629                 keys[i] = ber_bvdup( &digest );
2630         }
2631
2632         keys[i] = NULL;
2633         *keysp = keys;
2634         return LDAP_SUCCESS;
2635 }
2636
2637 /* Index generation function */
2638 int caseExactIA5Filter(
2639         slap_mask_t use,
2640         slap_mask_t flags,
2641         Syntax *syntax,
2642         MatchingRule *mr,
2643         struct berval *prefix,
2644         void * assertValue,
2645         struct berval ***keysp )
2646 {
2647         size_t slen, mlen;
2648         struct berval **keys;
2649         HASH_CONTEXT   HASHcontext;
2650         unsigned char   HASHdigest[HASH_BYTES];
2651         struct berval *value;
2652         struct berval digest;
2653         digest.bv_val = HASHdigest;
2654         digest.bv_len = sizeof(HASHdigest);
2655
2656         slen = strlen( syntax->ssyn_oid );
2657         mlen = strlen( mr->smr_oid );
2658
2659         value = (struct berval *) assertValue;
2660
2661         keys = ch_malloc( sizeof( struct berval * ) * 2 );
2662
2663         HASH_Init( &HASHcontext );
2664         if( prefix != NULL && prefix->bv_len > 0 ) {
2665                 HASH_Update( &HASHcontext,
2666                         prefix->bv_val, prefix->bv_len );
2667         }
2668         HASH_Update( &HASHcontext,
2669                 syntax->ssyn_oid, slen );
2670         HASH_Update( &HASHcontext,
2671                 mr->smr_oid, mlen );
2672         HASH_Update( &HASHcontext,
2673                 value->bv_val, value->bv_len );
2674         HASH_Final( HASHdigest, &HASHcontext );
2675
2676         keys[0] = ber_bvdup( &digest );
2677         keys[1] = NULL;
2678
2679         *keysp = keys;
2680         return LDAP_SUCCESS;
2681 }
2682
2683 /* Substrings Index generation function */
2684 int caseExactIA5SubstringsIndexer(
2685         slap_mask_t use,
2686         slap_mask_t flags,
2687         Syntax *syntax,
2688         MatchingRule *mr,
2689         struct berval *prefix,
2690         struct berval **values,
2691         struct berval ***keysp )
2692 {
2693         ber_len_t i, nkeys;
2694         size_t slen, mlen;
2695         struct berval **keys;
2696         HASH_CONTEXT   HASHcontext;
2697         unsigned char   HASHdigest[HASH_BYTES];
2698         struct berval digest;
2699         digest.bv_val = HASHdigest;
2700         digest.bv_len = sizeof(HASHdigest);
2701
2702         /* we should have at least one value at this point */
2703         assert( values != NULL && values[0] != NULL );
2704
2705         nkeys=0;
2706         for( i=0; values[i] != NULL; i++ ) {
2707                 /* count number of indices to generate */
2708                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
2709                         continue;
2710                 }
2711
2712                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
2713                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2714                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
2715                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
2716                         } else {
2717                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
2718                         }
2719                 }
2720
2721                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
2722                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2723                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
2724                         }
2725                 }
2726
2727                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
2728                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2729                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
2730                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
2731                         } else {
2732                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
2733                         }
2734                 }
2735         }
2736
2737         if( nkeys == 0 ) {
2738                 /* no keys to generate */
2739                 *keysp = NULL;
2740                 return LDAP_SUCCESS;
2741         }
2742
2743         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
2744
2745         slen = strlen( syntax->ssyn_oid );
2746         mlen = strlen( mr->smr_oid );
2747
2748         nkeys=0;
2749         for( i=0; values[i] != NULL; i++ ) {
2750                 ber_len_t j,max;
2751                 struct berval *value;
2752
2753                 value = values[i];
2754                 if( value->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
2755
2756                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
2757                         ( value->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
2758                 {
2759                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
2760                         max = value->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
2761
2762                         for( j=0; j<max; j++ ) {
2763                                 HASH_Init( &HASHcontext );
2764                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2765                                         HASH_Update( &HASHcontext,
2766                                                 prefix->bv_val, prefix->bv_len );
2767                                 }
2768
2769                                 HASH_Update( &HASHcontext,
2770                                         &pre, sizeof( pre ) );
2771                                 HASH_Update( &HASHcontext,
2772                                         syntax->ssyn_oid, slen );
2773                                 HASH_Update( &HASHcontext,
2774                                         mr->smr_oid, mlen );
2775                                 HASH_Update( &HASHcontext,
2776                                         &value->bv_val[j],
2777                                         SLAP_INDEX_SUBSTR_MAXLEN );
2778                                 HASH_Final( HASHdigest, &HASHcontext );
2779
2780                                 keys[nkeys++] = ber_bvdup( &digest );
2781                         }
2782                 }
2783
2784                 max = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2785                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2786
2787                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
2788                         char pre;
2789
2790                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
2791                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
2792                                 HASH_Init( &HASHcontext );
2793                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2794                                         HASH_Update( &HASHcontext,
2795                                                 prefix->bv_val, prefix->bv_len );
2796                                 }
2797                                 HASH_Update( &HASHcontext,
2798                                         &pre, sizeof( pre ) );
2799                                 HASH_Update( &HASHcontext,
2800                                         syntax->ssyn_oid, slen );
2801                                 HASH_Update( &HASHcontext,
2802                                         mr->smr_oid, mlen );
2803                                 HASH_Update( &HASHcontext,
2804                                         value->bv_val, j );
2805                                 HASH_Final( HASHdigest, &HASHcontext );
2806
2807                                 keys[nkeys++] = ber_bvdup( &digest );
2808                         }
2809
2810                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
2811                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
2812                                 HASH_Init( &HASHcontext );
2813                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2814                                         HASH_Update( &HASHcontext,
2815                                                 prefix->bv_val, prefix->bv_len );
2816                                 }
2817                                 HASH_Update( &HASHcontext,
2818                                         &pre, sizeof( pre ) );
2819                                 HASH_Update( &HASHcontext,
2820                                         syntax->ssyn_oid, slen );
2821                                 HASH_Update( &HASHcontext,
2822                                         mr->smr_oid, mlen );
2823                                 HASH_Update( &HASHcontext,
2824                                         &value->bv_val[value->bv_len-j], j );
2825                                 HASH_Final( HASHdigest, &HASHcontext );
2826
2827                                 keys[nkeys++] = ber_bvdup( &digest );
2828                         }
2829
2830                 }
2831         }
2832
2833         if( nkeys > 0 ) {
2834                 keys[nkeys] = NULL;
2835                 *keysp = keys;
2836         } else {
2837                 ch_free( keys );
2838                 *keysp = NULL;
2839         }
2840
2841         return LDAP_SUCCESS;
2842 }
2843
2844 int caseExactIA5SubstringsFilter(
2845         slap_mask_t use,
2846         slap_mask_t flags,
2847         Syntax *syntax,
2848         MatchingRule *mr,
2849         struct berval *prefix,
2850         void * assertValue,
2851         struct berval ***keysp )
2852 {
2853         SubstringsAssertion *sa = assertValue;
2854         char pre;
2855         ber_len_t nkeys = 0;
2856         size_t slen, mlen, klen;
2857         struct berval **keys;
2858         HASH_CONTEXT   HASHcontext;
2859         unsigned char   HASHdigest[HASH_BYTES];
2860         struct berval *value;
2861         struct berval digest;
2862
2863         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial != NULL &&
2864                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2865         {
2866                 nkeys++;
2867         }
2868
2869         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
2870                 ber_len_t i;
2871                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
2872                         if( sa->sa_any[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2873                                 /* don't bother accounting for stepping */
2874                                 nkeys += sa->sa_any[i]->bv_len -
2875                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
2876                         }
2877                 }
2878         }
2879
2880         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final != NULL &&
2881                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2882         {
2883                 nkeys++;
2884         }
2885
2886         if( nkeys == 0 ) {
2887                 *keysp = NULL;
2888                 return LDAP_SUCCESS;
2889         }
2890
2891         digest.bv_val = HASHdigest;
2892         digest.bv_len = sizeof(HASHdigest);
2893
2894         slen = strlen( syntax->ssyn_oid );
2895         mlen = strlen( mr->smr_oid );
2896
2897         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
2898         nkeys = 0;
2899
2900         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial != NULL &&
2901                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2902         {
2903                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
2904                 value = sa->sa_initial;
2905
2906                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2907                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2908
2909                 HASH_Init( &HASHcontext );
2910                 if( prefix != NULL && prefix->bv_len > 0 ) {
2911                         HASH_Update( &HASHcontext,
2912                                 prefix->bv_val, prefix->bv_len );
2913                 }
2914                 HASH_Update( &HASHcontext,
2915                         &pre, sizeof( pre ) );
2916                 HASH_Update( &HASHcontext,
2917                         syntax->ssyn_oid, slen );
2918                 HASH_Update( &HASHcontext,
2919                         mr->smr_oid, mlen );
2920                 HASH_Update( &HASHcontext,
2921                         value->bv_val, klen );
2922                 HASH_Final( HASHdigest, &HASHcontext );
2923
2924                 keys[nkeys++] = ber_bvdup( &digest );
2925         }
2926
2927         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
2928                 ber_len_t i, j;
2929                 pre = SLAP_INDEX_SUBSTR_PREFIX;
2930                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
2931
2932                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
2933                         if( sa->sa_any[i]->bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
2934                                 continue;
2935                         }
2936
2937                         value = sa->sa_any[i];
2938
2939                         for(j=0;
2940                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
2941                                 j += SLAP_INDEX_SUBSTR_STEP )
2942                         {
2943                                 HASH_Init( &HASHcontext );
2944                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2945                                         HASH_Update( &HASHcontext,
2946                                                 prefix->bv_val, prefix->bv_len );
2947                                 }
2948                                 HASH_Update( &HASHcontext,
2949                                         &pre, sizeof( pre ) );
2950                                 HASH_Update( &HASHcontext,
2951                                         syntax->ssyn_oid, slen );
2952                                 HASH_Update( &HASHcontext,
2953                                         mr->smr_oid, mlen );
2954                                 HASH_Update( &HASHcontext,
2955                                         &value->bv_val[j], klen ); 
2956                                 HASH_Final( HASHdigest, &HASHcontext );
2957
2958                                 keys[nkeys++] = ber_bvdup( &digest );
2959                         }
2960                 }
2961         }
2962
2963         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final != NULL &&
2964                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2965         {
2966                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
2967                 value = sa->sa_final;
2968
2969                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2970                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2971
2972                 HASH_Init( &HASHcontext );
2973                 if( prefix != NULL && prefix->bv_len > 0 ) {
2974                         HASH_Update( &HASHcontext,
2975                                 prefix->bv_val, prefix->bv_len );
2976                 }
2977                 HASH_Update( &HASHcontext,
2978                         &pre, sizeof( pre ) );
2979                 HASH_Update( &HASHcontext,
2980                         syntax->ssyn_oid, slen );
2981                 HASH_Update( &HASHcontext,
2982                         mr->smr_oid, mlen );
2983                 HASH_Update( &HASHcontext,
2984                         &value->bv_val[value->bv_len-klen], klen );
2985                 HASH_Final( HASHdigest, &HASHcontext );
2986
2987                 keys[nkeys++] = ber_bvdup( &digest );
2988         }
2989
2990         if( nkeys > 0 ) {
2991                 keys[nkeys] = NULL;
2992                 *keysp = keys;
2993         } else {
2994                 ch_free( keys );
2995                 *keysp = NULL;
2996         }
2997
2998         return LDAP_SUCCESS;
2999 }
3000         
3001 static int
3002 caseIgnoreIA5Match(
3003         int *matchp,
3004         slap_mask_t flags,
3005         Syntax *syntax,
3006         MatchingRule *mr,
3007         struct berval *value,
3008         void *assertedValue )
3009 {
3010         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
3011
3012         if( match == 0 && value->bv_len ) {
3013                 match = strncasecmp( value->bv_val,
3014                         ((struct berval *) assertedValue)->bv_val,
3015                         value->bv_len );
3016         }
3017
3018         *matchp = match;
3019         return LDAP_SUCCESS;
3020 }
3021
3022 static int
3023 caseIgnoreIA5SubstringsMatch(
3024         int *matchp,
3025         slap_mask_t flags,
3026         Syntax *syntax,
3027         MatchingRule *mr,
3028         struct berval *value,
3029         void *assertedValue )
3030 {
3031         int match = 0;
3032         SubstringsAssertion *sub = assertedValue;
3033         struct berval left = *value;
3034         int i;
3035         ber_len_t inlen=0;
3036
3037         /* Add up asserted input length */
3038         if( sub->sa_initial ) {
3039                 inlen += sub->sa_initial->bv_len;
3040         }
3041         if( sub->sa_any ) {
3042                 for(i=0; sub->sa_any[i] != NULL; i++) {
3043                         inlen += sub->sa_any[i]->bv_len;
3044                 }
3045         }
3046         if( sub->sa_final ) {
3047                 inlen += sub->sa_final->bv_len;
3048         }
3049
3050         if( sub->sa_initial ) {
3051                 if( inlen > left.bv_len ) {
3052                         match = 1;
3053                         goto done;
3054                 }
3055
3056                 match = strncasecmp( sub->sa_initial->bv_val, left.bv_val,
3057                         sub->sa_initial->bv_len );
3058
3059                 if( match != 0 ) {
3060                         goto done;
3061                 }
3062
3063                 left.bv_val += sub->sa_initial->bv_len;
3064                 left.bv_len -= sub->sa_initial->bv_len;
3065                 inlen -= sub->sa_initial->bv_len;
3066         }
3067
3068         if( sub->sa_final ) {
3069                 if( inlen > left.bv_len ) {
3070                         match = 1;
3071                         goto done;
3072                 }
3073
3074                 match = strncasecmp( sub->sa_final->bv_val,
3075                         &left.bv_val[left.bv_len - sub->sa_final->bv_len],
3076                         sub->sa_final->bv_len );
3077
3078                 if( match != 0 ) {
3079                         goto done;
3080                 }
3081
3082                 left.bv_len -= sub->sa_final->bv_len;
3083                 inlen -= sub->sa_final->bv_len;
3084         }
3085
3086         if( sub->sa_any ) {
3087                 for(i=0; sub->sa_any[i]; i++) {
3088                         ber_len_t idx;
3089                         char *p;
3090
3091 retry:
3092                         if( inlen > left.bv_len ) {
3093                                 /* not enough length */
3094                                 match = 1;
3095                                 goto done;
3096                         }
3097
3098                         if( sub->sa_any[i]->bv_len == 0 ) {
3099                                 continue;
3100                         }
3101
3102                         p = strcasechr( left.bv_val, *sub->sa_any[i]->bv_val );
3103
3104                         if( p == NULL ) {
3105                                 match = 1;
3106                                 goto done;
3107                         }
3108
3109                         idx = p - left.bv_val;
3110                         assert( idx < left.bv_len );
3111
3112                         if( idx >= left.bv_len ) {
3113                                 /* this shouldn't happen */
3114                                 return LDAP_OTHER;
3115                         }
3116
3117                         left.bv_val = p;
3118                         left.bv_len -= idx;
3119
3120                         if( sub->sa_any[i]->bv_len > left.bv_len ) {
3121                                 /* not enough left */
3122                                 match = 1;
3123                                 goto done;
3124                         }
3125
3126                         match = strncasecmp( left.bv_val,
3127                                 sub->sa_any[i]->bv_val,
3128                                 sub->sa_any[i]->bv_len );
3129
3130                         if( match != 0 ) {
3131                                 left.bv_val++;
3132                                 left.bv_len--;
3133
3134                                 goto retry;
3135                         }
3136
3137                         left.bv_val += sub->sa_any[i]->bv_len;
3138                         left.bv_len -= sub->sa_any[i]->bv_len;
3139                         inlen -= sub->sa_any[i]->bv_len;
3140                 }
3141         }
3142
3143 done:
3144         *matchp = match;
3145         return LDAP_SUCCESS;
3146 }
3147
3148 /* Index generation function */
3149 int caseIgnoreIA5Indexer(
3150         slap_mask_t use,
3151         slap_mask_t flags,
3152         Syntax *syntax,
3153         MatchingRule *mr,
3154         struct berval *prefix,
3155         struct berval **values,
3156         struct berval ***keysp )
3157 {
3158         int i;
3159         size_t slen, mlen;
3160         struct berval **keys;
3161         HASH_CONTEXT   HASHcontext;
3162         unsigned char   HASHdigest[HASH_BYTES];
3163         struct berval digest;
3164         digest.bv_val = HASHdigest;
3165         digest.bv_len = sizeof(HASHdigest);
3166
3167         /* we should have at least one value at this point */
3168         assert( values != NULL && values[0] != NULL );
3169
3170         for( i=0; values[i] != NULL; i++ ) {
3171                 /* just count them */
3172         }
3173
3174         keys = ch_malloc( sizeof( struct berval * ) * (i+1) );
3175
3176         slen = strlen( syntax->ssyn_oid );
3177         mlen = strlen( mr->smr_oid );
3178
3179         for( i=0; values[i] != NULL; i++ ) {
3180                 struct berval *value = ber_bvdup( values[i] );
3181                 ldap_pvt_str2upper( value->bv_val );
3182
3183                 HASH_Init( &HASHcontext );
3184                 if( prefix != NULL && prefix->bv_len > 0 ) {
3185                         HASH_Update( &HASHcontext,
3186                                 prefix->bv_val, prefix->bv_len );
3187                 }
3188                 HASH_Update( &HASHcontext,
3189                         syntax->ssyn_oid, slen );
3190                 HASH_Update( &HASHcontext,
3191                         mr->smr_oid, mlen );
3192                 HASH_Update( &HASHcontext,
3193                         value->bv_val, value->bv_len );
3194                 HASH_Final( HASHdigest, &HASHcontext );
3195
3196                 ber_bvfree( value );
3197
3198                 keys[i] = ber_bvdup( &digest );
3199         }
3200
3201         keys[i] = NULL;
3202         *keysp = keys;
3203         return LDAP_SUCCESS;
3204 }
3205
3206 /* Index generation function */
3207 int caseIgnoreIA5Filter(
3208         slap_mask_t use,
3209         slap_mask_t flags,
3210         Syntax *syntax,
3211         MatchingRule *mr,
3212         struct berval *prefix,
3213         void * assertValue,
3214         struct berval ***keysp )
3215 {
3216         size_t slen, mlen;
3217         struct berval **keys;
3218         HASH_CONTEXT   HASHcontext;
3219         unsigned char   HASHdigest[HASH_BYTES];
3220         struct berval *value;
3221         struct berval digest;
3222         digest.bv_val = HASHdigest;
3223         digest.bv_len = sizeof(HASHdigest);
3224
3225         slen = strlen( syntax->ssyn_oid );
3226         mlen = strlen( mr->smr_oid );
3227
3228         value = ber_bvdup( (struct berval *) assertValue );
3229         ldap_pvt_str2upper( value->bv_val );
3230
3231         keys = ch_malloc( sizeof( struct berval * ) * 2 );
3232
3233         HASH_Init( &HASHcontext );
3234         if( prefix != NULL && prefix->bv_len > 0 ) {
3235                 HASH_Update( &HASHcontext,
3236                         prefix->bv_val, prefix->bv_len );
3237         }
3238         HASH_Update( &HASHcontext,
3239                 syntax->ssyn_oid, slen );
3240         HASH_Update( &HASHcontext,
3241                 mr->smr_oid, mlen );
3242         HASH_Update( &HASHcontext,
3243                 value->bv_val, value->bv_len );
3244         HASH_Final( HASHdigest, &HASHcontext );
3245
3246         keys[0] = ber_bvdup( &digest );
3247         keys[1] = NULL;
3248
3249         ber_bvfree( value );
3250
3251         *keysp = keys;
3252
3253         return LDAP_SUCCESS;
3254 }
3255
3256 /* Substrings Index generation function */
3257 int caseIgnoreIA5SubstringsIndexer(
3258         slap_mask_t use,
3259         slap_mask_t flags,
3260         Syntax *syntax,
3261         MatchingRule *mr,
3262         struct berval *prefix,
3263         struct berval **values,
3264         struct berval ***keysp )
3265 {
3266         ber_len_t i, nkeys;
3267         size_t slen, mlen;
3268         struct berval **keys;
3269         HASH_CONTEXT   HASHcontext;
3270         unsigned char   HASHdigest[HASH_BYTES];
3271         struct berval digest;
3272         digest.bv_val = HASHdigest;
3273         digest.bv_len = sizeof(HASHdigest);
3274
3275         /* we should have at least one value at this point */
3276         assert( values != NULL && values[0] != NULL );
3277
3278         nkeys=0;
3279         for( i=0; values[i] != NULL; i++ ) {
3280                 /* count number of indices to generate */
3281                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
3282                         continue;
3283                 }
3284
3285                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
3286                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3287                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
3288                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
3289                         } else {
3290                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
3291                         }
3292                 }
3293
3294                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
3295                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3296                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
3297                         }
3298                 }
3299
3300                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
3301                         if( values[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3302                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
3303                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
3304                         } else {
3305                                 nkeys += values[i]->bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
3306                         }
3307                 }
3308         }
3309
3310         if( nkeys == 0 ) {
3311                 /* no keys to generate */
3312                 *keysp = NULL;
3313                 return LDAP_SUCCESS;
3314         }
3315
3316         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
3317
3318         slen = strlen( syntax->ssyn_oid );
3319         mlen = strlen( mr->smr_oid );
3320
3321         nkeys=0;
3322         for( i=0; values[i] != NULL; i++ ) {
3323                 int j,max;
3324                 struct berval *value;
3325
3326                 if( values[i]->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
3327
3328                 value = ber_bvdup( values[i] );
3329                 ldap_pvt_str2upper( value->bv_val );
3330
3331                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
3332                         ( value->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
3333                 {
3334                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
3335                         max = value->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
3336
3337                         for( j=0; j<max; j++ ) {
3338                                 HASH_Init( &HASHcontext );
3339                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3340                                         HASH_Update( &HASHcontext,
3341                                                 prefix->bv_val, prefix->bv_len );
3342                                 }
3343
3344                                 HASH_Update( &HASHcontext,
3345                                         &pre, sizeof( pre ) );
3346                                 HASH_Update( &HASHcontext,
3347                                         syntax->ssyn_oid, slen );
3348                                 HASH_Update( &HASHcontext,
3349                                         mr->smr_oid, mlen );
3350                                 HASH_Update( &HASHcontext,
3351                                         &value->bv_val[j],
3352                                         SLAP_INDEX_SUBSTR_MAXLEN );
3353                                 HASH_Final( HASHdigest, &HASHcontext );
3354
3355                                 keys[nkeys++] = ber_bvdup( &digest );
3356                         }
3357                 }
3358
3359                 max = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
3360                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
3361
3362                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
3363                         char pre;
3364
3365                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
3366                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
3367                                 HASH_Init( &HASHcontext );
3368                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3369                                         HASH_Update( &HASHcontext,
3370                                                 prefix->bv_val, prefix->bv_len );
3371                                 }
3372                                 HASH_Update( &HASHcontext,
3373                                         &pre, sizeof( pre ) );
3374                                 HASH_Update( &HASHcontext,
3375                                         syntax->ssyn_oid, slen );
3376                                 HASH_Update( &HASHcontext,
3377                                         mr->smr_oid, mlen );
3378                                 HASH_Update( &HASHcontext,
3379                                         value->bv_val, j );
3380                                 HASH_Final( HASHdigest, &HASHcontext );
3381
3382                                 keys[nkeys++] = ber_bvdup( &digest );
3383                         }
3384
3385                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
3386                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
3387                                 HASH_Init( &HASHcontext );
3388                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3389                                         HASH_Update( &HASHcontext,
3390                                                 prefix->bv_val, prefix->bv_len );
3391                                 }
3392                                 HASH_Update( &HASHcontext,
3393                                         &pre, sizeof( pre ) );
3394                                 HASH_Update( &HASHcontext,
3395                                         syntax->ssyn_oid, slen );
3396                                 HASH_Update( &HASHcontext,
3397                                         mr->smr_oid, mlen );
3398                                 HASH_Update( &HASHcontext,
3399                                         &value->bv_val[value->bv_len-j], j );
3400                                 HASH_Final( HASHdigest, &HASHcontext );
3401
3402                                 keys[nkeys++] = ber_bvdup( &digest );
3403                         }
3404
3405                 }
3406
3407                 ber_bvfree( value );
3408         }
3409
3410         if( nkeys > 0 ) {
3411                 keys[nkeys] = NULL;
3412                 *keysp = keys;
3413         } else {
3414                 ch_free( keys );
3415                 *keysp = NULL;
3416         }
3417
3418         return LDAP_SUCCESS;
3419 }
3420
3421 int caseIgnoreIA5SubstringsFilter(
3422         slap_mask_t use,
3423         slap_mask_t flags,
3424         Syntax *syntax,
3425         MatchingRule *mr,
3426         struct berval *prefix,
3427         void * assertValue,
3428         struct berval ***keysp )
3429 {
3430         SubstringsAssertion *sa = assertValue;
3431         char pre;
3432         ber_len_t nkeys = 0;
3433         size_t slen, mlen, klen;
3434         struct berval **keys;
3435         HASH_CONTEXT   HASHcontext;
3436         unsigned char   HASHdigest[HASH_BYTES];
3437         struct berval *value;
3438         struct berval digest;
3439
3440         if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial != NULL &&
3441                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3442         {
3443                 nkeys++;
3444         }
3445
3446         if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
3447                 ber_len_t i;
3448                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
3449                         if( sa->sa_any[i]->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3450                                 /* don't bother accounting for stepping */
3451                                 nkeys += sa->sa_any[i]->bv_len -
3452                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
3453                         }
3454                 }
3455         }
3456
3457         if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final != NULL &&
3458                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3459         {
3460                 nkeys++;
3461         }
3462
3463         if( nkeys == 0 ) {
3464                 *keysp = NULL;
3465                 return LDAP_SUCCESS;
3466         }
3467
3468         digest.bv_val = HASHdigest;
3469         digest.bv_len = sizeof(HASHdigest);
3470
3471         slen = strlen( syntax->ssyn_oid );
3472         mlen = strlen( mr->smr_oid );
3473
3474         keys = ch_malloc( sizeof( struct berval * ) * (nkeys+1) );
3475         nkeys = 0;
3476
3477         if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial != NULL &&
3478                 sa->sa_initial->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3479         {
3480                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
3481                 value = ber_bvdup( sa->sa_initial );
3482                 ldap_pvt_str2upper( value->bv_val );
3483
3484                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
3485                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
3486
3487                 HASH_Init( &HASHcontext );
3488                 if( prefix != NULL && prefix->bv_len > 0 ) {
3489                         HASH_Update( &HASHcontext,
3490                                 prefix->bv_val, prefix->bv_len );
3491                 }
3492                 HASH_Update( &HASHcontext,
3493                         &pre, sizeof( pre ) );
3494                 HASH_Update( &HASHcontext,
3495                         syntax->ssyn_oid, slen );
3496                 HASH_Update( &HASHcontext,
3497                         mr->smr_oid, mlen );
3498                 HASH_Update( &HASHcontext,
3499                         value->bv_val, klen );
3500                 HASH_Final( HASHdigest, &HASHcontext );
3501
3502                 ber_bvfree( value );
3503                 keys[nkeys++] = ber_bvdup( &digest );
3504         }
3505
3506         if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
3507                 ber_len_t i, j;
3508                 pre = SLAP_INDEX_SUBSTR_PREFIX;
3509                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
3510
3511                 for( i=0; sa->sa_any[i] != NULL; i++ ) {
3512                         if( sa->sa_any[i]->bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
3513                                 continue;
3514                         }
3515
3516                         value = ber_bvdup( sa->sa_any[i] );
3517                         ldap_pvt_str2upper( value->bv_val );
3518
3519                         for(j=0;
3520                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
3521                                 j += SLAP_INDEX_SUBSTR_STEP )
3522                         {
3523                                 HASH_Init( &HASHcontext );
3524                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3525                                         HASH_Update( &HASHcontext,
3526                                                 prefix->bv_val, prefix->bv_len );
3527                                 }
3528                                 HASH_Update( &HASHcontext,
3529                                         &pre, sizeof( pre ) );
3530                                 HASH_Update( &HASHcontext,
3531                                         syntax->ssyn_oid, slen );
3532                                 HASH_Update( &HASHcontext,
3533                                         mr->smr_oid, mlen );
3534                                 HASH_Update( &HASHcontext,
3535                                         &value->bv_val[j], klen );
3536                                 HASH_Final( HASHdigest, &HASHcontext );
3537
3538                                 keys[nkeys++] = ber_bvdup( &digest );
3539                         }
3540
3541                         ber_bvfree( value );
3542                 }
3543         }
3544
3545         if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final != NULL &&
3546                 sa->sa_final->bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3547         {
3548                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
3549                 value = ber_bvdup( sa->sa_final );
3550                 ldap_pvt_str2upper( value->bv_val );
3551
3552                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
3553                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
3554
3555                 HASH_Init( &HASHcontext );
3556                 if( prefix != NULL && prefix->bv_len > 0 ) {
3557                         HASH_Update( &HASHcontext,
3558                                 prefix->bv_val, prefix->bv_len );
3559                 }
3560                 HASH_Update( &HASHcontext,
3561                         &pre, sizeof( pre ) );
3562                 HASH_Update( &HASHcontext,
3563                         syntax->ssyn_oid, slen );
3564                 HASH_Update( &HASHcontext,
3565                         mr->smr_oid, mlen );
3566                 HASH_Update( &HASHcontext,
3567                         &value->bv_val[value->bv_len-klen], klen );
3568                 HASH_Final( HASHdigest, &HASHcontext );
3569
3570                 ber_bvfree( value );
3571                 keys[nkeys++] = ber_bvdup( &digest );
3572         }
3573
3574         if( nkeys > 0 ) {
3575                 keys[nkeys] = NULL;
3576                 *keysp = keys;
3577         } else {
3578                 ch_free( keys );
3579                 *keysp = NULL;
3580         }
3581
3582         return LDAP_SUCCESS;
3583 }
3584         
3585 static int
3586 numericStringValidate(
3587         Syntax *syntax,
3588         struct berval *in )
3589 {
3590         ber_len_t i;
3591
3592         for(i=0; i < in->bv_len; i++) {
3593                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
3594                         return LDAP_INVALID_SYNTAX;
3595                 }
3596         }
3597
3598         return LDAP_SUCCESS;
3599 }
3600
3601 static int
3602 numericStringNormalize(
3603         Syntax *syntax,
3604         struct berval *val,
3605         struct berval **normalized )
3606 {
3607         /* removal all spaces */
3608         struct berval *newval;
3609         char *p, *q;
3610
3611         newval = ch_malloc( sizeof( struct berval ) );
3612         newval->bv_val = ch_malloc( val->bv_len + 1 );
3613
3614         p = val->bv_val;
3615         q = newval->bv_val;
3616
3617         while ( *p ) {
3618                 if ( ASCII_SPACE( *p ) ) {
3619                         /* Ignore whitespace */
3620                         p++;
3621                 } else {
3622                         *q++ = *p++;
3623                 }
3624         }
3625
3626         assert( newval->bv_val <= p );
3627         assert( q <= p );
3628
3629         /* null terminate */
3630         *q = '\0';
3631
3632         newval->bv_len = q - newval->bv_val;
3633         *normalized = newval;
3634
3635         return LDAP_SUCCESS;
3636 }
3637
3638 static int
3639 objectIdentifierFirstComponentMatch(
3640         int *matchp,
3641         slap_mask_t flags,
3642         Syntax *syntax,
3643         MatchingRule *mr,
3644         struct berval *value,
3645         void *assertedValue )
3646 {
3647         int rc = LDAP_SUCCESS;
3648         int match;
3649         struct berval *asserted = (struct berval *) assertedValue;
3650         ber_len_t i;
3651         struct berval oid;
3652
3653         if( value->bv_len == 0 || value->bv_val[0] != '(' /*')'*/ ) {
3654                 return LDAP_INVALID_SYNTAX;
3655         }
3656
3657         /* trim leading white space */
3658         for( i=1; ASCII_SPACE(value->bv_val[i]) && i < value->bv_len; i++ ) {
3659                 /* empty */
3660         }
3661
3662         /* grab next word */
3663         oid.bv_val = &value->bv_val[i];
3664         oid.bv_len = value->bv_len - i;
3665         for( i=1; ASCII_SPACE(value->bv_val[i]) && i < oid.bv_len; i++ ) {
3666                 /* empty */
3667         }
3668         oid.bv_len = i;
3669
3670         /* insert attributeTypes, objectclass check here */
3671         if( OID_LEADCHAR(asserted->bv_val[0]) ) {
3672                 rc = objectIdentifierMatch( &match, flags, syntax, mr, &oid, asserted );
3673
3674         } else {
3675                 char *stored = ch_malloc( oid.bv_len + 1 );
3676                 AC_MEMCPY( stored, oid.bv_val, oid.bv_len );
3677                 stored[oid.bv_len] = '\0';
3678
3679                 if ( !strcmp( syntax->ssyn_oid, SLAP_SYNTAX_MATCHINGRULES_OID ) ) {
3680                         MatchingRule *asserted_mr = mr_find( asserted->bv_val );
3681                         MatchingRule *stored_mr = mr_find( stored );
3682
3683                         if( asserted_mr == NULL ) {
3684                                 rc = SLAPD_COMPARE_UNDEFINED;
3685                         } else {
3686                                 match = asserted_mr != stored_mr;
3687                         }
3688
3689                 } else if ( !strcmp( syntax->ssyn_oid,
3690                         SLAP_SYNTAX_ATTRIBUTETYPES_OID ) )
3691                 {
3692                         AttributeType *asserted_at = at_find( asserted->bv_val );
3693                         AttributeType *stored_at = at_find( stored );
3694
3695                         if( asserted_at == NULL ) {
3696                                 rc = SLAPD_COMPARE_UNDEFINED;
3697                         } else {
3698                                 match = asserted_at != stored_at;
3699                         }
3700
3701                 } else if ( !strcmp( syntax->ssyn_oid,
3702                         SLAP_SYNTAX_OBJECTCLASSES_OID ) )
3703                 {
3704                         ObjectClass *asserted_oc = oc_find( asserted->bv_val );
3705                         ObjectClass *stored_oc = oc_find( stored );
3706
3707                         if( asserted_oc == NULL ) {
3708                                 rc = SLAPD_COMPARE_UNDEFINED;
3709                         } else {
3710                                 match = asserted_oc != stored_oc;
3711                         }
3712                 }
3713
3714                 ch_free( stored );
3715         }
3716
3717 #ifdef NEW_LOGGING
3718         LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
3719                    "objectIdentifierFirstComponentMatch: %d\n    %s\n    %s\n",
3720                    match, value->bv_val, asserted->bv_val ));
3721 #else
3722         Debug( LDAP_DEBUG_ARGS, "objectIdentifierFirstComponentMatch "
3723                 "%d\n\t\"%s\"\n\t\"%s\"\n",
3724                 match, value->bv_val, asserted->bv_val );
3725 #endif
3726
3727
3728         if( rc == LDAP_SUCCESS ) *matchp = match;
3729         return rc;
3730 }
3731
3732 static int
3733 check_time_syntax (struct berval *val,
3734         int start,
3735         int *parts)
3736 {
3737         static int ceiling[9] = { 99, 99, 11, 30, 23, 59, 59, 12, 59 };
3738         static int mdays[2][12] = {
3739                 /* non-leap years */
3740                 { 30, 27, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 },
3741                 /* leap years */
3742                 { 30, 28, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 }
3743         };
3744         char *p, *e;
3745         int part, c, tzoffset, leapyear = 0 ;
3746
3747         if( val->bv_len == 0 ) {
3748                 return LDAP_INVALID_SYNTAX;
3749         }
3750
3751         p = (char *)val->bv_val;
3752         e = p + val->bv_len;
3753
3754         /* Ignore initial whitespace */
3755         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
3756                 p++;
3757         }
3758
3759         if (e - p < 13 - (2 * start)) {
3760                 return LDAP_INVALID_SYNTAX;
3761         }
3762
3763         for (part = 0; part < 9; part++) {
3764                 parts[part] = 0;
3765         }
3766
3767         for (part = start; part < 7; part++) {
3768                 c = *p;
3769                 if ((part == 6) && (c == 'Z' || c == '+' || c == '-')) {
3770                         part++;
3771                         break;
3772                 }
3773                 p++;
3774                 c -= '0';
3775                 if (p == e) {
3776                         return LDAP_INVALID_SYNTAX;
3777                 }
3778                 if (c < 0 || c > 9) {
3779                         return LDAP_INVALID_SYNTAX;
3780                 }
3781                 parts[part] = c;
3782
3783                 c = *p++ - '0';
3784                 if (p == e) {
3785                         return LDAP_INVALID_SYNTAX;
3786                 }
3787                 if (c < 0 || c > 9) {
3788                         return LDAP_INVALID_SYNTAX;
3789                 }
3790                 parts[part] *= 10;
3791                 parts[part] += c;
3792
3793                 if (part == 2 || part == 3) {
3794                         parts[part]--;
3795                 }
3796                 if (parts[part] < 0) {
3797                         return LDAP_INVALID_SYNTAX;
3798                 }
3799                 if (parts[part] > ceiling[part]) {
3800                         return LDAP_INVALID_SYNTAX;
3801                 }
3802         }
3803
3804         /* leapyear check for the Gregorian calendar (year>1581) */
3805         if (((parts[1] % 4 == 0) && (parts[1] != 0)) ||
3806                 ((parts[0] % 4 == 0) && (parts[1] == 0)))
3807         {
3808                 leapyear = 1;
3809         }
3810
3811         if (parts[3] > mdays[leapyear][parts[2]]) {
3812                 return LDAP_INVALID_SYNTAX;
3813         }
3814         
3815         c = *p++;
3816         if (c == 'Z') {
3817                 tzoffset = 0; /* UTC */
3818         } else if (c != '+' && c != '-') {
3819                 return LDAP_INVALID_SYNTAX;
3820         } else {
3821                 if (c == '-') {
3822                         tzoffset = -1;
3823                 } else /* c == '+' */ {
3824                         tzoffset = 1;
3825                 }
3826
3827                 if (p > e - 4) {
3828                         return LDAP_INVALID_SYNTAX;
3829                 }
3830
3831                 for (part = 7; part < 9; part++) {
3832                         c = *p++ - '0';
3833                         if (c < 0 || c > 9) {
3834                                 return LDAP_INVALID_SYNTAX;
3835                         }
3836                         parts[part] = c;
3837
3838                         c = *p++ - '0';
3839                         if (c < 0 || c > 9) {
3840                                 return LDAP_INVALID_SYNTAX;
3841                         }
3842                         parts[part] *= 10;
3843                         parts[part] += c;
3844                         if (parts[part] < 0 || parts[part] > ceiling[part]) {
3845                                 return LDAP_INVALID_SYNTAX;
3846                         }
3847                 }
3848         }
3849
3850         /* Ignore trailing whitespace */
3851         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
3852                 p++;
3853         }
3854         if (p != e) {
3855                 return LDAP_INVALID_SYNTAX;
3856         }
3857
3858         switch ( tzoffset ) {
3859         case -1: /* negativ offset to UTC, ie west of Greenwich  */
3860                 parts[4] += parts[7];
3861                 parts[5] += parts[8];
3862                 for (part = 6; --part > 0; ) { /* offset is just hhmm, no seconds */
3863                         if (part != 3) {
3864                                 c = ceiling[part];
3865                         } else {
3866                                 c = mdays[leapyear][parts[2]];
3867                         }
3868                         if (parts[part] > c) {
3869                                 parts[part] -= c + 1;
3870                                 parts[part - 1]++;
3871                         }
3872                 }
3873                 break;
3874         case 1: /* positive offset to UTC, ie east of Greenwich */
3875                 parts[4] -= parts[7];
3876                 parts[5] -= parts[8];
3877                 for (part = 6; --part > 0; ) {
3878                         if (part != 3) {
3879                                 c = ceiling[part];
3880                         } else {
3881                                 /* first arg to % needs to be non negativ */
3882                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
3883                         }
3884                         if (parts[part] < 0) {
3885                                 parts[part] += c + 1;
3886                                 parts[part - 1]--;
3887                         }
3888                 }
3889                 break;
3890         case 0: /* already UTC */
3891                 break;
3892         }
3893
3894         return LDAP_SUCCESS;
3895 }
3896
3897 static int
3898 utcTimeNormalize(
3899         Syntax *syntax,
3900         struct berval *val,
3901         struct berval **normalized )
3902 {
3903         struct berval *out;
3904         int parts[9], rc;
3905
3906         rc = check_time_syntax(val, 1, parts);
3907         if (rc != LDAP_SUCCESS) {
3908                 return rc;
3909         }
3910
3911         *normalized = NULL;
3912         out = ch_malloc( sizeof(struct berval) );
3913         if( out == NULL ) {
3914                 return LBER_ERROR_MEMORY;
3915         }
3916
3917         out->bv_val = ch_malloc( 14 );
3918         if ( out->bv_val == NULL ) {
3919                 ch_free( out );
3920                 return LBER_ERROR_MEMORY;
3921         }
3922
3923         sprintf( out->bv_val, "%02ld%02ld%02ld%02ld%02ld%02ldZ",
3924                 parts[1], parts[2] + 1, parts[3] + 1,
3925                 parts[4], parts[5], parts[6] );
3926         out->bv_len = 13;
3927         *normalized = out;
3928
3929         return LDAP_SUCCESS;
3930 }
3931
3932 static int
3933 utcTimeValidate(
3934         Syntax *syntax,
3935         struct berval *in )
3936 {
3937         int parts[9];
3938
3939         return check_time_syntax(in, 1, parts);
3940 }
3941
3942 static int
3943 generalizedTimeValidate(
3944         Syntax *syntax,
3945         struct berval *in )
3946 {
3947         int parts[9];
3948
3949         return check_time_syntax(in, 0, parts);
3950 }
3951
3952 static int
3953 generalizedTimeNormalize(
3954         Syntax *syntax,
3955         struct berval *val,
3956         struct berval **normalized )
3957 {
3958         struct berval *out;
3959         int parts[9], rc;
3960
3961         rc = check_time_syntax(val, 0, parts);
3962         if (rc != LDAP_SUCCESS) {
3963                 return rc;
3964         }
3965
3966         *normalized = NULL;
3967         out = ch_malloc( sizeof(struct berval) );
3968         if( out == NULL ) {
3969                 return LBER_ERROR_MEMORY;
3970         }
3971
3972         out->bv_val = ch_malloc( 16 );
3973         if ( out->bv_val == NULL ) {
3974                 ch_free( out );
3975                 return LBER_ERROR_MEMORY;
3976         }
3977
3978         sprintf( out->bv_val, "%02ld%02ld%02ld%02ld%02ld%02ld%02ldZ",
3979                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
3980                 parts[4], parts[5], parts[6] );
3981         out->bv_len = 15;
3982         *normalized = out;
3983
3984         return LDAP_SUCCESS;
3985 }
3986
3987 static int
3988 nisNetgroupTripleValidate(
3989         Syntax *syntax,
3990         struct berval *val )
3991 {
3992         char *p, *e;
3993         int commas = 0;
3994
3995         if ( val->bv_len == 0 ) {
3996                 return LDAP_INVALID_SYNTAX;
3997         }
3998
3999         p = (char *)val->bv_val;
4000         e = p + val->bv_len;
4001
4002         if ( *p != '(' /*')'*/ ) {
4003                 return LDAP_INVALID_SYNTAX;
4004         }
4005
4006         for ( p++; ( p < e ) && ( *p != ')' ); p++ ) {
4007                 if ( *p == ',' ) {
4008                         commas++;
4009                         if ( commas > 2 ) {
4010                                 return LDAP_INVALID_SYNTAX;
4011                         }
4012
4013                 } else if ( !ATTR_CHAR( *p ) ) {
4014                         return LDAP_INVALID_SYNTAX;
4015                 }
4016         }
4017
4018         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4019                 return LDAP_INVALID_SYNTAX;
4020         }
4021
4022         p++;
4023
4024         if (p != e) {
4025                 return LDAP_INVALID_SYNTAX;
4026         }
4027
4028         return LDAP_SUCCESS;
4029 }
4030
4031 static int
4032 bootParameterValidate(
4033         Syntax *syntax,
4034         struct berval *val )
4035 {
4036         char *p, *e;
4037
4038         if ( val->bv_len == 0 ) {
4039                 return LDAP_INVALID_SYNTAX;
4040         }
4041
4042         p = (char *)val->bv_val;
4043         e = p + val->bv_len;
4044
4045         /* key */
4046         for (; ( p < e ) && ( *p != '=' ); p++ ) {
4047                 if ( !ATTR_CHAR( *p ) ) {
4048                         return LDAP_INVALID_SYNTAX;
4049                 }
4050         }
4051
4052         if ( *p != '=' ) {
4053                 return LDAP_INVALID_SYNTAX;
4054         }
4055
4056         /* server */
4057         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4058                 if ( !ATTR_CHAR( *p ) ) {
4059                         return LDAP_INVALID_SYNTAX;
4060                 }
4061         }
4062
4063         if ( *p != ':' ) {
4064                 return LDAP_INVALID_SYNTAX;
4065         }
4066
4067         /* path */
4068         for ( p++; p < e; p++ ) {
4069                 if ( !ATTR_CHAR( *p ) ) {
4070                         return LDAP_INVALID_SYNTAX;
4071                 }
4072         }
4073
4074         return LDAP_SUCCESS;
4075 }
4076
4077 struct syntax_defs_rec {
4078         char *sd_desc;
4079         int sd_flags;
4080         slap_syntax_validate_func *sd_validate;
4081         slap_syntax_transform_func *sd_normalize;
4082         slap_syntax_transform_func *sd_pretty;
4083 #ifdef SLAPD_BINARY_CONVERSION
4084         slap_syntax_transform_func *sd_ber2str;
4085         slap_syntax_transform_func *sd_str2ber;
4086 #endif
4087 };
4088
4089 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4090 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4091
4092 struct syntax_defs_rec syntax_defs[] = {
4093         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' " X_BINARY X_NOT_H_R ")",
4094                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4095         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4096                 0, NULL, NULL, NULL},
4097         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4098                 0, NULL, NULL, NULL},
4099         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' " X_NOT_H_R ")",
4100                 SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
4101         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' " X_NOT_H_R ")",
4102                 SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4103         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4104                 0, bitStringValidate, NULL, NULL },
4105         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4106                 0, booleanValidate, NULL, NULL},
4107         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4108                 X_BINARY X_NOT_H_R ")",
4109                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4110         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4111                 X_BINARY X_NOT_H_R ")",
4112                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4113         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4114                 X_BINARY X_NOT_H_R ")",
4115                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4116         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4117                 0, countryStringValidate, IA5StringNormalize, NULL},
4118         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4119                 0, dnValidate, dnNormalize, dnPretty},
4120         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4121                 0, NULL, NULL, NULL},
4122         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4123                 0, NULL, NULL, NULL},
4124         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4125                 0, UTF8StringValidate, UTF8StringNormalize, NULL},
4126         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4127                 0, NULL, NULL, NULL},
4128         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4129                 0, NULL, NULL, NULL},
4130         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4131                 0, NULL, NULL, NULL},
4132         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4133                 0, NULL, NULL, NULL},
4134         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4135                 0, NULL, NULL, NULL},
4136         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4137                 0, printablesStringValidate, IA5StringNormalize, NULL},
4138         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4139                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4140         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4141                 0, generalizedTimeValidate, generalizedTimeNormalize, NULL},
4142         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4143                 0, NULL, NULL, NULL},
4144         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4145                 0, IA5StringValidate, IA5StringNormalize, NULL},
4146         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4147                 0, integerValidate, integerNormalize, integerPretty},
4148         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4149                 SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
4150         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4151                 0, NULL, NULL, NULL},
4152         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4153                 0, NULL, NULL, NULL},
4154         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4155                 0, NULL, NULL, NULL},
4156         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4157                 0, NULL, NULL, NULL},
4158         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4159                 0, NULL, NULL, NULL},
4160         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4161                 0, nameUIDValidate, nameUIDNormalize, NULL},
4162         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4163                 0, NULL, NULL, NULL},
4164         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4165                 0, numericStringValidate, numericStringNormalize, NULL},
4166         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4167                 0, NULL, NULL, NULL},
4168         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4169                 0, oidValidate, NULL, NULL},
4170         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4171                 0, IA5StringValidate, IA5StringNormalize, NULL},
4172         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4173                 0, blobValidate, NULL, NULL},
4174         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4175                 0, UTF8StringValidate, UTF8StringNormalize, NULL},
4176         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4177                 0, NULL, NULL, NULL},
4178         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4179                 0, NULL, NULL, NULL},
4180         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4181                 0, printableStringValidate, IA5StringNormalize, NULL},
4182         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4183                 X_BINARY X_NOT_H_R ")",
4184                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4185         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4186                 0, printableStringValidate, IA5StringNormalize, NULL},
4187         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4188                 0, NULL, NULL, NULL},
4189         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4190                 0, printableStringValidate, IA5StringNormalize, NULL},
4191         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4192                 0, utcTimeValidate, utcTimeNormalize, NULL},
4193         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4194                 0, NULL, NULL, NULL},
4195         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4196                 0, NULL, NULL, NULL},
4197         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4198                 0, NULL, NULL, NULL},
4199         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4200                 0, NULL, NULL, NULL},
4201         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4202                 0, NULL, NULL, NULL},
4203
4204         /* RFC 2307 NIS Syntaxes */
4205         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4206                 0, nisNetgroupTripleValidate, NULL, NULL},
4207         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4208                 0, bootParameterValidate, NULL, NULL},
4209
4210         /* OpenLDAP Experimental Syntaxes */
4211         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
4212                 0, UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
4213                 NULL, NULL},
4214         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4215                 0, NULL, NULL, NULL},
4216
4217         /* OpenLDAP Void Syntax */
4218         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4219                 SLAP_SYNTAX_HIDE, inValidate, NULL, NULL},
4220         {NULL, 0, NULL, NULL, NULL}
4221 };
4222
4223 struct mrule_defs_rec {
4224         char *                                          mrd_desc;
4225         slap_mask_t                                     mrd_usage;
4226         slap_mr_convert_func *          mrd_convert;
4227         slap_mr_normalize_func *        mrd_normalize;
4228         slap_mr_match_func *            mrd_match;
4229         slap_mr_indexer_func *          mrd_indexer;
4230         slap_mr_filter_func *           mrd_filter;
4231
4232         char *                                          mrd_associated;
4233 };
4234
4235 /*
4236  * Other matching rules in X.520 that we do not use (yet):
4237  *
4238  * 2.5.13.9             numericStringOrderingMatch
4239  * 2.5.13.15    integerOrderingMatch
4240  * 2.5.13.18    octetStringOrderingMatch
4241  * 2.5.13.19    octetStringSubstringsMatch
4242  * 2.5.13.25    uTCTimeMatch
4243  * 2.5.13.26    uTCTimeOrderingMatch
4244  * 2.5.13.31    directoryStringFirstComponentMatch
4245  * 2.5.13.32    wordMatch
4246  * 2.5.13.33    keywordMatch
4247  * 2.5.13.34    certificateExactMatch
4248  * 2.5.13.35    certificateMatch
4249  * 2.5.13.36    certificatePairExactMatch
4250  * 2.5.13.37    certificatePairMatch
4251  * 2.5.13.38    certificateListExactMatch
4252  * 2.5.13.39    certificateListMatch
4253  * 2.5.13.40    algorithmIdentifierMatch
4254  * 2.5.13.41    storedPrefixMatch
4255  * 2.5.13.42    attributeCertificateMatch
4256  * 2.5.13.43    readerAndKeyIDMatch
4257  * 2.5.13.44    attributeIntegrityMatch
4258  */
4259
4260 struct mrule_defs_rec mrule_defs[] = {
4261         /*
4262          * EQUALITY matching rules must be listed after associated APPROX
4263          * matching rules.  So, we list all APPROX matching rules first.
4264          */
4265         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4266                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4267                 SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT,
4268                 NULL, NULL,
4269                 directoryStringApproxMatch,
4270                 directoryStringApproxIndexer, 
4271                 directoryStringApproxFilter,
4272                 NULL},
4273
4274         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4275                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4276                 SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT,
4277                 NULL, NULL,
4278                 IA5StringApproxMatch,
4279                 IA5StringApproxIndexer, 
4280                 IA5StringApproxFilter,
4281                 NULL},
4282
4283         /*
4284          * Other matching rules
4285          */
4286         
4287         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4288                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4289                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4290                 NULL, NULL,
4291                 objectIdentifierMatch, caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
4292                 NULL},
4293
4294         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4295                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4296                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4297                 NULL, NULL,
4298                 dnMatch, dnIndexer, dnFilter,
4299                 NULL},
4300
4301         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4302                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4303                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4304                 NULL, NULL,
4305                 caseIgnoreMatch, caseIgnoreIndexer, caseIgnoreFilter,
4306                 directoryStringApproxMatchOID },
4307
4308         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4309                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4310                 SLAP_MR_ORDERING,
4311                 NULL, NULL,
4312                 caseIgnoreOrderingMatch, NULL, NULL,
4313                 NULL},
4314
4315         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4316                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4317                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4318                 NULL, NULL,
4319                 caseIgnoreSubstringsMatch,
4320                 caseIgnoreSubstringsIndexer,
4321                 caseIgnoreSubstringsFilter,
4322                 NULL},
4323
4324         {"( 2.5.13.5 NAME 'caseExactMatch' "
4325                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4326                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4327                 NULL, NULL,
4328                 caseExactMatch, caseExactIndexer, caseExactFilter,
4329                 directoryStringApproxMatchOID },
4330
4331         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4332                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4333                 SLAP_MR_ORDERING,
4334                 NULL, NULL,
4335                 caseExactOrderingMatch, NULL, NULL,
4336                 NULL},
4337
4338         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4339                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4340                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4341                 NULL, NULL,
4342                 caseExactSubstringsMatch,
4343                 caseExactSubstringsIndexer,
4344                 caseExactSubstringsFilter,
4345                 NULL},
4346
4347         {"( 2.5.13.8 NAME 'numericStringMatch' "
4348                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4349                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4350                 NULL, NULL,
4351                 caseIgnoreIA5Match,
4352                 caseIgnoreIA5Indexer,
4353                 caseIgnoreIA5Filter,
4354                 NULL},
4355
4356         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4357                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4358                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4359                 NULL, NULL,
4360                 caseIgnoreIA5SubstringsMatch,
4361                 caseIgnoreIA5SubstringsIndexer,
4362                 caseIgnoreIA5SubstringsFilter,
4363                 NULL},
4364
4365         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4366                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4367                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4368                 NULL, NULL,
4369                 caseIgnoreListMatch, NULL, NULL,
4370                 NULL},
4371
4372         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4373                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4374                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4375                 NULL, NULL,
4376                 caseIgnoreListSubstringsMatch, NULL, NULL,
4377                 NULL},
4378
4379         {"( 2.5.13.13 NAME 'booleanMatch' "
4380                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4381                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4382                 NULL, NULL,
4383                 booleanMatch, NULL, NULL,
4384                 NULL},
4385
4386         {"( 2.5.13.14 NAME 'integerMatch' "
4387                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4388                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4389                 NULL, NULL,
4390                 integerMatch, integerIndexer, integerFilter,
4391                 NULL},
4392
4393         {"( 2.5.13.16 NAME 'bitStringMatch' "
4394                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4395                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4396                 NULL, NULL,
4397                 bitStringMatch, NULL, NULL,
4398                 NULL},
4399
4400         {"( 2.5.13.17 NAME 'octetStringMatch' "
4401                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4402                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4403                 NULL, NULL,
4404                 octetStringMatch, octetStringIndexer, octetStringFilter,
4405                 NULL},
4406
4407         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
4408                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
4409                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4410                 NULL, NULL,
4411                 telephoneNumberMatch,
4412                 telephoneNumberIndexer,
4413                 telephoneNumberFilter,
4414                 NULL},
4415
4416         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
4417                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4418                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4419                 NULL, NULL,
4420                 telephoneNumberSubstringsMatch,
4421                 telephoneNumberSubstringsIndexer,
4422                 telephoneNumberSubstringsFilter,
4423                 NULL},
4424
4425         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
4426                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
4427                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4428                 NULL, NULL,
4429                 NULL, NULL, NULL,
4430                 NULL},
4431
4432         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
4433                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
4434                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4435                 NULL, NULL,
4436                 uniqueMemberMatch, NULL, NULL,
4437                 NULL},
4438
4439         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
4440                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
4441                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4442                 NULL, NULL,
4443                 protocolInformationMatch, NULL, NULL,
4444                 NULL},
4445
4446         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
4447                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4448                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4449                 NULL, NULL,
4450                 generalizedTimeMatch, NULL, NULL,
4451                 NULL},
4452
4453         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
4454                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4455                 SLAP_MR_ORDERING,
4456                 NULL, NULL,
4457                 generalizedTimeOrderingMatch, NULL, NULL,
4458                 NULL},
4459
4460         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
4461                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4462                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4463                 NULL, NULL,
4464                 integerFirstComponentMatch, NULL, NULL,
4465                 NULL},
4466
4467         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
4468                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4469                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4470                 NULL, NULL,
4471                 objectIdentifierFirstComponentMatch, NULL, NULL,
4472                 NULL},
4473
4474         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
4475                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4476                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4477                 NULL, NULL,
4478                 caseExactIA5Match, caseExactIA5Indexer, caseExactIA5Filter,
4479                 IA5StringApproxMatchOID },
4480
4481         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
4482                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4483                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4484                 NULL, NULL,
4485                 caseIgnoreIA5Match, caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
4486                 IA5StringApproxMatchOID },
4487
4488         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
4489                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4490                 SLAP_MR_SUBSTR,
4491                 NULL, NULL,
4492                 caseIgnoreIA5SubstringsMatch,
4493                 caseIgnoreIA5SubstringsIndexer,
4494                 caseIgnoreIA5SubstringsFilter,
4495                 NULL},
4496
4497         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
4498                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4499                 SLAP_MR_SUBSTR,
4500                 NULL, NULL,
4501                 caseExactIA5SubstringsMatch,
4502                 caseExactIA5SubstringsIndexer,
4503                 caseExactIA5SubstringsFilter,
4504                 NULL},
4505
4506         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
4507                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4508                 SLAP_MR_EQUALITY,
4509                 NULL, NULL,
4510                 authPasswordMatch, NULL, NULL,
4511                 NULL},
4512
4513         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
4514                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
4515                 SLAP_MR_EQUALITY,
4516                 NULL, NULL,
4517                 OpenLDAPaciMatch, NULL, NULL,
4518                 NULL},
4519
4520         {NULL, SLAP_MR_NONE, NULL, NULL, NULL, NULL}
4521 };
4522
4523 int
4524 schema_init( void )
4525 {
4526         int             res;
4527         int             i;
4528
4529         /* we should only be called once (from main) */
4530         assert( schema_init_done == 0 );
4531
4532         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
4533                 res = register_syntax( syntax_defs[i].sd_desc,
4534                         syntax_defs[i].sd_flags,
4535                         syntax_defs[i].sd_validate,
4536                         syntax_defs[i].sd_normalize,
4537                         syntax_defs[i].sd_pretty
4538 #ifdef SLAPD_BINARY_CONVERSION
4539                         ,
4540                         syntax_defs[i].sd_ber2str,
4541                         syntax_defs[i].sd_str2ber
4542 #endif
4543                 );
4544
4545                 if ( res ) {
4546                         fprintf( stderr, "schema_init: Error registering syntax %s\n",
4547                                  syntax_defs[i].sd_desc );
4548                         return LDAP_OTHER;
4549                 }
4550         }
4551
4552         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
4553                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE ) {
4554                         fprintf( stderr,
4555                                 "schema_init: Ingoring unusable matching rule %s\n",
4556                                  mrule_defs[i].mrd_desc );
4557                         continue;
4558                 }
4559
4560                 res = register_matching_rule(
4561                         mrule_defs[i].mrd_desc,
4562                         mrule_defs[i].mrd_usage,
4563                         mrule_defs[i].mrd_convert,
4564                         mrule_defs[i].mrd_normalize,
4565                         mrule_defs[i].mrd_match,
4566                         mrule_defs[i].mrd_indexer,
4567                         mrule_defs[i].mrd_filter,
4568                         mrule_defs[i].mrd_associated );
4569
4570                 if ( res ) {
4571                         fprintf( stderr,
4572                                 "schema_init: Error registering matching rule %s\n",
4573                                  mrule_defs[i].mrd_desc );
4574                         return LDAP_OTHER;
4575                 }
4576         }
4577         schema_init_done = 1;
4578         return LDAP_SUCCESS;
4579 }