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