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