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