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