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