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