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