]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
e1fd36cc9ab45e9db549c645db47c7c4e570f3d6
[openldap] / servers / slapd / schema_init.c
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <limits.h>
12
13 #include <ac/ctype.h>
14 #include <ac/errno.h>
15 #include <ac/string.h>
16 #include <ac/socket.h>
17
18 #include "slap.h"
19 #include "ldap_pvt.h"
20 #include "lber_pvt.h"
21
22 #include "ldap_utf8.h"
23
24 #include "lutil_hash.h"
25 #define HASH_BYTES                              LUTIL_HASH_BYTES
26 #define HASH_CONTEXT                    lutil_HASH_CTX
27 #define HASH_Init(c)                    lutil_HASHInit(c)
28 #define HASH_Update(c,buf,len)  lutil_HASHUpdate(c,buf,len)
29 #define HASH_Final(d,c)                 lutil_HASHFinal(d,c)
30
31 /* recycled validatation routines */
32 #define berValidate                                             blobValidate
33
34 /* unimplemented pretters */
35 #define integerPretty                                   NULL
36
37 /* recycled matching routines */
38 #define bitStringMatch                                  octetStringMatch
39 #define numericStringMatch                              caseIgnoreIA5Match
40 #define objectIdentifierMatch                   octetStringMatch
41 #define telephoneNumberMatch                    caseIgnoreIA5Match
42 #define telephoneNumberSubstringsMatch  caseIgnoreIA5SubstringsMatch
43 #define generalizedTimeMatch                    caseIgnoreIA5Match
44 #define generalizedTimeOrderingMatch    caseIgnoreIA5Match
45 #define uniqueMemberMatch                               dnMatch
46 #define integerFirstComponentMatch              integerMatch
47
48 /* approx matching rules */
49 #define directoryStringApproxMatchOID   "1.3.6.1.4.1.4203.666.4.4"
50 #define directoryStringApproxMatch      approxMatch
51 #define directoryStringApproxIndexer    approxIndexer
52 #define directoryStringApproxFilter     approxFilter
53 #define IA5StringApproxMatchOID                 "1.3.6.1.4.1.4203.666.4.5"
54 #define IA5StringApproxMatch                    approxMatch
55 #define IA5StringApproxIndexer                  approxIndexer
56 #define IA5StringApproxFilter                   approxFilter
57
58 /* ordering matching rules */
59 #define caseIgnoreOrderingMatch                 caseIgnoreMatch
60 #define caseExactOrderingMatch                  caseExactMatch
61 #define integerOrderingMatch                    integerMatch
62 #define octetStringOrderingMatch                octetStringMatch
63
64 /* unimplemented matching routines */
65 #define caseIgnoreListMatch                             NULL
66 #define caseIgnoreListSubstringsMatch   NULL
67 #define protocolInformationMatch                NULL
68
69 #ifdef SLAPD_ACI_ENABLED
70 #define OpenLDAPaciMatch                                NULL
71 #endif
72 #ifdef SLAPD_AUTHPASSWD
73 #define authPasswordMatch                               NULL
74 #endif
75
76 /* recycled indexing/filtering routines */
77 #define dnIndexer                               caseExactIgnoreIndexer
78 #define dnFilter                                caseExactIgnoreFilter
79 #define bitStringFilter                 octetStringFilter
80 #define bitStringIndexer                octetStringIndexer
81
82 #define telephoneNumberIndexer                  caseIgnoreIA5Indexer
83 #define telephoneNumberFilter                   caseIgnoreIA5Filter
84 #define telephoneNumberSubstringsIndexer        caseIgnoreIA5SubstringsIndexer
85 #define telephoneNumberSubstringsFilter         caseIgnoreIA5SubstringsFilter
86
87 static MatchingRule *caseExactMatchingRule;
88 static MatchingRule *caseExactSubstringsMatchingRule;
89 static MatchingRule *integerFirstComponentMatchingRule;
90
91 static const struct MatchingRulePtr {
92         const char   *oid;
93         MatchingRule **mr;
94 } mr_ptr [] = {
95         /* must match OIDs below */
96         { "2.5.13.5",  &caseExactMatchingRule },
97         { "2.5.13.7",  &caseExactSubstringsMatchingRule },
98         { "2.5.13.29", &integerFirstComponentMatchingRule }
99 };
100
101
102 static char *bvcasechr( struct berval *bv, unsigned char c, ber_len_t *len )
103 {
104         ber_len_t i;
105         char lower = TOLOWER( c );
106         char upper = TOUPPER( c );
107
108         if( c == 0 ) return NULL;
109         
110         for( i=0; i < bv->bv_len; i++ ) {
111                 if( upper == bv->bv_val[i] || lower == bv->bv_val[i] ) {
112                         *len = i;
113                         return &bv->bv_val[i];
114                 }
115         }
116
117         return NULL;
118 }
119
120 static int
121 octetStringMatch(
122         int *matchp,
123         slap_mask_t flags,
124         Syntax *syntax,
125         MatchingRule *mr,
126         struct berval *value,
127         void *assertedValue )
128 {
129         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
130
131         if( match == 0 ) {
132                 match = memcmp( value->bv_val,
133                         ((struct berval *) assertedValue)->bv_val,
134                         value->bv_len );
135         }
136
137         *matchp = match;
138         return LDAP_SUCCESS;
139 }
140
141 /* Index generation function */
142 int octetStringIndexer(
143         slap_mask_t use,
144         slap_mask_t flags,
145         Syntax *syntax,
146         MatchingRule *mr,
147         struct berval *prefix,
148         BerVarray values,
149         BerVarray *keysp )
150 {
151         int i;
152         size_t slen, mlen;
153         BerVarray keys;
154         HASH_CONTEXT   HASHcontext;
155         unsigned char   HASHdigest[HASH_BYTES];
156         struct berval digest;
157         digest.bv_val = HASHdigest;
158         digest.bv_len = sizeof(HASHdigest);
159
160         for( i=0; values[i].bv_val != NULL; i++ ) {
161                 /* just count them */
162         }
163
164         /* we should have at least one value at this point */
165         assert( i > 0 );
166
167         keys = ch_malloc( sizeof( struct berval ) * (i+1) );
168
169         slen = syntax->ssyn_oidlen;
170         mlen = mr->smr_oidlen;
171
172         for( i=0; values[i].bv_val != NULL; i++ ) {
173                 HASH_Init( &HASHcontext );
174                 if( prefix != NULL && prefix->bv_len > 0 ) {
175                         HASH_Update( &HASHcontext,
176                                 prefix->bv_val, prefix->bv_len );
177                 }
178                 HASH_Update( &HASHcontext,
179                         syntax->ssyn_oid, slen );
180                 HASH_Update( &HASHcontext,
181                         mr->smr_oid, mlen );
182                 HASH_Update( &HASHcontext,
183                         values[i].bv_val, values[i].bv_len );
184                 HASH_Final( HASHdigest, &HASHcontext );
185
186                 ber_dupbv( &keys[i], &digest );
187         }
188
189         keys[i].bv_val = NULL;
190         keys[i].bv_len = 0;
191
192         *keysp = keys;
193
194         return LDAP_SUCCESS;
195 }
196
197 /* Index generation function */
198 int octetStringFilter(
199         slap_mask_t use,
200         slap_mask_t flags,
201         Syntax *syntax,
202         MatchingRule *mr,
203         struct berval *prefix,
204         void * assertedValue,
205         BerVarray *keysp )
206 {
207         size_t slen, mlen;
208         BerVarray keys;
209         HASH_CONTEXT   HASHcontext;
210         unsigned char   HASHdigest[HASH_BYTES];
211         struct berval *value = (struct berval *) assertedValue;
212         struct berval digest;
213         digest.bv_val = HASHdigest;
214         digest.bv_len = sizeof(HASHdigest);
215
216         slen = syntax->ssyn_oidlen;
217         mlen = mr->smr_oidlen;
218
219         keys = ch_malloc( sizeof( struct berval ) * 2 );
220
221         HASH_Init( &HASHcontext );
222         if( prefix != NULL && prefix->bv_len > 0 ) {
223                 HASH_Update( &HASHcontext,
224                         prefix->bv_val, prefix->bv_len );
225         }
226         HASH_Update( &HASHcontext,
227                 syntax->ssyn_oid, slen );
228         HASH_Update( &HASHcontext,
229                 mr->smr_oid, mlen );
230         HASH_Update( &HASHcontext,
231                 value->bv_val, value->bv_len );
232         HASH_Final( HASHdigest, &HASHcontext );
233
234         ber_dupbv( keys, &digest );
235         keys[1].bv_val = NULL;
236         keys[1].bv_len = 0;
237
238         *keysp = keys;
239
240         return LDAP_SUCCESS;
241 }
242
243 static int
244 inValidate(
245         Syntax *syntax,
246         struct berval *in )
247 {
248         /* no value allowed */
249         return LDAP_INVALID_SYNTAX;
250 }
251
252 static int
253 blobValidate(
254         Syntax *syntax,
255         struct berval *in )
256 {
257         /* any value allowed */
258         return LDAP_SUCCESS;
259 }
260
261 static int
262 bitStringValidate(
263         Syntax *syntax,
264         struct berval *in )
265 {
266         ber_len_t i;
267
268         /* very unforgiving validation, requires no normalization
269          * before simplistic matching
270          */
271         if( in->bv_len < 3 ) {
272                 return LDAP_INVALID_SYNTAX;
273         }
274
275         /*
276          * rfc 2252 section 6.3 Bit String
277          * bitstring = "'" *binary-digit "'"
278          * binary-digit = "0" / "1"
279          * example: '0101111101'B
280          */
281         
282         if( in->bv_val[0] != '\'' ||
283                 in->bv_val[in->bv_len-2] != '\'' ||
284                 in->bv_val[in->bv_len-1] != 'B' )
285         {
286                 return LDAP_INVALID_SYNTAX;
287         }
288
289         for( i=in->bv_len-3; i>0; i-- ) {
290                 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
291                         return LDAP_INVALID_SYNTAX;
292                 }
293         }
294
295         return LDAP_SUCCESS;
296 }
297
298 static int
299 bitStringNormalize(
300         Syntax *syntax,
301         struct berval *val,
302         struct berval *normalized )
303 {
304         /*
305          * A normalized bitString is has no extaneous (leading) zero bits.
306          * That is, '00010'B is normalized to '10'B
307          * However, as a special case, '0'B requires no normalization.
308          */
309         char *p;
310
311         /* start at the first bit */
312         p = &val->bv_val[1];
313
314         /* Find the first non-zero bit */
315         while ( *p == '0' ) p++;
316
317         if( *p == '\'' ) {
318                 /* no non-zero bits */
319                 ber_str2bv( "\'0\'B", sizeof("\'0\'B") - 1, 1, normalized );
320                 goto done;
321         }
322
323         normalized->bv_val = ch_malloc( val->bv_len + 1 );
324
325         normalized->bv_val[0] = '\'';
326         normalized->bv_len = 1;
327
328         for( ; *p != '\0'; p++ ) {
329                 normalized->bv_val[normalized->bv_len++] = *p;
330         }
331
332         normalized->bv_val[normalized->bv_len] = '\0';
333
334 done:
335         return LDAP_SUCCESS;
336 }
337
338 static int
339 nameUIDValidate(
340         Syntax *syntax,
341         struct berval *in )
342 {
343         int rc;
344         struct berval dn;
345
346         if( in->bv_len == 0 ) return LDAP_SUCCESS;
347
348         ber_dupbv( &dn, in );
349         if( !dn.bv_val ) return LDAP_OTHER;
350
351         if( dn.bv_val[dn.bv_len-1] == 'B'
352                 && dn.bv_val[dn.bv_len-2] == '\'' )
353         {
354                 /* assume presence of optional UID */
355                 ber_len_t i;
356
357                 for(i=dn.bv_len-3; i>1; i--) {
358                         if( dn.bv_val[i] != '0' &&      dn.bv_val[i] != '1' ) {
359                                 break;
360                         }
361                 }
362                 if( dn.bv_val[i] != '\'' || dn.bv_val[i-1] != '#' ) {
363                         ber_memfree( dn.bv_val );
364                         return LDAP_INVALID_SYNTAX;
365                 }
366
367                 /* trim the UID to allow use of dnValidate */
368                 dn.bv_val[i-1] = '\0';
369                 dn.bv_len = i-1;
370         }
371
372         rc = dnValidate( NULL, &dn );
373
374         ber_memfree( dn.bv_val );
375         return rc;
376 }
377
378 static int
379 nameUIDNormalize(
380         Syntax *syntax,
381         struct berval *val,
382         struct berval *normalized )
383 {
384         struct berval out;
385         int rc;
386
387         ber_dupbv( &out, val );
388         if( out.bv_len != 0 ) {
389                 struct berval uidin = { 0, NULL };
390                 struct berval uidout = { 0, NULL };
391
392                 if( out.bv_val[out.bv_len-1] == 'B'
393                         && out.bv_val[out.bv_len-2] == '\'' )
394                 {
395                         /* assume presence of optional UID */
396                         uidin.bv_val = strrchr( out.bv_val, '#' );
397
398                         if( uidin.bv_val == NULL ) {
399                                 free( out.bv_val );
400                                 return LDAP_INVALID_SYNTAX;
401                         }
402
403                         uidin.bv_len = out.bv_len - (uidin.bv_val - out.bv_val);
404                         out.bv_len -= uidin.bv_len--;
405
406                         /* temporarily trim the UID */
407                         *(uidin.bv_val++) = '\0';
408
409                         rc = bitStringNormalize( syntax, &uidin, &uidout );
410
411                         if( rc != LDAP_SUCCESS ) {
412                                 free( out.bv_val );
413                                 return LDAP_INVALID_SYNTAX;
414                         }
415                 }
416
417 #ifdef USE_DN_NORMALIZE
418                 rc = dnNormalize2( NULL, &out, normalized );
419 #else
420                 rc = dnPretty2( NULL, &out, normalized );
421 #endif
422
423                 if( rc != LDAP_SUCCESS ) {
424                         free( out.bv_val );
425                         free( uidout.bv_val );
426                         return LDAP_INVALID_SYNTAX;
427                 }
428
429                 if( uidout.bv_len ) {
430                         normalized->bv_val = ch_realloc( normalized->bv_val,
431                                 normalized->bv_len + uidout.bv_len + sizeof("#") );
432
433                         /* insert the separator */
434                         normalized->bv_val[normalized->bv_len++] = '#';
435
436                         /* append the UID */
437                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
438                                 uidout.bv_val, uidout.bv_len );
439                         normalized->bv_len += uidout.bv_len;
440
441                         /* terminate */
442                         normalized->bv_val[normalized->bv_len] = '\0';
443                 }
444
445                 free( out.bv_val );
446         }
447
448         return LDAP_SUCCESS;
449 }
450
451 /*
452  * Handling boolean syntax and matching is quite rigid.
453  * A more flexible approach would be to allow a variety
454  * of strings to be normalized and prettied into TRUE
455  * and FALSE.
456  */
457 static int
458 booleanValidate(
459         Syntax *syntax,
460         struct berval *in )
461 {
462         /* very unforgiving validation, requires no normalization
463          * before simplistic matching
464          */
465
466         if( in->bv_len == 4 ) {
467                 if( !memcmp( in->bv_val, "TRUE", 4 ) ) {
468                         return LDAP_SUCCESS;
469                 }
470         } else if( in->bv_len == 5 ) {
471                 if( !memcmp( in->bv_val, "FALSE", 5 ) ) {
472                         return LDAP_SUCCESS;
473                 }
474         }
475
476         return LDAP_INVALID_SYNTAX;
477 }
478
479 static int
480 booleanMatch(
481         int *matchp,
482         slap_mask_t flags,
483         Syntax *syntax,
484         MatchingRule *mr,
485         struct berval *value,
486         void *assertedValue )
487 {
488         /* simplistic matching allowed by rigid validation */
489         struct berval *asserted = (struct berval *) assertedValue;
490         *matchp = value->bv_len != asserted->bv_len;
491         return LDAP_SUCCESS;
492 }
493
494 /*-------------------------------------------------------------------
495 LDAP/X.500 string syntax / matching rules have a few oddities.  This
496 comment attempts to detail how slapd(8) treats them.
497
498 Summary:
499   StringSyntax          X.500   LDAP    Matching
500   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
501   PrintableString       subset  subset  i/e + ignore insignificant spaces
502   NumericString         subset  subset  ignore all spaces
503   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
504   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
505
506   TelephoneNumber subset  subset  i + ignore all spaces and "-"
507
508   See draft-ietf-ldapbis-strpro for details (once published).
509
510
511 Directory String -
512   In X.500(93), a directory string can be either a PrintableString,
513   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
514   In later versions, more CHOICEs were added.  In all cases the string
515   must be non-empty.
516
517   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
518
519   For matching, there are both case ignore and exact rules.  Both
520   also require that "insignificant" spaces be ignored.
521         spaces before the first non-space are ignored;
522         spaces after the last non-space are ignored;
523         spaces after a space are ignored.
524   Note: by these rules (and as clarified in X.520), a string of only
525   spaces is to be treated as if held one space, not empty (which
526   would be a syntax error).
527
528 NumericString
529   In ASN.1, numeric string is just a string of digits and spaces
530   and could be empty.  However, in X.500, all attribute values of
531   numeric string carry a non-empty constraint.  For example:
532
533         internationalISDNNumber ATTRIBUTE ::= {
534                 WITH SYNTAX InternationalISDNNumber
535                 EQUALITY MATCHING RULE numericStringMatch
536                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
537                 ID id-at-internationalISDNNumber }
538         InternationalISDNNumber ::=
539             NumericString (SIZE(1..ub-international-isdn-number))
540
541   Unforunately, some assertion values are don't carry the same
542   constraint (but its unclear how such an assertion could ever
543   be true). In LDAP, there is one syntax (numericString) not two
544   (numericString with constraint, numericString without constraint).
545   This should be treated as numericString with non-empty constraint.
546   Note that while someone may have no ISDN number, there are no ISDN
547   numbers which are zero length.
548
549   In matching, spaces are ignored.
550
551 PrintableString
552   In ASN.1, Printable string is just a string of printable characters
553   and can be empty.  In X.500, semantics much like NumericString (see
554   serialNumber for a like example) excepting uses insignificant space
555   handling instead of ignore all spaces.  
556
557 IA5String
558   Basically same as PrintableString.  There are no examples in X.500,
559   but same logic applies.  So we require them to be non-empty as
560   well.
561
562 -------------------------------------------------------------------*/
563
564 static int
565 UTF8StringValidate(
566         Syntax *syntax,
567         struct berval *in )
568 {
569         ber_len_t count;
570         int len;
571         unsigned char *u = in->bv_val;
572
573         if( !in->bv_len ) return LDAP_INVALID_SYNTAX;
574
575         for( count = in->bv_len; count > 0; count-=len, u+=len ) {
576                 /* get the length indicated by the first byte */
577                 len = LDAP_UTF8_CHARLEN2( u, len );
578
579                 /* very basic checks */
580                 switch( len ) {
581                         case 6:
582                                 if( (u[5] & 0xC0) != 0x80 ) {
583                                         return LDAP_INVALID_SYNTAX;
584                                 }
585                         case 5:
586                                 if( (u[4] & 0xC0) != 0x80 ) {
587                                         return LDAP_INVALID_SYNTAX;
588                                 }
589                         case 4:
590                                 if( (u[3] & 0xC0) != 0x80 ) {
591                                         return LDAP_INVALID_SYNTAX;
592                                 }
593                         case 3:
594                                 if( (u[2] & 0xC0 )!= 0x80 ) {
595                                         return LDAP_INVALID_SYNTAX;
596                                 }
597                         case 2:
598                                 if( (u[1] & 0xC0) != 0x80 ) {
599                                         return LDAP_INVALID_SYNTAX;
600                                 }
601                         case 1:
602                                 /* CHARLEN already validated it */
603                                 break;
604                         default:
605                                 return LDAP_INVALID_SYNTAX;
606                 }
607
608                 /* make sure len corresponds with the offset
609                         to the next character */
610                 if( LDAP_UTF8_OFFSET( u ) != len ) return LDAP_INVALID_SYNTAX;
611         }
612
613         if( count != 0 ) return LDAP_INVALID_SYNTAX;
614
615         return LDAP_SUCCESS;
616 }
617
618 static int
619 UTF8StringNormalize(
620         Syntax *syntax,
621         struct berval *val,
622         struct berval *normalized )
623 {
624         char *p, *q, *s, *e;
625         int len = 0;
626
627         /* validator should have refused an empty string */
628         assert( val->bv_len );
629
630         p = val->bv_val;
631
632         /* Ignore initial whitespace */
633         /* All space is ASCII. All ASCII is 1 byte */
634         for ( ; p < val->bv_val + val->bv_len && ASCII_SPACE( p[ 0 ] ); p++ );
635
636         normalized->bv_len = val->bv_len - (p - val->bv_val);
637
638         if( !normalized->bv_len ) {
639                 ber_mem2bv( " ", 1, 1, normalized );
640                 return LDAP_SUCCESS;
641         }
642
643         ber_mem2bv( p, normalized->bv_len, 1, normalized );
644         e = normalized->bv_val + normalized->bv_len;
645
646         assert( normalized->bv_val );
647
648         p = q = normalized->bv_val;
649         s = NULL;
650
651         while ( p < e ) {
652                 q += len;
653                 if ( ASCII_SPACE( *p ) ) {
654                         s = q - len;
655                         len = 1;
656                         *q = *p++;
657
658                         /* Ignore the extra whitespace */
659                         while ( ASCII_SPACE( *p ) ) {
660                                 p++;
661                         }
662                 } else {
663                         len = LDAP_UTF8_COPY(q,p);
664                         s=NULL;
665                         p+=len;
666                 }
667         }
668
669         assert( normalized->bv_val <= p );
670         assert( q+len <= p );
671
672         /* cannot start with a space */
673         assert( !ASCII_SPACE( normalized->bv_val[0] ) );
674
675         /*
676          * If the string ended in space, backup the pointer one
677          * position.  One is enough because the above loop collapsed
678          * all whitespace to a single space.
679          */
680
681         if ( s != NULL ) {
682                 len = q - s;
683                 q = s;
684         }
685
686         /* cannot end with a space */
687         assert( !ASCII_SPACE( *q ) );
688
689         q += len;
690
691         /* null terminate */
692         *q = '\0';
693
694         normalized->bv_len = q - normalized->bv_val;
695
696         return LDAP_SUCCESS;
697 }
698
699 /* Returns Unicode canonically normalized copy of a substring assertion
700  * Skipping attribute description */
701 static SubstringsAssertion *
702 UTF8SubstringsassertionNormalize(
703         SubstringsAssertion *sa,
704         unsigned casefold )
705 {
706         SubstringsAssertion *nsa;
707         int i;
708
709         nsa = (SubstringsAssertion *)SLAP_CALLOC( 1, sizeof(SubstringsAssertion) );
710         if( nsa == NULL ) {
711                 return NULL;
712         }
713
714         if( sa->sa_initial.bv_val != NULL ) {
715                 UTF8bvnormalize( &sa->sa_initial, &nsa->sa_initial, casefold );
716                 if( nsa->sa_initial.bv_val == NULL ) {
717                         goto err;
718                 }
719         }
720
721         if( sa->sa_any != NULL ) {
722                 for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
723                         /* empty */
724                 }
725                 nsa->sa_any = (struct berval *)
726                         SLAP_MALLOC( (i + 1) * sizeof(struct berval) );
727                 if( nsa->sa_any == NULL ) {
728                                 goto err;
729                 }
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
3584 /*
3585  * Next function returns a string representation of a ASN1_INTEGER.
3586  * It works for unlimited lengths.
3587  */
3588
3589 static struct berval *
3590 asn1_integer2str(ASN1_INTEGER *a, struct berval *bv)
3591 {
3592         char buf[256];
3593         char *p;
3594         static char digit[] = "0123456789";
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.19    octetStringSubstringsMatch
4466  * 2.5.13.25    uTCTimeMatch
4467  * 2.5.13.26    uTCTimeOrderingMatch
4468  * 2.5.13.31    directoryStringFirstComponentMatch
4469  * 2.5.13.32    wordMatch
4470  * 2.5.13.33    keywordMatch
4471  * 2.5.13.35    certificateMatch
4472  * 2.5.13.36    certificatePairExactMatch
4473  * 2.5.13.37    certificatePairMatch
4474  * 2.5.13.38    certificateListExactMatch
4475  * 2.5.13.39    certificateListMatch
4476  * 2.5.13.40    algorithmIdentifierMatch
4477  * 2.5.13.41    storedPrefixMatch
4478  * 2.5.13.42    attributeCertificateMatch
4479  * 2.5.13.43    readerAndKeyIDMatch
4480  * 2.5.13.44    attributeIntegrityMatch
4481  */
4482 static slap_mrule_defs_rec mrule_defs[] = {
4483         /*
4484          * EQUALITY matching rules must be listed after associated APPROX
4485          * matching rules.  So, we list all APPROX matching rules first.
4486          */
4487         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4488                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4489                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4490                 NULL, NULL,
4491                 directoryStringApproxMatch,
4492                 directoryStringApproxIndexer, 
4493                 directoryStringApproxFilter,
4494                 NULL},
4495
4496         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4497                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4498                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4499                 NULL, NULL,
4500                 IA5StringApproxMatch,
4501                 IA5StringApproxIndexer, 
4502                 IA5StringApproxFilter,
4503                 NULL},
4504
4505         /*
4506          * Other matching rules
4507          */
4508         
4509         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4510                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4511                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4512                 NULL, NULL,
4513                 objectIdentifierMatch, caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
4514                 NULL},
4515
4516         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4517                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4518                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4519                 NULL, NULL,
4520                 dnMatch, dnIndexer, dnFilter,
4521                 NULL},
4522
4523         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4524                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4525                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
4526                         directoryStringSyntaxes,
4527                 NULL, NULL,
4528                 caseIgnoreMatch, caseExactIgnoreIndexer, caseExactIgnoreFilter,
4529                 directoryStringApproxMatchOID },
4530
4531         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4532                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4533                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4534                 NULL, NULL,
4535                 caseIgnoreOrderingMatch, NULL, NULL,
4536                 NULL},
4537
4538         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4539                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4540                 SLAP_MR_SUBSTR, NULL,
4541                 NULL, NULL,
4542                 caseExactIgnoreSubstringsMatch,
4543                 caseExactIgnoreSubstringsIndexer,
4544                 caseExactIgnoreSubstringsFilter,
4545                 NULL},
4546
4547         {"( 2.5.13.5 NAME 'caseExactMatch' "
4548                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4549                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4550                 NULL, NULL,
4551                 caseExactMatch, caseExactIgnoreIndexer, caseExactIgnoreFilter,
4552                 directoryStringApproxMatchOID },
4553
4554         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4555                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4556                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4557                 NULL, NULL,
4558                 caseExactOrderingMatch, NULL, NULL,
4559                 NULL},
4560
4561         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4562                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4563                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4564                 NULL, NULL,
4565                 caseExactIgnoreSubstringsMatch,
4566                 caseExactIgnoreSubstringsIndexer,
4567                 caseExactIgnoreSubstringsFilter,
4568                 NULL},
4569
4570         {"( 2.5.13.8 NAME 'numericStringMatch' "
4571                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4572                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD, NULL,
4573                 NULL, NULL,
4574                 caseIgnoreIA5Match,
4575                 caseIgnoreIA5Indexer,
4576                 caseIgnoreIA5Filter,
4577                 NULL},
4578
4579         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4580                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4581                 SLAP_MR_SUBSTR, NULL,
4582                 NULL, NULL,
4583                 caseIgnoreIA5SubstringsMatch,
4584                 caseIgnoreIA5SubstringsIndexer,
4585                 caseIgnoreIA5SubstringsFilter,
4586                 NULL},
4587
4588         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4589                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4590                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD, NULL,
4591                 NULL, NULL,
4592                 caseIgnoreListMatch, NULL, NULL,
4593                 NULL},
4594
4595         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4596                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4597                 SLAP_MR_SUBSTR, NULL,
4598                 NULL, NULL,
4599                 caseIgnoreListSubstringsMatch, NULL, NULL,
4600                 NULL},
4601
4602         {"( 2.5.13.13 NAME 'booleanMatch' "
4603                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4604                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4605                 NULL, NULL,
4606                 booleanMatch, NULL, NULL,
4607                 NULL},
4608
4609         {"( 2.5.13.14 NAME 'integerMatch' "
4610                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4611                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4612                 NULL, NULL,
4613                 integerMatch, integerIndexer, integerFilter,
4614                 NULL},
4615
4616         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4617                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4618                 SLAP_MR_ORDERING, NULL,
4619                 NULL, NULL,
4620                 integerOrderingMatch, NULL, NULL,
4621                 NULL},
4622
4623         {"( 2.5.13.16 NAME 'bitStringMatch' "
4624                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4625                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4626                 NULL, NULL,
4627                 bitStringMatch, bitStringIndexer, bitStringFilter,
4628                 NULL},
4629
4630         {"( 2.5.13.17 NAME 'octetStringMatch' "
4631                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4632                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4633                 NULL, NULL,
4634                 octetStringMatch, octetStringIndexer, octetStringFilter,
4635                 NULL},
4636
4637         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
4638                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4639                 SLAP_MR_ORDERING, NULL,
4640                 NULL, NULL,
4641                 octetStringOrderingMatch, NULL, NULL,
4642                 NULL},
4643
4644         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
4645                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
4646                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD, NULL,
4647                 NULL, NULL,
4648                 telephoneNumberMatch,
4649                 telephoneNumberIndexer,
4650                 telephoneNumberFilter,
4651                 NULL},
4652
4653         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
4654                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4655                 SLAP_MR_SUBSTR, NULL,
4656                 NULL, NULL,
4657                 telephoneNumberSubstringsMatch,
4658                 telephoneNumberSubstringsIndexer,
4659                 telephoneNumberSubstringsFilter,
4660                 NULL},
4661
4662         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
4663                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
4664                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4665                 NULL, NULL,
4666                 NULL, NULL, NULL,
4667                 NULL},
4668
4669         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
4670                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
4671                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4672                 NULL, NULL,
4673                 uniqueMemberMatch, NULL, NULL,
4674                 NULL},
4675
4676         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
4677                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
4678                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4679                 NULL, NULL,
4680                 protocolInformationMatch, NULL, NULL,
4681                 NULL},
4682
4683         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
4684                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4685                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4686                 NULL, NULL,
4687                 generalizedTimeMatch, NULL, NULL,
4688                 NULL},
4689
4690         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
4691                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4692                 SLAP_MR_ORDERING, NULL,
4693                 NULL, NULL,
4694                 generalizedTimeOrderingMatch, NULL, NULL,
4695                 NULL},
4696
4697         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
4698                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4699                 SLAP_MR_EQUALITY | SLAP_MR_EXT, integerFirstComponentMatchSyntaxes,
4700                 NULL, NULL,
4701                 integerFirstComponentMatch, NULL, NULL,
4702                 NULL},
4703
4704         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
4705                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4706                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4707                         objectIdentifierFirstComponentMatchSyntaxes,
4708                 NULL, NULL,
4709                 objectIdentifierFirstComponentMatch, NULL, NULL,
4710                 NULL},
4711
4712 #ifdef HAVE_TLS
4713         {"( 2.5.13.34 NAME 'certificateExactMatch' "
4714                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
4715                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
4716                 certificateExactConvert, NULL,
4717                 certificateExactMatch,
4718                 certificateExactIndexer, certificateExactFilter,
4719                 NULL},
4720 #endif
4721
4722         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
4723                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4724                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4725                 NULL, NULL,
4726                 caseExactIA5Match, caseExactIA5Indexer, caseExactIA5Filter,
4727                 IA5StringApproxMatchOID },
4728
4729         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
4730                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4731                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD, NULL,
4732                 NULL, NULL,
4733                 caseIgnoreIA5Match, caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
4734                 IA5StringApproxMatchOID },
4735
4736         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
4737                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4738                 SLAP_MR_SUBSTR, NULL,
4739                 NULL, NULL,
4740                 caseIgnoreIA5SubstringsMatch,
4741                 caseIgnoreIA5SubstringsIndexer,
4742                 caseIgnoreIA5SubstringsFilter,
4743                 NULL},
4744
4745         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
4746                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4747                 SLAP_MR_SUBSTR, NULL,
4748                 NULL, NULL,
4749                 caseExactIA5SubstringsMatch,
4750                 caseExactIA5SubstringsIndexer,
4751                 caseExactIA5SubstringsFilter,
4752                 NULL},
4753
4754 #ifdef SLAPD_AUTHPASSWD
4755         /* needs updating */
4756         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
4757                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4758                 SLAP_MR_EQUALITY, NULL,
4759                 NULL, NULL,
4760                 authPasswordMatch, NULL, NULL,
4761                 NULL},
4762 #endif
4763
4764 #ifdef SLAPD_ACI_ENABLED
4765         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
4766                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
4767                 SLAP_MR_EQUALITY, NULL,
4768                 NULL, NULL,
4769                 OpenLDAPaciMatch, NULL, NULL,
4770                 NULL},
4771 #endif
4772
4773         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
4774                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4775                 SLAP_MR_EXT, NULL,
4776                 NULL, NULL,
4777                 integerBitAndMatch, NULL, NULL,
4778                 NULL},
4779
4780         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
4781                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4782                 SLAP_MR_EXT, NULL,
4783                 NULL, NULL,
4784                 integerBitOrMatch, NULL, NULL,
4785                 NULL},
4786
4787         {NULL, SLAP_MR_NONE, NULL,
4788                 NULL, NULL, NULL, NULL, NULL,
4789                 NULL }
4790 };
4791
4792 int
4793 slap_schema_init( void )
4794 {
4795         int             res;
4796         int             i = 0;
4797
4798         /* we should only be called once (from main) */
4799         assert( schema_init_done == 0 );
4800
4801         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
4802                 res = register_syntax( &syntax_defs[i] );
4803
4804                 if ( res ) {
4805                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
4806                                  syntax_defs[i].sd_desc );
4807                         return LDAP_OTHER;
4808                 }
4809         }
4810
4811         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
4812                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
4813                         mrule_defs[i].mrd_compat_syntaxes == NULL )
4814                 {
4815                         fprintf( stderr,
4816                                 "slap_schema_init: Ingoring unusable matching rule %s\n",
4817                                  mrule_defs[i].mrd_desc );
4818                         continue;
4819                 }
4820
4821                 res = register_matching_rule( &mrule_defs[i] );
4822
4823                 if ( res ) {
4824                         fprintf( stderr,
4825                                 "slap_schema_init: Error registering matching rule %s\n",
4826                                  mrule_defs[i].mrd_desc );
4827                         return LDAP_OTHER;
4828                 }
4829         }
4830
4831         for ( i=0; i < (int)(sizeof(mr_ptr)/sizeof(mr_ptr[0])); i++ )
4832                 *mr_ptr[i].mr = mr_find( mr_ptr[i].oid );
4833
4834         res = slap_schema_load();
4835         schema_init_done = 1;
4836         return res;
4837 }
4838
4839 void
4840 schema_destroy( void )
4841 {
4842         int i;
4843         oidm_destroy();
4844         oc_destroy();
4845         at_destroy();
4846         for ( i=0; i < (int)(sizeof(mr_ptr)/sizeof(mr_ptr[0])); i++ )
4847                 *mr_ptr[i].mr = NULL;
4848         mr_destroy();
4849         mru_destroy();
4850         syn_destroy();
4851 }