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