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