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