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