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