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