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