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