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