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