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