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