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