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