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