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