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