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