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