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