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