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