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