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