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