]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
Fix IRIX sc_mask conflict
[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 ) LDAP_INVALID_SYNTAX;
2126
2127         return LDAP_SUCCESS;
2128 }
2129
2130 static int
2131 IA5StringValidate(
2132         Syntax *syntax,
2133         struct berval *val )
2134 {
2135         ber_len_t i;
2136
2137         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
2138
2139         for(i=0; i < val->bv_len; i++) {
2140                 if( !LDAP_ASCII(val->bv_val[i]) ) {
2141                         return LDAP_INVALID_SYNTAX;
2142                 }
2143         }
2144
2145         return LDAP_SUCCESS;
2146 }
2147
2148 static int
2149 IA5StringNormalize(
2150         Syntax *syntax,
2151         struct berval *val,
2152         struct berval *normalized )
2153 {
2154         char *p, *q;
2155
2156         assert( val->bv_len );
2157
2158         p = val->bv_val;
2159
2160         /* Ignore initial whitespace */
2161         while ( ASCII_SPACE( *p ) ) {
2162                 p++;
2163         }
2164
2165         normalized->bv_val = ch_strdup( p );
2166         p = q = normalized->bv_val;
2167
2168         while ( *p ) {
2169                 if ( ASCII_SPACE( *p ) ) {
2170                         *q++ = *p++;
2171
2172                         /* Ignore the extra whitespace */
2173                         while ( ASCII_SPACE( *p ) ) {
2174                                 p++;
2175                         }
2176                 } else {
2177                         *q++ = *p++;
2178                 }
2179         }
2180
2181         assert( normalized->bv_val <= p );
2182         assert( q <= p );
2183
2184         /*
2185          * If the string ended in space, backup the pointer one
2186          * position.  One is enough because the above loop collapsed
2187          * all whitespace to a single space.
2188          */
2189
2190         if ( ASCII_SPACE( q[-1] ) ) {
2191                 --q;
2192         }
2193
2194         /* null terminate */
2195         *q = '\0';
2196
2197         normalized->bv_len = q - normalized->bv_val;
2198
2199         if( normalized->bv_len == 0 ) {
2200                 normalized->bv_val = ch_realloc( normalized->bv_val, 2 );
2201                 normalized->bv_val[0] = ' ';
2202                 normalized->bv_val[1] = '\0';
2203                 normalized->bv_len = 1;
2204         }
2205
2206         return LDAP_SUCCESS;
2207 }
2208
2209 static int
2210 caseExactIA5Match(
2211         int *matchp,
2212         slap_mask_t flags,
2213         Syntax *syntax,
2214         MatchingRule *mr,
2215         struct berval *value,
2216         void *assertedValue )
2217 {
2218         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
2219
2220         if( match == 0 ) {
2221                 match = strncmp( value->bv_val,
2222                         ((struct berval *) assertedValue)->bv_val,
2223                         value->bv_len );
2224         }
2225
2226         *matchp = match;
2227         return LDAP_SUCCESS;
2228 }
2229
2230 static int
2231 caseExactIA5SubstringsMatch(
2232         int *matchp,
2233         slap_mask_t flags,
2234         Syntax *syntax,
2235         MatchingRule *mr,
2236         struct berval *value,
2237         void *assertedValue )
2238 {
2239         int match = 0;
2240         SubstringsAssertion *sub = assertedValue;
2241         struct berval left = *value;
2242         int i;
2243         ber_len_t inlen=0;
2244
2245         /* Add up asserted input length */
2246         if( sub->sa_initial.bv_val ) {
2247                 inlen += sub->sa_initial.bv_len;
2248         }
2249         if( sub->sa_any ) {
2250                 for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
2251                         inlen += sub->sa_any[i].bv_len;
2252                 }
2253         }
2254         if( sub->sa_final.bv_val ) {
2255                 inlen += sub->sa_final.bv_len;
2256         }
2257
2258         if( sub->sa_initial.bv_val ) {
2259                 if( inlen > left.bv_len ) {
2260                         match = 1;
2261                         goto done;
2262                 }
2263
2264                 match = strncmp( sub->sa_initial.bv_val, left.bv_val,
2265                         sub->sa_initial.bv_len );
2266
2267                 if( match != 0 ) {
2268                         goto done;
2269                 }
2270
2271                 left.bv_val += sub->sa_initial.bv_len;
2272                 left.bv_len -= sub->sa_initial.bv_len;
2273                 inlen -= sub->sa_initial.bv_len;
2274         }
2275
2276         if( sub->sa_final.bv_val ) {
2277                 if( inlen > left.bv_len ) {
2278                         match = 1;
2279                         goto done;
2280                 }
2281
2282                 match = strncmp( sub->sa_final.bv_val,
2283                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
2284                         sub->sa_final.bv_len );
2285
2286                 if( match != 0 ) {
2287                         goto done;
2288                 }
2289
2290                 left.bv_len -= sub->sa_final.bv_len;
2291                 inlen -= sub->sa_final.bv_len;
2292         }
2293
2294         if( sub->sa_any ) {
2295                 for(i=0; sub->sa_any[i].bv_val; i++) {
2296                         ber_len_t idx;
2297                         char *p;
2298
2299 retry:
2300                         if( inlen > left.bv_len ) {
2301                                 /* not enough length */
2302                                 match = 1;
2303                                 goto done;
2304                         }
2305
2306                         if( sub->sa_any[i].bv_len == 0 ) {
2307                                 continue;
2308                         }
2309
2310                         p = strchr( left.bv_val, *sub->sa_any[i].bv_val );
2311
2312                         if( p == NULL ) {
2313                                 match = 1;
2314                                 goto done;
2315                         }
2316
2317                         idx = p - left.bv_val;
2318
2319                         if( idx >= left.bv_len ) {
2320                                 /* this shouldn't happen */
2321                                 return LDAP_OTHER;
2322                         }
2323
2324                         left.bv_val = p;
2325                         left.bv_len -= idx;
2326
2327                         if( sub->sa_any[i].bv_len > left.bv_len ) {
2328                                 /* not enough left */
2329                                 match = 1;
2330                                 goto done;
2331                         }
2332
2333                         match = strncmp( left.bv_val,
2334                                 sub->sa_any[i].bv_val,
2335                                 sub->sa_any[i].bv_len );
2336
2337                         if( match != 0 ) {
2338                                 left.bv_val++;
2339                                 left.bv_len--;
2340                                 goto retry;
2341                         }
2342
2343                         left.bv_val += sub->sa_any[i].bv_len;
2344                         left.bv_len -= sub->sa_any[i].bv_len;
2345                         inlen -= sub->sa_any[i].bv_len;
2346                 }
2347         }
2348
2349 done:
2350         *matchp = match;
2351         return LDAP_SUCCESS;
2352 }
2353
2354 /* Index generation function */
2355 static int caseExactIA5Indexer(
2356         slap_mask_t use,
2357         slap_mask_t flags,
2358         Syntax *syntax,
2359         MatchingRule *mr,
2360         struct berval *prefix,
2361         BerVarray values,
2362         BerVarray *keysp )
2363 {
2364         int i;
2365         size_t slen, mlen;
2366         BerVarray keys;
2367         HASH_CONTEXT   HASHcontext;
2368         unsigned char   HASHdigest[HASH_BYTES];
2369         struct berval digest;
2370         digest.bv_val = HASHdigest;
2371         digest.bv_len = sizeof(HASHdigest);
2372
2373         for( i=0; values[i].bv_val != NULL; i++ ) {
2374                 /* empty - just count them */
2375         }
2376
2377         /* we should have at least one value at this point */
2378         assert( i > 0 );
2379
2380         keys = ch_malloc( sizeof( struct berval ) * (i+1) );
2381
2382         slen = syntax->ssyn_oidlen;
2383         mlen = mr->smr_oidlen;
2384
2385         for( i=0; values[i].bv_val != NULL; i++ ) {
2386                 struct berval *value = &values[i];
2387
2388                 HASH_Init( &HASHcontext );
2389                 if( prefix != NULL && prefix->bv_len > 0 ) {
2390                         HASH_Update( &HASHcontext,
2391                                 prefix->bv_val, prefix->bv_len );
2392                 }
2393                 HASH_Update( &HASHcontext,
2394                         syntax->ssyn_oid, slen );
2395                 HASH_Update( &HASHcontext,
2396                         mr->smr_oid, mlen );
2397                 HASH_Update( &HASHcontext,
2398                         value->bv_val, value->bv_len );
2399                 HASH_Final( HASHdigest, &HASHcontext );
2400
2401                 ber_dupbv( &keys[i], &digest );
2402         }
2403
2404         keys[i].bv_val = NULL;
2405         *keysp = keys;
2406         return LDAP_SUCCESS;
2407 }
2408
2409 /* Index generation function */
2410 static int caseExactIA5Filter(
2411         slap_mask_t use,
2412         slap_mask_t flags,
2413         Syntax *syntax,
2414         MatchingRule *mr,
2415         struct berval *prefix,
2416         void * assertValue,
2417         BerVarray *keysp )
2418 {
2419         size_t slen, mlen;
2420         BerVarray keys;
2421         HASH_CONTEXT   HASHcontext;
2422         unsigned char   HASHdigest[HASH_BYTES];
2423         struct berval *value;
2424         struct berval digest;
2425         digest.bv_val = HASHdigest;
2426         digest.bv_len = sizeof(HASHdigest);
2427
2428         slen = syntax->ssyn_oidlen;
2429         mlen = mr->smr_oidlen;
2430
2431         value = (struct berval *) assertValue;
2432
2433         keys = ch_malloc( sizeof( struct berval ) * 2 );
2434
2435         HASH_Init( &HASHcontext );
2436         if( prefix != NULL && prefix->bv_len > 0 ) {
2437                 HASH_Update( &HASHcontext,
2438                         prefix->bv_val, prefix->bv_len );
2439         }
2440         HASH_Update( &HASHcontext,
2441                 syntax->ssyn_oid, slen );
2442         HASH_Update( &HASHcontext,
2443                 mr->smr_oid, mlen );
2444         HASH_Update( &HASHcontext,
2445                 value->bv_val, value->bv_len );
2446         HASH_Final( HASHdigest, &HASHcontext );
2447
2448         ber_dupbv( &keys[0], &digest );
2449         keys[1].bv_val = NULL;
2450
2451         *keysp = keys;
2452         return LDAP_SUCCESS;
2453 }
2454
2455 /* Substrings Index generation function */
2456 static int caseExactIA5SubstringsIndexer(
2457         slap_mask_t use,
2458         slap_mask_t flags,
2459         Syntax *syntax,
2460         MatchingRule *mr,
2461         struct berval *prefix,
2462         BerVarray values,
2463         BerVarray *keysp )
2464 {
2465         ber_len_t i, nkeys;
2466         size_t slen, mlen;
2467         BerVarray keys;
2468         HASH_CONTEXT   HASHcontext;
2469         unsigned char   HASHdigest[HASH_BYTES];
2470         struct berval digest;
2471         digest.bv_val = HASHdigest;
2472         digest.bv_len = sizeof(HASHdigest);
2473
2474         /* we should have at least one value at this point */
2475         assert( values != NULL && values[0].bv_val != NULL );
2476
2477         nkeys=0;
2478         for( i=0; values[i].bv_val != NULL; i++ ) {
2479                 /* count number of indices to generate */
2480                 if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
2481                         continue;
2482                 }
2483
2484                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
2485                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2486                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
2487                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
2488                         } else {
2489                                 nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
2490                         }
2491                 }
2492
2493                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
2494                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2495                                 nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
2496                         }
2497                 }
2498
2499                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
2500                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2501                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
2502                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
2503                         } else {
2504                                 nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
2505                         }
2506                 }
2507         }
2508
2509         if( nkeys == 0 ) {
2510                 /* no keys to generate */
2511                 *keysp = NULL;
2512                 return LDAP_SUCCESS;
2513         }
2514
2515         keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
2516
2517         slen = syntax->ssyn_oidlen;
2518         mlen = mr->smr_oidlen;
2519
2520         nkeys=0;
2521         for( i=0; values[i].bv_val != NULL; i++ ) {
2522                 ber_len_t j,max;
2523                 struct berval *value;
2524
2525                 value = &values[i];
2526                 if( value->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
2527
2528                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
2529                         ( value->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
2530                 {
2531                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
2532                         max = value->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
2533
2534                         for( j=0; j<max; j++ ) {
2535                                 HASH_Init( &HASHcontext );
2536                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2537                                         HASH_Update( &HASHcontext,
2538                                                 prefix->bv_val, prefix->bv_len );
2539                                 }
2540
2541                                 HASH_Update( &HASHcontext,
2542                                         &pre, sizeof( pre ) );
2543                                 HASH_Update( &HASHcontext,
2544                                         syntax->ssyn_oid, slen );
2545                                 HASH_Update( &HASHcontext,
2546                                         mr->smr_oid, mlen );
2547                                 HASH_Update( &HASHcontext,
2548                                         &value->bv_val[j],
2549                                         SLAP_INDEX_SUBSTR_MAXLEN );
2550                                 HASH_Final( HASHdigest, &HASHcontext );
2551
2552                                 ber_dupbv( &keys[nkeys++], &digest );
2553                         }
2554                 }
2555
2556                 max = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2557                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2558
2559                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
2560                         char pre;
2561
2562                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
2563                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
2564                                 HASH_Init( &HASHcontext );
2565                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2566                                         HASH_Update( &HASHcontext,
2567                                                 prefix->bv_val, prefix->bv_len );
2568                                 }
2569                                 HASH_Update( &HASHcontext,
2570                                         &pre, sizeof( pre ) );
2571                                 HASH_Update( &HASHcontext,
2572                                         syntax->ssyn_oid, slen );
2573                                 HASH_Update( &HASHcontext,
2574                                         mr->smr_oid, mlen );
2575                                 HASH_Update( &HASHcontext,
2576                                         value->bv_val, j );
2577                                 HASH_Final( HASHdigest, &HASHcontext );
2578
2579                                 ber_dupbv( &keys[nkeys++], &digest );
2580                         }
2581
2582                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
2583                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
2584                                 HASH_Init( &HASHcontext );
2585                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2586                                         HASH_Update( &HASHcontext,
2587                                                 prefix->bv_val, prefix->bv_len );
2588                                 }
2589                                 HASH_Update( &HASHcontext,
2590                                         &pre, sizeof( pre ) );
2591                                 HASH_Update( &HASHcontext,
2592                                         syntax->ssyn_oid, slen );
2593                                 HASH_Update( &HASHcontext,
2594                                         mr->smr_oid, mlen );
2595                                 HASH_Update( &HASHcontext,
2596                                         &value->bv_val[value->bv_len-j], j );
2597                                 HASH_Final( HASHdigest, &HASHcontext );
2598
2599                                 ber_dupbv( &keys[nkeys++], &digest );
2600                         }
2601
2602                 }
2603         }
2604
2605         if( nkeys > 0 ) {
2606                 keys[nkeys].bv_val = NULL;
2607                 *keysp = keys;
2608         } else {
2609                 ch_free( keys );
2610                 *keysp = NULL;
2611         }
2612
2613         return LDAP_SUCCESS;
2614 }
2615
2616 static int caseExactIA5SubstringsFilter(
2617         slap_mask_t use,
2618         slap_mask_t flags,
2619         Syntax *syntax,
2620         MatchingRule *mr,
2621         struct berval *prefix,
2622         void * assertValue,
2623         BerVarray *keysp )
2624 {
2625         SubstringsAssertion *sa = assertValue;
2626         char pre;
2627         ber_len_t nkeys = 0;
2628         size_t slen, mlen, klen;
2629         BerVarray keys;
2630         HASH_CONTEXT   HASHcontext;
2631         unsigned char   HASHdigest[HASH_BYTES];
2632         struct berval *value;
2633         struct berval digest;
2634
2635         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
2636                 sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2637         {
2638                 nkeys++;
2639         }
2640
2641         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
2642                 ber_len_t i;
2643                 for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
2644                         if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
2645                                 /* don't bother accounting for stepping */
2646                                 nkeys += sa->sa_any[i].bv_len -
2647                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
2648                         }
2649                 }
2650         }
2651
2652         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
2653                 sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2654         {
2655                 nkeys++;
2656         }
2657
2658         if( nkeys == 0 ) {
2659                 *keysp = NULL;
2660                 return LDAP_SUCCESS;
2661         }
2662
2663         digest.bv_val = HASHdigest;
2664         digest.bv_len = sizeof(HASHdigest);
2665
2666         slen = syntax->ssyn_oidlen;
2667         mlen = mr->smr_oidlen;
2668
2669         keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
2670         nkeys = 0;
2671
2672         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
2673                 sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2674         {
2675                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
2676                 value = &sa->sa_initial;
2677
2678                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2679                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2680
2681                 HASH_Init( &HASHcontext );
2682                 if( prefix != NULL && prefix->bv_len > 0 ) {
2683                         HASH_Update( &HASHcontext,
2684                                 prefix->bv_val, prefix->bv_len );
2685                 }
2686                 HASH_Update( &HASHcontext,
2687                         &pre, sizeof( pre ) );
2688                 HASH_Update( &HASHcontext,
2689                         syntax->ssyn_oid, slen );
2690                 HASH_Update( &HASHcontext,
2691                         mr->smr_oid, mlen );
2692                 HASH_Update( &HASHcontext,
2693                         value->bv_val, klen );
2694                 HASH_Final( HASHdigest, &HASHcontext );
2695
2696                 ber_dupbv( &keys[nkeys++], &digest );
2697         }
2698
2699         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
2700                 ber_len_t i, j;
2701                 pre = SLAP_INDEX_SUBSTR_PREFIX;
2702                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
2703
2704                 for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
2705                         if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
2706                                 continue;
2707                         }
2708
2709                         value = &sa->sa_any[i];
2710
2711                         for(j=0;
2712                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
2713                                 j += SLAP_INDEX_SUBSTR_STEP )
2714                         {
2715                                 HASH_Init( &HASHcontext );
2716                                 if( prefix != NULL && prefix->bv_len > 0 ) {
2717                                         HASH_Update( &HASHcontext,
2718                                                 prefix->bv_val, prefix->bv_len );
2719                                 }
2720                                 HASH_Update( &HASHcontext,
2721                                         &pre, sizeof( pre ) );
2722                                 HASH_Update( &HASHcontext,
2723                                         syntax->ssyn_oid, slen );
2724                                 HASH_Update( &HASHcontext,
2725                                         mr->smr_oid, mlen );
2726                                 HASH_Update( &HASHcontext,
2727                                         &value->bv_val[j], klen ); 
2728                                 HASH_Final( HASHdigest, &HASHcontext );
2729
2730                                 ber_dupbv( &keys[nkeys++], &digest );
2731                         }
2732                 }
2733         }
2734
2735         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
2736                 sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
2737         {
2738                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
2739                 value = &sa->sa_final;
2740
2741                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
2742                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
2743
2744                 HASH_Init( &HASHcontext );
2745                 if( prefix != NULL && prefix->bv_len > 0 ) {
2746                         HASH_Update( &HASHcontext,
2747                                 prefix->bv_val, prefix->bv_len );
2748                 }
2749                 HASH_Update( &HASHcontext,
2750                         &pre, sizeof( pre ) );
2751                 HASH_Update( &HASHcontext,
2752                         syntax->ssyn_oid, slen );
2753                 HASH_Update( &HASHcontext,
2754                         mr->smr_oid, mlen );
2755                 HASH_Update( &HASHcontext,
2756                         &value->bv_val[value->bv_len-klen], klen );
2757                 HASH_Final( HASHdigest, &HASHcontext );
2758
2759                 ber_dupbv( &keys[nkeys++], &digest );
2760         }
2761
2762         if( nkeys > 0 ) {
2763                 keys[nkeys].bv_val = NULL;
2764                 *keysp = keys;
2765         } else {
2766                 ch_free( keys );
2767                 *keysp = NULL;
2768         }
2769
2770         return LDAP_SUCCESS;
2771 }
2772         
2773 static int
2774 caseIgnoreIA5Match(
2775         int *matchp,
2776         slap_mask_t flags,
2777         Syntax *syntax,
2778         MatchingRule *mr,
2779         struct berval *value,
2780         void *assertedValue )
2781 {
2782         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
2783
2784         if( match == 0 && value->bv_len ) {
2785                 match = strncasecmp( value->bv_val,
2786                         ((struct berval *) assertedValue)->bv_val,
2787                         value->bv_len );
2788         }
2789
2790         *matchp = match;
2791         return LDAP_SUCCESS;
2792 }
2793
2794 static int
2795 caseIgnoreIA5SubstringsMatch(
2796         int *matchp,
2797         slap_mask_t flags,
2798         Syntax *syntax,
2799         MatchingRule *mr,
2800         struct berval *value,
2801         void *assertedValue )
2802 {
2803         int match = 0;
2804         SubstringsAssertion *sub = assertedValue;
2805         struct berval left = *value;
2806         int i;
2807         ber_len_t inlen=0;
2808
2809         /* Add up asserted input length */
2810         if( sub->sa_initial.bv_val ) {
2811                 inlen += sub->sa_initial.bv_len;
2812         }
2813         if( sub->sa_any ) {
2814                 for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
2815                         inlen += sub->sa_any[i].bv_len;
2816                 }
2817         }
2818         if( sub->sa_final.bv_val ) {
2819                 inlen += sub->sa_final.bv_len;
2820         }
2821
2822         if( sub->sa_initial.bv_val ) {
2823                 if( inlen > left.bv_len ) {
2824                         match = 1;
2825                         goto done;
2826                 }
2827
2828                 match = strncasecmp( sub->sa_initial.bv_val, left.bv_val,
2829                         sub->sa_initial.bv_len );
2830
2831                 if( match != 0 ) {
2832                         goto done;
2833                 }
2834
2835                 left.bv_val += sub->sa_initial.bv_len;
2836                 left.bv_len -= sub->sa_initial.bv_len;
2837                 inlen -= sub->sa_initial.bv_len;
2838         }
2839
2840         if( sub->sa_final.bv_val ) {
2841                 if( inlen > left.bv_len ) {
2842                         match = 1;
2843                         goto done;
2844                 }
2845
2846                 match = strncasecmp( sub->sa_final.bv_val,
2847                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
2848                         sub->sa_final.bv_len );
2849
2850                 if( match != 0 ) {
2851                         goto done;
2852                 }
2853
2854                 left.bv_len -= sub->sa_final.bv_len;
2855                 inlen -= sub->sa_final.bv_len;
2856         }
2857
2858         if( sub->sa_any ) {
2859                 for(i=0; sub->sa_any[i].bv_val; i++) {
2860                         ber_len_t idx;
2861                         char *p;
2862
2863 retry:
2864                         if( inlen > left.bv_len ) {
2865                                 /* not enough length */
2866                                 match = 1;
2867                                 goto done;
2868                         }
2869
2870                         if( sub->sa_any[i].bv_len == 0 ) {
2871                                 continue;
2872                         }
2873
2874                         p = bvcasechr( &left, *sub->sa_any[i].bv_val, &idx );
2875
2876                         if( p == NULL ) {
2877                                 match = 1;
2878                                 goto done;
2879                         }
2880
2881                         assert( idx < left.bv_len );
2882                         if( idx >= left.bv_len ) {
2883                                 /* this shouldn't happen */
2884                                 return LDAP_OTHER;
2885                         }
2886
2887                         left.bv_val = p;
2888                         left.bv_len -= idx;
2889
2890                         if( sub->sa_any[i].bv_len > left.bv_len ) {
2891                                 /* not enough left */
2892                                 match = 1;
2893                                 goto done;
2894                         }
2895
2896                         match = strncasecmp( left.bv_val,
2897                                 sub->sa_any[i].bv_val,
2898                                 sub->sa_any[i].bv_len );
2899
2900                         if( match != 0 ) {
2901                                 left.bv_val++;
2902                                 left.bv_len--;
2903
2904                                 goto retry;
2905                         }
2906
2907                         left.bv_val += sub->sa_any[i].bv_len;
2908                         left.bv_len -= sub->sa_any[i].bv_len;
2909                         inlen -= sub->sa_any[i].bv_len;
2910                 }
2911         }
2912
2913 done:
2914         *matchp = match;
2915         return LDAP_SUCCESS;
2916 }
2917
2918 /* Index generation function */
2919 static int caseIgnoreIA5Indexer(
2920         slap_mask_t use,
2921         slap_mask_t flags,
2922         Syntax *syntax,
2923         MatchingRule *mr,
2924         struct berval *prefix,
2925         BerVarray values,
2926         BerVarray *keysp )
2927 {
2928         int i;
2929         int rc = LDAP_SUCCESS;
2930         size_t slen, mlen;
2931         BerVarray keys;
2932         HASH_CONTEXT   HASHcontext;
2933         unsigned char   HASHdigest[HASH_BYTES];
2934         struct berval digest;
2935         digest.bv_val = HASHdigest;
2936         digest.bv_len = sizeof(HASHdigest);
2937
2938         /* we should have at least one value at this point */
2939         assert( values != NULL && values[0].bv_val != NULL );
2940
2941         for( i=0; values[i].bv_val != NULL; i++ ) {
2942                 /* just count them */
2943         }
2944
2945         keys = ch_malloc( sizeof( struct berval ) * (i+1) );
2946
2947         slen = syntax->ssyn_oidlen;
2948         mlen = mr->smr_oidlen;
2949
2950         for( i=0; values[i].bv_val != NULL; i++ ) {
2951                 struct berval value;
2952
2953                 if( mr->smr_normalize ) {
2954                         rc = (mr->smr_normalize)( use, syntax, mr, &values[i], &value );
2955                         if( rc != LDAP_SUCCESS ) {
2956                                 break;
2957                         }
2958                 } else if ( mr->smr_syntax->ssyn_normalize ) {
2959                         rc = (mr->smr_syntax->ssyn_normalize)( syntax, &values[i], &value );
2960                         if( rc != LDAP_SUCCESS ) {
2961                                 break;
2962                         }
2963                 } else {
2964                         ber_dupbv( &value, &values[i] );
2965                 }
2966
2967                 ldap_pvt_str2lower( value.bv_val );
2968
2969                 HASH_Init( &HASHcontext );
2970                 if( prefix != NULL && prefix->bv_len > 0 ) {
2971                         HASH_Update( &HASHcontext,
2972                                 prefix->bv_val, prefix->bv_len );
2973                 }
2974                 HASH_Update( &HASHcontext,
2975                         syntax->ssyn_oid, slen );
2976                 HASH_Update( &HASHcontext,
2977                         mr->smr_oid, mlen );
2978                 HASH_Update( &HASHcontext,
2979                         value.bv_val, value.bv_len );
2980                 HASH_Final( HASHdigest, &HASHcontext );
2981
2982                 free( value.bv_val );
2983
2984                 ber_dupbv( &keys[i], &digest );
2985         }
2986
2987         keys[i].bv_val = NULL;
2988         if( rc != LDAP_SUCCESS ) {
2989                 ber_bvarray_free( keys );
2990                 keys = NULL;
2991         }
2992         *keysp = keys;
2993         return rc;
2994 }
2995
2996 /* Index generation function */
2997 static int caseIgnoreIA5Filter(
2998         slap_mask_t use,
2999         slap_mask_t flags,
3000         Syntax *syntax,
3001         MatchingRule *mr,
3002         struct berval *prefix,
3003         void * assertValue,
3004         BerVarray *keysp )
3005 {
3006         size_t slen, mlen;
3007         BerVarray keys;
3008         HASH_CONTEXT   HASHcontext;
3009         unsigned char   HASHdigest[HASH_BYTES];
3010         struct berval value;
3011         struct berval digest;
3012         digest.bv_val = HASHdigest;
3013         digest.bv_len = sizeof(HASHdigest);
3014
3015         slen = syntax->ssyn_oidlen;
3016         mlen = mr->smr_oidlen;
3017
3018         ber_dupbv( &value, (struct berval *) assertValue );
3019         ldap_pvt_str2lower( value.bv_val );
3020
3021         keys = ch_malloc( sizeof( struct berval ) * 2 );
3022
3023         HASH_Init( &HASHcontext );
3024         if( prefix != NULL && prefix->bv_len > 0 ) {
3025                 HASH_Update( &HASHcontext,
3026                         prefix->bv_val, prefix->bv_len );
3027         }
3028         HASH_Update( &HASHcontext,
3029                 syntax->ssyn_oid, slen );
3030         HASH_Update( &HASHcontext,
3031                 mr->smr_oid, mlen );
3032         HASH_Update( &HASHcontext,
3033                 value.bv_val, value.bv_len );
3034         HASH_Final( HASHdigest, &HASHcontext );
3035
3036         ber_dupbv( &keys[0], &digest );
3037         keys[1].bv_val = NULL;
3038
3039         free( value.bv_val );
3040
3041         *keysp = keys;
3042
3043         return LDAP_SUCCESS;
3044 }
3045
3046 /* Substrings Index generation function */
3047 static int caseIgnoreIA5SubstringsIndexer(
3048         slap_mask_t use,
3049         slap_mask_t flags,
3050         Syntax *syntax,
3051         MatchingRule *mr,
3052         struct berval *prefix,
3053         BerVarray values,
3054         BerVarray *keysp )
3055 {
3056         ber_len_t i, nkeys;
3057         size_t slen, mlen;
3058         BerVarray keys;
3059         HASH_CONTEXT   HASHcontext;
3060         unsigned char   HASHdigest[HASH_BYTES];
3061         struct berval digest;
3062         digest.bv_val = HASHdigest;
3063         digest.bv_len = sizeof(HASHdigest);
3064
3065         /* we should have at least one value at this point */
3066         assert( values != NULL && values[0].bv_val != NULL );
3067
3068         nkeys=0;
3069         for( i=0; values[i].bv_val != NULL; i++ ) {
3070                 /* count number of indices to generate */
3071                 if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
3072                         continue;
3073                 }
3074
3075                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
3076                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3077                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
3078                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
3079                         } else {
3080                                 nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
3081                         }
3082                 }
3083
3084                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
3085                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3086                                 nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
3087                         }
3088                 }
3089
3090                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
3091                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3092                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
3093                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
3094                         } else {
3095                                 nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
3096                         }
3097                 }
3098         }
3099
3100         if( nkeys == 0 ) {
3101                 /* no keys to generate */
3102                 *keysp = NULL;
3103                 return LDAP_SUCCESS;
3104         }
3105
3106         keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
3107
3108         slen = syntax->ssyn_oidlen;
3109         mlen = mr->smr_oidlen;
3110
3111         nkeys=0;
3112         for( i=0; values[i].bv_val != NULL; i++ ) {
3113                 int j,max;
3114                 struct berval value;
3115
3116                 if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
3117
3118                 ber_dupbv( &value, &values[i] );
3119                 ldap_pvt_str2lower( value.bv_val );
3120
3121                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
3122                         ( value.bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
3123                 {
3124                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
3125                         max = value.bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
3126
3127                         for( j=0; j<max; j++ ) {
3128                                 HASH_Init( &HASHcontext );
3129                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3130                                         HASH_Update( &HASHcontext,
3131                                                 prefix->bv_val, prefix->bv_len );
3132                                 }
3133
3134                                 HASH_Update( &HASHcontext,
3135                                         &pre, sizeof( pre ) );
3136                                 HASH_Update( &HASHcontext,
3137                                         syntax->ssyn_oid, slen );
3138                                 HASH_Update( &HASHcontext,
3139                                         mr->smr_oid, mlen );
3140                                 HASH_Update( &HASHcontext,
3141                                         &value.bv_val[j],
3142                                         SLAP_INDEX_SUBSTR_MAXLEN );
3143                                 HASH_Final( HASHdigest, &HASHcontext );
3144
3145                                 ber_dupbv( &keys[nkeys++], &digest );
3146                         }
3147                 }
3148
3149                 max = SLAP_INDEX_SUBSTR_MAXLEN < value.bv_len
3150                         ? SLAP_INDEX_SUBSTR_MAXLEN : value.bv_len;
3151
3152                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
3153                         char pre;
3154
3155                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
3156                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
3157                                 HASH_Init( &HASHcontext );
3158                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3159                                         HASH_Update( &HASHcontext,
3160                                                 prefix->bv_val, prefix->bv_len );
3161                                 }
3162                                 HASH_Update( &HASHcontext,
3163                                         &pre, sizeof( pre ) );
3164                                 HASH_Update( &HASHcontext,
3165                                         syntax->ssyn_oid, slen );
3166                                 HASH_Update( &HASHcontext,
3167                                         mr->smr_oid, mlen );
3168                                 HASH_Update( &HASHcontext,
3169                                         value.bv_val, j );
3170                                 HASH_Final( HASHdigest, &HASHcontext );
3171
3172                                 ber_dupbv( &keys[nkeys++], &digest );
3173                         }
3174
3175                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
3176                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
3177                                 HASH_Init( &HASHcontext );
3178                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3179                                         HASH_Update( &HASHcontext,
3180                                                 prefix->bv_val, prefix->bv_len );
3181                                 }
3182                                 HASH_Update( &HASHcontext,
3183                                         &pre, sizeof( pre ) );
3184                                 HASH_Update( &HASHcontext,
3185                                         syntax->ssyn_oid, slen );
3186                                 HASH_Update( &HASHcontext,
3187                                         mr->smr_oid, mlen );
3188                                 HASH_Update( &HASHcontext,
3189                                         &value.bv_val[value.bv_len-j], j );
3190                                 HASH_Final( HASHdigest, &HASHcontext );
3191
3192                                 ber_dupbv( &keys[nkeys++], &digest );
3193                         }
3194
3195                 }
3196
3197                 free( value.bv_val );
3198         }
3199
3200         if( nkeys > 0 ) {
3201                 keys[nkeys].bv_val = NULL;
3202                 *keysp = keys;
3203         } else {
3204                 ch_free( keys );
3205                 *keysp = NULL;
3206         }
3207
3208         return LDAP_SUCCESS;
3209 }
3210
3211 static int caseIgnoreIA5SubstringsFilter(
3212         slap_mask_t use,
3213         slap_mask_t flags,
3214         Syntax *syntax,
3215         MatchingRule *mr,
3216         struct berval *prefix,
3217         void * assertValue,
3218         BerVarray *keysp )
3219 {
3220         SubstringsAssertion *sa = assertValue;
3221         char pre;
3222         ber_len_t nkeys = 0;
3223         size_t slen, mlen, klen;
3224         BerVarray keys;
3225         HASH_CONTEXT   HASHcontext;
3226         unsigned char   HASHdigest[HASH_BYTES];
3227         struct berval value;
3228         struct berval digest;
3229
3230         if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial.bv_val != NULL &&
3231                 sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3232         {
3233                 nkeys++;
3234         }
3235
3236         if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
3237                 ber_len_t i;
3238                 for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
3239                         if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
3240                                 /* don't bother accounting for stepping */
3241                                 nkeys += sa->sa_any[i].bv_len -
3242                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
3243                         }
3244                 }
3245         }
3246
3247         if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final.bv_val != NULL &&
3248                 sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3249         {
3250                 nkeys++;
3251         }
3252
3253         if( nkeys == 0 ) {
3254                 *keysp = NULL;
3255                 return LDAP_SUCCESS;
3256         }
3257
3258         digest.bv_val = HASHdigest;
3259         digest.bv_len = sizeof(HASHdigest);
3260
3261         slen = syntax->ssyn_oidlen;
3262         mlen = mr->smr_oidlen;
3263
3264         keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
3265         nkeys = 0;
3266
3267         if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial.bv_val != NULL &&
3268                 sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3269         {
3270                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
3271                 ber_dupbv( &value, &sa->sa_initial );
3272                 ldap_pvt_str2lower( value.bv_val );
3273
3274                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value.bv_len
3275                         ? SLAP_INDEX_SUBSTR_MAXLEN : value.bv_len;
3276
3277                 HASH_Init( &HASHcontext );
3278                 if( prefix != NULL && prefix->bv_len > 0 ) {
3279                         HASH_Update( &HASHcontext,
3280                                 prefix->bv_val, prefix->bv_len );
3281                 }
3282                 HASH_Update( &HASHcontext,
3283                         &pre, sizeof( pre ) );
3284                 HASH_Update( &HASHcontext,
3285                         syntax->ssyn_oid, slen );
3286                 HASH_Update( &HASHcontext,
3287                         mr->smr_oid, mlen );
3288                 HASH_Update( &HASHcontext,
3289                         value.bv_val, klen );
3290                 HASH_Final( HASHdigest, &HASHcontext );
3291
3292                 free( value.bv_val );
3293                 ber_dupbv( &keys[nkeys++], &digest );
3294         }
3295
3296         if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
3297                 ber_len_t i, j;
3298                 pre = SLAP_INDEX_SUBSTR_PREFIX;
3299                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
3300
3301                 for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
3302                         if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
3303                                 continue;
3304                         }
3305
3306                         ber_dupbv( &value, &sa->sa_any[i] );
3307                         ldap_pvt_str2lower( value.bv_val );
3308
3309                         for(j=0;
3310                                 j <= value.bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
3311                                 j += SLAP_INDEX_SUBSTR_STEP )
3312                         {
3313                                 HASH_Init( &HASHcontext );
3314                                 if( prefix != NULL && prefix->bv_len > 0 ) {
3315                                         HASH_Update( &HASHcontext,
3316                                                 prefix->bv_val, prefix->bv_len );
3317                                 }
3318                                 HASH_Update( &HASHcontext,
3319                                         &pre, sizeof( pre ) );
3320                                 HASH_Update( &HASHcontext,
3321                                         syntax->ssyn_oid, slen );
3322                                 HASH_Update( &HASHcontext,
3323                                         mr->smr_oid, mlen );
3324                                 HASH_Update( &HASHcontext,
3325                                         &value.bv_val[j], klen );
3326                                 HASH_Final( HASHdigest, &HASHcontext );
3327
3328                                 ber_dupbv( &keys[nkeys++], &digest );
3329                         }
3330
3331                         free( value.bv_val );
3332                 }
3333         }
3334
3335         if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final.bv_val != NULL &&
3336                 sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
3337         {
3338                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
3339                 ber_dupbv( &value, &sa->sa_final );
3340                 ldap_pvt_str2lower( value.bv_val );
3341
3342                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value.bv_len
3343                         ? SLAP_INDEX_SUBSTR_MAXLEN : value.bv_len;
3344
3345                 HASH_Init( &HASHcontext );
3346                 if( prefix != NULL && prefix->bv_len > 0 ) {
3347                         HASH_Update( &HASHcontext,
3348                                 prefix->bv_val, prefix->bv_len );
3349                 }
3350                 HASH_Update( &HASHcontext,
3351                         &pre, sizeof( pre ) );
3352                 HASH_Update( &HASHcontext,
3353                         syntax->ssyn_oid, slen );
3354                 HASH_Update( &HASHcontext,
3355                         mr->smr_oid, mlen );
3356                 HASH_Update( &HASHcontext,
3357                         &value.bv_val[value.bv_len-klen], klen );
3358                 HASH_Final( HASHdigest, &HASHcontext );
3359
3360                 free( value.bv_val );
3361                 ber_dupbv( &keys[nkeys++], &digest );
3362         }
3363
3364         if( nkeys > 0 ) {
3365                 keys[nkeys].bv_val = NULL;
3366                 *keysp = keys;
3367         } else {
3368                 ch_free( keys );
3369                 *keysp = NULL;
3370         }
3371
3372         return LDAP_SUCCESS;
3373 }
3374         
3375 static int
3376 numericStringValidate(
3377         Syntax *syntax,
3378         struct berval *in )
3379 {
3380         ber_len_t i;
3381
3382         if( in->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
3383
3384         for(i=0; i < in->bv_len; i++) {
3385                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
3386                         return LDAP_INVALID_SYNTAX;
3387                 }
3388         }
3389
3390         return LDAP_SUCCESS;
3391 }
3392
3393 static int
3394 numericStringNormalize(
3395         Syntax *syntax,
3396         struct berval *val,
3397         struct berval *normalized )
3398 {
3399         /* removal all spaces */
3400         char *p, *q;
3401
3402         assert( val->bv_len );
3403
3404         normalized->bv_val = ch_malloc( val->bv_len + 1 );
3405
3406         p = val->bv_val;
3407         q = normalized->bv_val;
3408
3409         while ( *p ) {
3410                 if ( ASCII_SPACE( *p ) ) {
3411                         /* Ignore whitespace */
3412                         p++;
3413                 } else {
3414                         *q++ = *p++;
3415                 }
3416         }
3417
3418         /* we should have copied no more then is in val */
3419         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
3420
3421         /* null terminate */
3422         *q = '\0';
3423
3424         normalized->bv_len = q - normalized->bv_val;
3425
3426         if( normalized->bv_len == 0 ) {
3427                 normalized->bv_val = ch_realloc( normalized->bv_val, 2 );
3428                 normalized->bv_val[0] = ' ';
3429                 normalized->bv_val[1] = '\0';
3430                 normalized->bv_len = 1;
3431         }
3432
3433         return LDAP_SUCCESS;
3434 }
3435
3436 static int
3437 objectIdentifierFirstComponentMatch(
3438         int *matchp,
3439         slap_mask_t flags,
3440         Syntax *syntax,
3441         MatchingRule *mr,
3442         struct berval *value,
3443         void *assertedValue )
3444 {
3445         int rc = LDAP_SUCCESS;
3446         int match;
3447         struct berval *asserted = (struct berval *) assertedValue;
3448         ber_len_t i;
3449         struct berval oid;
3450
3451         if( value->bv_len == 0 || value->bv_val[0] != '(' /*')'*/ ) {
3452                 return LDAP_INVALID_SYNTAX;
3453         }
3454
3455         /* trim leading white space */
3456         for( i=1; ASCII_SPACE(value->bv_val[i]) && i < value->bv_len; i++ ) {
3457                 /* empty */
3458         }
3459
3460         /* grab next word */
3461         oid.bv_val = &value->bv_val[i];
3462         oid.bv_len = value->bv_len - i;
3463         for( i=1; ASCII_SPACE(value->bv_val[i]) && i < oid.bv_len; i++ ) {
3464                 /* empty */
3465         }
3466         oid.bv_len = i;
3467
3468         /* insert attributeTypes, objectclass check here */
3469         if( OID_LEADCHAR(asserted->bv_val[0]) ) {
3470                 rc = objectIdentifierMatch( &match, flags, syntax, mr, &oid, asserted );
3471
3472         } else {
3473                 if ( !strcmp( syntax->ssyn_oid, SLAP_SYNTAX_MATCHINGRULES_OID ) ) {
3474                         MatchingRule *asserted_mr = mr_bvfind( asserted );
3475                         MatchingRule *stored_mr = mr_bvfind( &oid );
3476
3477                         if( asserted_mr == NULL ) {
3478                                 rc = SLAPD_COMPARE_UNDEFINED;
3479                         } else {
3480                                 match = asserted_mr != stored_mr;
3481                         }
3482
3483                 } else if ( !strcmp( syntax->ssyn_oid,
3484                         SLAP_SYNTAX_ATTRIBUTETYPES_OID ) )
3485                 {
3486                         AttributeType *asserted_at = at_bvfind( asserted );
3487                         AttributeType *stored_at = at_bvfind( &oid );
3488
3489                         if( asserted_at == NULL ) {
3490                                 rc = SLAPD_COMPARE_UNDEFINED;
3491                         } else {
3492                                 match = asserted_at != stored_at;
3493                         }
3494
3495                 } else if ( !strcmp( syntax->ssyn_oid,
3496                         SLAP_SYNTAX_OBJECTCLASSES_OID ) )
3497                 {
3498                         ObjectClass *asserted_oc = oc_bvfind( asserted );
3499                         ObjectClass *stored_oc = oc_bvfind( &oid );
3500
3501                         if( asserted_oc == NULL ) {
3502                                 rc = SLAPD_COMPARE_UNDEFINED;
3503                         } else {
3504                                 match = asserted_oc != stored_oc;
3505                         }
3506                 }
3507         }
3508
3509 #ifdef NEW_LOGGING
3510         LDAP_LOG( CONFIG, ENTRY, 
3511                 "objectIdentifierFirstComponentMatch: %d\n %s\n %s\n",
3512                 match, value->bv_val, asserted->bv_val );
3513 #else
3514         Debug( LDAP_DEBUG_ARGS, "objectIdentifierFirstComponentMatch "
3515                 "%d\n\t\"%s\"\n\t\"%s\"\n",
3516                 match, value->bv_val, asserted->bv_val );
3517 #endif
3518
3519
3520         if( rc == LDAP_SUCCESS ) *matchp = match;
3521         return rc;
3522 }
3523
3524 static int
3525 integerBitAndMatch(
3526         int *matchp,
3527         slap_mask_t flags,
3528         Syntax *syntax,
3529         MatchingRule *mr,
3530         struct berval *value,
3531         void *assertedValue )
3532 {
3533         long lValue, lAssertedValue;
3534
3535         /* safe to assume integers are NUL terminated? */
3536         lValue = strtoul(value->bv_val, NULL, 10);
3537         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE )
3538                 return LDAP_CONSTRAINT_VIOLATION;
3539
3540         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
3541         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX) && errno == ERANGE )
3542                 return LDAP_CONSTRAINT_VIOLATION;
3543
3544         *matchp = (lValue & lAssertedValue);
3545         return LDAP_SUCCESS;
3546 }
3547
3548 static int
3549 integerBitOrMatch(
3550         int *matchp,
3551         slap_mask_t flags,
3552         Syntax *syntax,
3553         MatchingRule *mr,
3554         struct berval *value,
3555         void *assertedValue )
3556 {
3557         long lValue, lAssertedValue;
3558
3559         /* safe to assume integers are NUL terminated? */
3560         lValue = strtoul(value->bv_val, NULL, 10);
3561         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE )
3562                 return LDAP_CONSTRAINT_VIOLATION;
3563
3564         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
3565         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX) && errno == ERANGE )
3566                 return LDAP_CONSTRAINT_VIOLATION;
3567
3568         *matchp = (lValue | lAssertedValue);
3569         return LDAP_SUCCESS;
3570 }
3571
3572 #ifdef HAVE_TLS
3573 #include <openssl/x509.h>
3574 #include <openssl/err.h>
3575 char digit[] = "0123456789";
3576
3577 /*
3578  * Next function returns a string representation of a ASN1_INTEGER.
3579  * It works for unlimited lengths.
3580  */
3581
3582 static struct berval *
3583 asn1_integer2str(ASN1_INTEGER *a, struct berval *bv)
3584 {
3585         char buf[256];
3586         char *p;
3587   
3588         /* We work backwards, make it fill from the end of buf */
3589         p = buf + sizeof(buf) - 1;
3590         *p = '\0';
3591
3592         if ( a == NULL || a->length == 0 ) {
3593                 *--p = '0';
3594         } else {
3595                 int i;
3596                 int n = a->length;
3597                 int base = 0;
3598                 unsigned int *copy;
3599
3600                 /* We want to preserve the original */
3601                 copy = ch_malloc(n*sizeof(unsigned int));
3602                 for (i = 0; i<n; i++) {
3603                         copy[i] = a->data[i];
3604                 }
3605
3606                 /* 
3607                  * base indicates the index of the most significant
3608                  * byte that might be nonzero.  When it goes off the
3609                  * end, we now there is nothing left to do.
3610                  */
3611                 while (base < n) {
3612                         unsigned int carry;
3613
3614                         carry = 0;
3615                         for (i = base; i<n; i++ ) {
3616                                 copy[i] += carry*256;
3617                                 carry = copy[i] % 10;
3618                                 copy[i] /= 10;
3619                         }
3620                         if (p <= buf+1) {
3621                                 /*
3622                                  * Way too large, we need to leave
3623                                  * room for sign if negative
3624                                  */
3625                                 free(copy);
3626                                 return NULL;
3627                         }
3628                         *--p = digit[carry];
3629                         if (copy[base] == 0)
3630                                 base++;
3631                 }
3632                 free(copy);
3633         }
3634
3635         if ( a->type == V_ASN1_NEG_INTEGER ) {
3636                 *--p = '-';
3637         }
3638
3639         return ber_str2bv( p, 0, 1, bv );
3640 }
3641
3642 /*
3643  * Given a certificate in DER format, extract the corresponding
3644  * assertion value for certificateExactMatch
3645  */
3646 static int
3647 certificateExactConvert(
3648         struct berval * in,
3649         struct berval * out )
3650 {
3651         X509 *xcert;
3652         unsigned char *p = in->bv_val;
3653         struct berval serial;
3654         struct berval issuer_dn;
3655
3656         xcert = d2i_X509(NULL, &p, in->bv_len);
3657         if ( !xcert ) {
3658 #ifdef NEW_LOGGING
3659                 LDAP_LOG( CONFIG, ENTRY, 
3660                         "certificateExactConvert: error parsing cert: %s\n",
3661                         ERR_error_string(ERR_get_error(),NULL), 0, 0 );
3662 #else
3663                 Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: "
3664                        "error parsing cert: %s\n",
3665                        ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
3666 #endif
3667                 return LDAP_INVALID_SYNTAX;
3668         }
3669
3670         if ( !asn1_integer2str(xcert->cert_info->serialNumber, &serial) ) {
3671                 X509_free(xcert);
3672                 return LDAP_INVALID_SYNTAX;
3673         }
3674         if ( dnX509normalize(X509_get_issuer_name(xcert), &issuer_dn ) != LDAP_SUCCESS ) {
3675                 X509_free(xcert);
3676                 ber_memfree(serial.bv_val);
3677                 return LDAP_INVALID_SYNTAX;
3678         }
3679
3680         X509_free(xcert);
3681
3682         out->bv_len = serial.bv_len + issuer_dn.bv_len + sizeof(" $ ");
3683         out->bv_val = ch_malloc(out->bv_len);
3684         p = out->bv_val;
3685         AC_MEMCPY(p, serial.bv_val, serial.bv_len);
3686         p += serial.bv_len;
3687         AC_MEMCPY(p, " $ ", sizeof(" $ ")-1);
3688         p += 3;
3689         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3690         p += issuer_dn.bv_len;
3691         *p++ = '\0';
3692
3693 #ifdef NEW_LOGGING
3694         LDAP_LOG( CONFIG, ARGS, 
3695                 "certificateExactConvert: \n    %s\n", out->bv_val, 0, 0 );
3696 #else
3697         Debug( LDAP_DEBUG_ARGS, "certificateExactConvert "
3698                 "\n\t\"%s\"\n",
3699                 out->bv_val, NULL, NULL );
3700 #endif
3701
3702         ber_memfree(serial.bv_val);
3703         ber_memfree(issuer_dn.bv_val);
3704
3705         return LDAP_SUCCESS;
3706 }
3707
3708 static int
3709 serial_and_issuer_parse(
3710         struct berval *assertion,
3711         struct berval *serial,
3712         struct berval *issuer_dn
3713 )
3714 {
3715         char *begin;
3716         char *end;
3717         char *p;
3718         struct berval bv;
3719
3720         begin = assertion->bv_val;
3721         end = assertion->bv_val+assertion->bv_len-1;
3722         for (p=begin; p<=end && *p != '$'; p++)
3723                 ;
3724         if ( p > end )
3725                 return LDAP_INVALID_SYNTAX;
3726
3727         /* p now points at the $ sign, now use begin and end to delimit the
3728            serial number */
3729         while (ASCII_SPACE(*begin))
3730                 begin++;
3731         end = p-1;
3732         while (ASCII_SPACE(*end))
3733                 end--;
3734
3735         bv.bv_len = end-begin+1;
3736         bv.bv_val = begin;
3737         ber_dupbv(serial, &bv);
3738
3739         /* now extract the issuer, remember p was at the dollar sign */
3740         if ( issuer_dn ) {
3741                 begin = p+1;
3742                 end = assertion->bv_val+assertion->bv_len-1;
3743                 while (ASCII_SPACE(*begin))
3744                         begin++;
3745                 /* should we trim spaces at the end too? is it safe always? */
3746
3747                 bv.bv_len = end-begin+1;
3748                 bv.bv_val = begin;
3749                 dnNormalize2( NULL, &bv, issuer_dn );
3750         }
3751
3752         return LDAP_SUCCESS;
3753 }
3754
3755 static int
3756 certificateExactMatch(
3757         int *matchp,
3758         slap_mask_t flags,
3759         Syntax *syntax,
3760         MatchingRule *mr,
3761         struct berval *value,
3762         void *assertedValue )
3763 {
3764         X509 *xcert;
3765         unsigned char *p = value->bv_val;
3766         struct berval serial;
3767         struct berval issuer_dn;
3768         struct berval asserted_serial;
3769         struct berval asserted_issuer_dn;
3770         int ret;
3771
3772         xcert = d2i_X509(NULL, &p, value->bv_len);
3773         if ( !xcert ) {
3774 #ifdef NEW_LOGGING
3775                 LDAP_LOG( CONFIG, ENTRY, 
3776                         "certificateExactMatch: error parsing cert: %s\n",
3777                         ERR_error_string(ERR_get_error(),NULL), 0, 0 );
3778 #else
3779                 Debug( LDAP_DEBUG_ARGS, "certificateExactMatch: "
3780                        "error parsing cert: %s\n",
3781                        ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
3782 #endif
3783                 return LDAP_INVALID_SYNTAX;
3784         }
3785
3786         asn1_integer2str(xcert->cert_info->serialNumber, &serial);
3787         dnX509normalize(X509_get_issuer_name(xcert), &issuer_dn);
3788
3789         X509_free(xcert);
3790
3791         serial_and_issuer_parse(assertedValue,
3792                                 &asserted_serial,
3793                                 &asserted_issuer_dn);
3794
3795         ret = integerMatch(
3796                 matchp,
3797                 flags,
3798                 slap_schema.si_syn_integer,
3799                 slap_schema.si_mr_integerMatch,
3800                 &serial,
3801                 &asserted_serial);
3802         if ( ret == LDAP_SUCCESS ) {
3803                 if ( *matchp == 0 ) {
3804                         /* We need to normalize everything for dnMatch */
3805                         ret = dnMatch(
3806                                 matchp,
3807                                 flags,
3808                                 slap_schema.si_syn_distinguishedName,
3809                                 slap_schema.si_mr_distinguishedNameMatch,
3810                                 &issuer_dn,
3811                                 &asserted_issuer_dn);
3812                 }
3813         }
3814
3815 #ifdef NEW_LOGGING
3816         LDAP_LOG( CONFIG, ARGS, "certificateExactMatch "
3817                 "%d\n\t\"%s $ %s\"\n",
3818                 *matchp, serial.bv_val, issuer_dn.bv_val );
3819         LDAP_LOG( CONFIG, ARGS, "\t\"%s $ %s\"\n",
3820                 asserted_serial.bv_val, asserted_issuer_dn.bv_val,
3821                 0 );
3822 #else
3823         Debug( LDAP_DEBUG_ARGS, "certificateExactMatch "
3824                 "%d\n\t\"%s $ %s\"\n",
3825                 *matchp, serial.bv_val, issuer_dn.bv_val );
3826         Debug( LDAP_DEBUG_ARGS, "\t\"%s $ %s\"\n",
3827                 asserted_serial.bv_val, asserted_issuer_dn.bv_val,
3828                 NULL );
3829 #endif
3830
3831         ber_memfree(serial.bv_val);
3832         ber_memfree(issuer_dn.bv_val);
3833         ber_memfree(asserted_serial.bv_val);
3834         ber_memfree(asserted_issuer_dn.bv_val);
3835
3836         return ret;
3837 }
3838
3839 /* 
3840  * Index generation function
3841  * We just index the serials, in most scenarios the issuer DN is one of
3842  * a very small set of values.
3843  */
3844 static int certificateExactIndexer(
3845         slap_mask_t use,
3846         slap_mask_t flags,
3847         Syntax *syntax,
3848         MatchingRule *mr,
3849         struct berval *prefix,
3850         BerVarray values,
3851         BerVarray *keysp )
3852 {
3853         int i;
3854         BerVarray keys;
3855         X509 *xcert;
3856         unsigned char *p;
3857         struct berval serial;
3858
3859         /* we should have at least one value at this point */
3860         assert( values != NULL && values[0].bv_val != NULL );
3861
3862         for( i=0; values[i].bv_val != NULL; i++ ) {
3863                 /* empty -- just count them */
3864         }
3865
3866         keys = ch_malloc( sizeof( struct berval ) * (i+1) );
3867
3868         for( i=0; values[i].bv_val != NULL; i++ ) {
3869                 p = values[i].bv_val;
3870                 xcert = d2i_X509(NULL, &p, values[i].bv_len);
3871                 if ( !xcert ) {
3872 #ifdef NEW_LOGGING
3873                         LDAP_LOG( CONFIG, ENTRY, 
3874                                 "certificateExactIndexer: error parsing cert: %s\n",
3875                                 ERR_error_string(ERR_get_error(),NULL), 0, 0);
3876 #else
3877                         Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
3878                                "error parsing cert: %s\n",
3879                                ERR_error_string(ERR_get_error(),NULL),
3880                                NULL, NULL );
3881 #endif
3882                         /* Do we leak keys on error? */
3883                         return LDAP_INVALID_SYNTAX;
3884                 }
3885
3886                 asn1_integer2str(xcert->cert_info->serialNumber, &serial);
3887                 X509_free(xcert);
3888                 integerNormalize( slap_schema.si_syn_integer,
3889                                   &serial,
3890                                   &keys[i] );
3891                 ber_memfree(serial.bv_val);
3892 #ifdef NEW_LOGGING
3893                 LDAP_LOG( CONFIG, ENTRY, 
3894                         "certificateExactIndexer: returning: %s\n", keys[i].bv_val, 0, 0);
3895 #else
3896                 Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
3897                        "returning: %s\n",
3898                        keys[i].bv_val,
3899                        NULL, NULL );
3900 #endif
3901         }
3902
3903         keys[i].bv_val = NULL;
3904         *keysp = keys;
3905         return LDAP_SUCCESS;
3906 }
3907
3908 /* Index generation function */
3909 /* We think this is always called with a value in matching rule syntax */
3910 static int certificateExactFilter(
3911         slap_mask_t use,
3912         slap_mask_t flags,
3913         Syntax *syntax,
3914         MatchingRule *mr,
3915         struct berval *prefix,
3916         void * assertValue,
3917         BerVarray *keysp )
3918 {
3919         BerVarray keys;
3920         struct berval asserted_serial;
3921
3922         serial_and_issuer_parse(assertValue,
3923                                 &asserted_serial,
3924                                 NULL);
3925
3926         keys = ch_malloc( sizeof( struct berval ) * 2 );
3927         integerNormalize( syntax, &asserted_serial, &keys[0] );
3928         keys[1].bv_val = NULL;
3929         *keysp = keys;
3930
3931         ber_memfree(asserted_serial.bv_val);
3932         return LDAP_SUCCESS;
3933 }
3934 #endif
3935
3936 static int
3937 check_time_syntax (struct berval *val,
3938         int start,
3939         int *parts)
3940 {
3941         static int ceiling[9] = { 99, 99, 11, 30, 23, 59, 59, 12, 59 };
3942         static int mdays[2][12] = {
3943                 /* non-leap years */
3944                 { 30, 27, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 },
3945                 /* leap years */
3946                 { 30, 28, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 }
3947         };
3948         char *p, *e;
3949         int part, c, tzoffset, leapyear = 0 ;
3950
3951         if( val->bv_len == 0 ) {
3952                 return LDAP_INVALID_SYNTAX;
3953         }
3954
3955         p = (char *)val->bv_val;
3956         e = p + val->bv_len;
3957
3958         /* Ignore initial whitespace */
3959         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
3960                 p++;
3961         }
3962
3963         if (e - p < 13 - (2 * start)) {
3964                 return LDAP_INVALID_SYNTAX;
3965         }
3966
3967         for (part = 0; part < 9; part++) {
3968                 parts[part] = 0;
3969         }
3970
3971         for (part = start; part < 7; part++) {
3972                 c = *p;
3973                 if ((part == 6) && (c == 'Z' || c == '+' || c == '-')) {
3974                         part++;
3975                         break;
3976                 }
3977                 p++;
3978                 c -= '0';
3979                 if (p == e) {
3980                         return LDAP_INVALID_SYNTAX;
3981                 }
3982                 if (c < 0 || c > 9) {
3983                         return LDAP_INVALID_SYNTAX;
3984                 }
3985                 parts[part] = c;
3986
3987                 c = *p++ - '0';
3988                 if (p == e) {
3989                         return LDAP_INVALID_SYNTAX;
3990                 }
3991                 if (c < 0 || c > 9) {
3992                         return LDAP_INVALID_SYNTAX;
3993                 }
3994                 parts[part] *= 10;
3995                 parts[part] += c;
3996
3997                 if (part == 2 || part == 3) {
3998                         parts[part]--;
3999                 }
4000                 if (parts[part] < 0) {
4001                         return LDAP_INVALID_SYNTAX;
4002                 }
4003                 if (parts[part] > ceiling[part]) {
4004                         return LDAP_INVALID_SYNTAX;
4005                 }
4006         }
4007
4008         /* leapyear check for the Gregorian calendar (year>1581) */
4009         if (((parts[1] % 4 == 0) && (parts[1] != 0)) ||
4010                 ((parts[0] % 4 == 0) && (parts[1] == 0)))
4011         {
4012                 leapyear = 1;
4013         }
4014
4015         if (parts[3] > mdays[leapyear][parts[2]]) {
4016                 return LDAP_INVALID_SYNTAX;
4017         }
4018         
4019         c = *p++;
4020         if (c == 'Z') {
4021                 tzoffset = 0; /* UTC */
4022         } else if (c != '+' && c != '-') {
4023                 return LDAP_INVALID_SYNTAX;
4024         } else {
4025                 if (c == '-') {
4026                         tzoffset = -1;
4027                 } else /* c == '+' */ {
4028                         tzoffset = 1;
4029                 }
4030
4031                 if (p > e - 4) {
4032                         return LDAP_INVALID_SYNTAX;
4033                 }
4034
4035                 for (part = 7; part < 9; part++) {
4036                         c = *p++ - '0';
4037                         if (c < 0 || c > 9) {
4038                                 return LDAP_INVALID_SYNTAX;
4039                         }
4040                         parts[part] = c;
4041
4042                         c = *p++ - '0';
4043                         if (c < 0 || c > 9) {
4044                                 return LDAP_INVALID_SYNTAX;
4045                         }
4046                         parts[part] *= 10;
4047                         parts[part] += c;
4048                         if (parts[part] < 0 || parts[part] > ceiling[part]) {
4049                                 return LDAP_INVALID_SYNTAX;
4050                         }
4051                 }
4052         }
4053
4054         /* Ignore trailing whitespace */
4055         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
4056                 p++;
4057         }
4058         if (p != e) {
4059                 return LDAP_INVALID_SYNTAX;
4060         }
4061
4062         switch ( tzoffset ) {
4063         case -1: /* negativ offset to UTC, ie west of Greenwich  */
4064                 parts[4] += parts[7];
4065                 parts[5] += parts[8];
4066                 for (part = 6; --part > 0; ) { /* offset is just hhmm, no seconds */
4067                         if (part != 3) {
4068                                 c = ceiling[part];
4069                         } else {
4070                                 c = mdays[leapyear][parts[2]];
4071                         }
4072                         if (parts[part] > c) {
4073                                 parts[part] -= c + 1;
4074                                 parts[part - 1]++;
4075                         }
4076                 }
4077                 break;
4078         case 1: /* positive offset to UTC, ie east of Greenwich */
4079                 parts[4] -= parts[7];
4080                 parts[5] -= parts[8];
4081                 for (part = 6; --part > 0; ) {
4082                         if (part != 3) {
4083                                 c = ceiling[part];
4084                         } else {
4085                                 /* first arg to % needs to be non negativ */
4086                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
4087                         }
4088                         if (parts[part] < 0) {
4089                                 parts[part] += c + 1;
4090                                 parts[part - 1]--;
4091                         }
4092                 }
4093                 break;
4094         case 0: /* already UTC */
4095                 break;
4096         }
4097
4098         return LDAP_SUCCESS;
4099 }
4100
4101 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4102 static int
4103 utcTimeNormalize(
4104         Syntax *syntax,
4105         struct berval *val,
4106         struct berval *normalized )
4107 {
4108         int parts[9], rc;
4109
4110         rc = check_time_syntax(val, 1, parts);
4111         if (rc != LDAP_SUCCESS) {
4112                 return rc;
4113         }
4114
4115         normalized->bv_val = ch_malloc( 14 );
4116         if ( normalized->bv_val == NULL ) {
4117                 return LBER_ERROR_MEMORY;
4118         }
4119
4120         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
4121                 parts[1], parts[2] + 1, parts[3] + 1,
4122                 parts[4], parts[5], parts[6] );
4123         normalized->bv_len = 13;
4124
4125         return LDAP_SUCCESS;
4126 }
4127 #endif
4128
4129 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4130 static int
4131 utcTimeValidate(
4132         Syntax *syntax,
4133         struct berval *in )
4134 {
4135         int parts[9];
4136
4137         return check_time_syntax(in, 1, parts);
4138 }
4139 #endif
4140
4141 static int
4142 generalizedTimeValidate(
4143         Syntax *syntax,
4144         struct berval *in )
4145 {
4146         int parts[9];
4147
4148         return check_time_syntax(in, 0, parts);
4149 }
4150
4151 static int
4152 generalizedTimeNormalize(
4153         Syntax *syntax,
4154         struct berval *val,
4155         struct berval *normalized )
4156 {
4157         int parts[9], rc;
4158
4159         rc = check_time_syntax(val, 0, parts);
4160         if (rc != LDAP_SUCCESS) {
4161                 return rc;
4162         }
4163
4164         normalized->bv_val = ch_malloc( 16 );
4165         if ( normalized->bv_val == NULL ) {
4166                 return LBER_ERROR_MEMORY;
4167         }
4168
4169         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02dZ",
4170                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
4171                 parts[4], parts[5], parts[6] );
4172         normalized->bv_len = 15;
4173
4174         return LDAP_SUCCESS;
4175 }
4176
4177 static int
4178 nisNetgroupTripleValidate(
4179         Syntax *syntax,
4180         struct berval *val )
4181 {
4182         char *p, *e;
4183         int commas = 0;
4184
4185         if ( val->bv_len == 0 ) {
4186                 return LDAP_INVALID_SYNTAX;
4187         }
4188
4189         p = (char *)val->bv_val;
4190         e = p + val->bv_len;
4191
4192         if ( *p != '(' /*')'*/ ) {
4193                 return LDAP_INVALID_SYNTAX;
4194         }
4195
4196         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
4197                 if ( *p == ',' ) {
4198                         commas++;
4199                         if ( commas > 2 ) {
4200                                 return LDAP_INVALID_SYNTAX;
4201                         }
4202
4203                 } else if ( !AD_CHAR( *p ) ) {
4204                         return LDAP_INVALID_SYNTAX;
4205                 }
4206         }
4207
4208         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4209                 return LDAP_INVALID_SYNTAX;
4210         }
4211
4212         p++;
4213
4214         if (p != e) {
4215                 return LDAP_INVALID_SYNTAX;
4216         }
4217
4218         return LDAP_SUCCESS;
4219 }
4220
4221 static int
4222 bootParameterValidate(
4223         Syntax *syntax,
4224         struct berval *val )
4225 {
4226         char *p, *e;
4227
4228         if ( val->bv_len == 0 ) {
4229                 return LDAP_INVALID_SYNTAX;
4230         }
4231
4232         p = (char *)val->bv_val;
4233         e = p + val->bv_len;
4234
4235         /* key */
4236         for (; ( p < e ) && ( *p != '=' ); p++ ) {
4237                 if ( !AD_CHAR( *p ) ) {
4238                         return LDAP_INVALID_SYNTAX;
4239                 }
4240         }
4241
4242         if ( *p != '=' ) {
4243                 return LDAP_INVALID_SYNTAX;
4244         }
4245
4246         /* server */
4247         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4248                 if ( !AD_CHAR( *p ) ) {
4249                         return LDAP_INVALID_SYNTAX;
4250                 }
4251         }
4252
4253         if ( *p != ':' ) {
4254                 return LDAP_INVALID_SYNTAX;
4255         }
4256
4257         /* path */
4258         for ( p++; p < e; p++ ) {
4259                 if ( !SLAP_PRINTABLE( *p ) ) {
4260                         return LDAP_INVALID_SYNTAX;
4261                 }
4262         }
4263
4264         return LDAP_SUCCESS;
4265 }
4266
4267 static struct syntax_defs_rec {
4268         char *sd_desc;
4269 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4270 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4271         int sd_flags;
4272         slap_syntax_validate_func *sd_validate;
4273         slap_syntax_transform_func *sd_normalize;
4274         slap_syntax_transform_func *sd_pretty;
4275 #ifdef SLAPD_BINARY_CONVERSION
4276         slap_syntax_transform_func *sd_ber2str;
4277         slap_syntax_transform_func *sd_str2ber;
4278 #endif
4279 } syntax_defs[] = {
4280         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4281                 X_BINARY X_NOT_H_R ")",
4282                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4283         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4284                 0, NULL, NULL, NULL},
4285         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4286                 0, NULL, NULL, NULL},
4287         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4288                 X_NOT_H_R ")",
4289                 SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
4290         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4291                 X_NOT_H_R ")",
4292                 SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4293         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4294                 0, bitStringValidate, bitStringNormalize, NULL },
4295         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4296                 0, booleanValidate, NULL, NULL},
4297         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4298                 X_BINARY X_NOT_H_R ")",
4299                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4300         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4301                 X_BINARY X_NOT_H_R ")",
4302                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4303         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4304                 X_BINARY X_NOT_H_R ")",
4305                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4306         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4307                 0, countryStringValidate, IA5StringNormalize, NULL},
4308         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4309                 0, dnValidate, dnNormalize2, dnPretty2},
4310         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4311                 0, NULL, NULL, NULL},
4312         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4313                 0, NULL, NULL, NULL},
4314         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4315                 0, UTF8StringValidate, UTF8StringNormalize, NULL},
4316         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4317                 0, NULL, NULL, NULL},
4318         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4319                 0, NULL, NULL, NULL},
4320         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4321                 0, NULL, NULL, NULL},
4322         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4323                 0, NULL, NULL, NULL},
4324         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4325                 0, NULL, NULL, NULL},
4326         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4327                 0, printablesStringValidate, telephoneNumberNormalize, NULL},
4328         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4329                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4330         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4331                 0, generalizedTimeValidate, generalizedTimeNormalize, NULL},
4332         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4333                 0, NULL, NULL, NULL},
4334         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4335                 0, IA5StringValidate, IA5StringNormalize, NULL},
4336         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4337                 0, integerValidate, integerNormalize, NULL},
4338         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4339                 SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
4340         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4341                 0, NULL, NULL, NULL},
4342         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4343                 0, NULL, NULL, NULL},
4344         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4345                 0, NULL, NULL, NULL},
4346         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4347                 0, NULL, NULL, NULL},
4348         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4349                 0, NULL, NULL, NULL},
4350         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4351                 0, nameUIDValidate, nameUIDNormalize, NULL},
4352         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4353                 0, NULL, NULL, NULL},
4354         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4355                 0, numericStringValidate, numericStringNormalize, NULL},
4356         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4357                 0, NULL, NULL, NULL},
4358         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4359                 0, oidValidate, NULL, NULL},
4360         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4361                 0, IA5StringValidate, IA5StringNormalize, NULL},
4362         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4363                 0, blobValidate, NULL, NULL},
4364         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4365                 0, UTF8StringValidate, UTF8StringNormalize, NULL},
4366         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4367                 0, NULL, NULL, NULL},
4368         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4369                 0, NULL, NULL, NULL},
4370         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4371                 0, printableStringValidate, IA5StringNormalize, NULL},
4372         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' "
4373                 X_BINARY X_NOT_H_R ")",
4374                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4375         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4376                 X_BINARY X_NOT_H_R ")",
4377                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
4378         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4379                 0, printableStringValidate, telephoneNumberNormalize, NULL},
4380         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4381                 0, NULL, NULL, NULL},
4382         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4383                 0, printablesStringValidate, IA5StringNormalize, NULL},
4384 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4385         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4386                 0, utcTimeValidate, utcTimeNormalize, NULL},
4387 #endif
4388         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4389                 0, NULL, NULL, NULL},
4390         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4391                 0, NULL, NULL, NULL},
4392         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4393                 0, NULL, NULL, NULL},
4394         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4395                 0, NULL, NULL, NULL},
4396         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4397                 0, NULL, NULL, NULL},
4398
4399         /* RFC 2307 NIS Syntaxes */
4400         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4401                 0, nisNetgroupTripleValidate, NULL, NULL},
4402         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4403                 0, bootParameterValidate, NULL, NULL},
4404
4405 #ifdef HAVE_TLS
4406         /* From PKIX */
4407         /* These OIDs are not published yet, but will be in the next
4408          * I-D for PKIX LDAPv3 schema as have been advanced by David
4409          * Chadwick in private mail.
4410          */
4411         {"( 1.2.826.0.1.3344810.7.1 DESC 'Serial Number and Issuer' )",
4412                 0, NULL, NULL, NULL},
4413 #endif
4414
4415         /* OpenLDAP Experimental Syntaxes */
4416 #ifdef SLAPD_ACI_ENABLED
4417         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
4418                 SLAP_SYNTAX_HIDE,
4419                 UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
4420                 NULL, NULL},
4421 #endif
4422
4423 #ifdef SLAPD_AUTHPASSWD
4424         /* needs updating */
4425         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4426                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4427 #endif
4428
4429         /* OpenLDAP Void Syntax */
4430         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4431                 SLAP_SYNTAX_HIDE, inValidate, NULL, NULL},
4432         {NULL, 0, NULL, NULL, NULL}
4433 };
4434
4435 /*
4436  * Other matching rules in X.520 that we do not use (yet):
4437  *
4438  * 2.5.13.9             numericStringOrderingMatch
4439  * 2.5.13.18    octetStringOrderingMatch
4440  * 2.5.13.19    octetStringSubstringsMatch
4441  * 2.5.13.25    uTCTimeMatch
4442  * 2.5.13.26    uTCTimeOrderingMatch
4443  * 2.5.13.31    directoryStringFirstComponentMatch
4444  * 2.5.13.32    wordMatch
4445  * 2.5.13.33    keywordMatch
4446  * 2.5.13.35    certificateMatch
4447  * 2.5.13.36    certificatePairExactMatch
4448  * 2.5.13.37    certificatePairMatch
4449  * 2.5.13.38    certificateListExactMatch
4450  * 2.5.13.39    certificateListMatch
4451  * 2.5.13.40    algorithmIdentifierMatch
4452  * 2.5.13.41    storedPrefixMatch
4453  * 2.5.13.42    attributeCertificateMatch
4454  * 2.5.13.43    readerAndKeyIDMatch
4455  * 2.5.13.44    attributeIntegrityMatch
4456  */
4457 static struct mrule_defs_rec {
4458         char *                                          mrd_desc;
4459         slap_mask_t                                     mrd_usage;
4460         slap_mr_convert_func *          mrd_convert;
4461         slap_mr_normalize_func *        mrd_normalize;
4462         slap_mr_match_func *            mrd_match;
4463         slap_mr_indexer_func *          mrd_indexer;
4464         slap_mr_filter_func *           mrd_filter;
4465
4466         char *                                          mrd_associated;
4467 } mrule_defs[] = {
4468         /*
4469          * EQUALITY matching rules must be listed after associated APPROX
4470          * matching rules.  So, we list all APPROX matching rules first.
4471          */
4472         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4473                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4474                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT,
4475                 NULL, NULL,
4476                 directoryStringApproxMatch,
4477                 directoryStringApproxIndexer, 
4478                 directoryStringApproxFilter,
4479                 NULL},
4480
4481         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4482                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4483                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT,
4484                 NULL, NULL,
4485                 IA5StringApproxMatch,
4486                 IA5StringApproxIndexer, 
4487                 IA5StringApproxFilter,
4488                 NULL},
4489
4490         /*
4491          * Other matching rules
4492          */
4493         
4494         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4495                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4496                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4497                 NULL, NULL,
4498                 objectIdentifierMatch, caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
4499                 NULL},
4500
4501         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4502                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4503                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4504                 NULL, NULL,
4505                 dnMatch, dnIndexer, dnFilter,
4506                 NULL},
4507
4508         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4509                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4510                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
4511                 NULL, NULL,
4512                 caseIgnoreMatch, caseExactIgnoreIndexer, caseExactIgnoreFilter,
4513                 directoryStringApproxMatchOID },
4514
4515         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4516                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4517                 SLAP_MR_ORDERING,
4518                 NULL, NULL,
4519                 caseIgnoreOrderingMatch, NULL, NULL,
4520                 NULL},
4521
4522         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4523                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4524                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4525                 NULL, NULL,
4526                 caseExactIgnoreSubstringsMatch,
4527                 caseExactIgnoreSubstringsIndexer,
4528                 caseExactIgnoreSubstringsFilter,
4529                 NULL},
4530
4531         {"( 2.5.13.5 NAME 'caseExactMatch' "
4532                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4533                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4534                 NULL, NULL,
4535                 caseExactMatch, caseExactIgnoreIndexer, caseExactIgnoreFilter,
4536                 directoryStringApproxMatchOID },
4537
4538         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4539                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4540                 SLAP_MR_ORDERING,
4541                 NULL, NULL,
4542                 caseExactOrderingMatch, NULL, NULL,
4543                 NULL},
4544
4545         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4546                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4547                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4548                 NULL, NULL,
4549                 caseExactIgnoreSubstringsMatch,
4550                 caseExactIgnoreSubstringsIndexer,
4551                 caseExactIgnoreSubstringsFilter,
4552                 NULL},
4553
4554         {"( 2.5.13.8 NAME 'numericStringMatch' "
4555                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4556                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
4557                 NULL, NULL,
4558                 caseIgnoreIA5Match,
4559                 caseIgnoreIA5Indexer,
4560                 caseIgnoreIA5Filter,
4561                 NULL},
4562
4563         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4564                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4565                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4566                 NULL, NULL,
4567                 caseIgnoreIA5SubstringsMatch,
4568                 caseIgnoreIA5SubstringsIndexer,
4569                 caseIgnoreIA5SubstringsFilter,
4570                 NULL},
4571
4572         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4573                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4574                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
4575                 NULL, NULL,
4576                 caseIgnoreListMatch, NULL, NULL,
4577                 NULL},
4578
4579         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4580                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4581                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4582                 NULL, NULL,
4583                 caseIgnoreListSubstringsMatch, NULL, NULL,
4584                 NULL},
4585
4586         {"( 2.5.13.13 NAME 'booleanMatch' "
4587                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4588                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4589                 NULL, NULL,
4590                 booleanMatch, NULL, NULL,
4591                 NULL},
4592
4593         {"( 2.5.13.14 NAME 'integerMatch' "
4594                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4595                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4596                 NULL, NULL,
4597                 integerMatch, integerIndexer, integerFilter,
4598                 NULL},
4599
4600         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4601                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4602                 SLAP_MR_ORDERING,
4603                 NULL, NULL,
4604                 integerOrderingMatch, NULL, NULL,
4605                 NULL},
4606
4607         {"( 2.5.13.16 NAME 'bitStringMatch' "
4608                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4609                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4610                 NULL, NULL,
4611                 bitStringMatch, bitStringIndexer, bitStringFilter,
4612                 NULL},
4613
4614         {"( 2.5.13.17 NAME 'octetStringMatch' "
4615                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4616                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4617                 NULL, NULL,
4618                 octetStringMatch, octetStringIndexer, octetStringFilter,
4619                 NULL},
4620
4621         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
4622                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
4623                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
4624                 NULL, NULL,
4625                 telephoneNumberMatch,
4626                 telephoneNumberIndexer,
4627                 telephoneNumberFilter,
4628                 NULL},
4629
4630         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
4631                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4632                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
4633                 NULL, NULL,
4634                 telephoneNumberSubstringsMatch,
4635                 telephoneNumberSubstringsIndexer,
4636                 telephoneNumberSubstringsFilter,
4637                 NULL},
4638
4639         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
4640                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
4641                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4642                 NULL, NULL,
4643                 NULL, NULL, NULL,
4644                 NULL},
4645
4646         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
4647                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
4648                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4649                 NULL, NULL,
4650                 uniqueMemberMatch, NULL, NULL,
4651                 NULL},
4652
4653         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
4654                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
4655                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4656                 NULL, NULL,
4657                 protocolInformationMatch, NULL, NULL,
4658                 NULL},
4659
4660         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
4661                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4662                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4663                 NULL, NULL,
4664                 generalizedTimeMatch, NULL, NULL,
4665                 NULL},
4666
4667         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
4668                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4669                 SLAP_MR_ORDERING,
4670                 NULL, NULL,
4671                 generalizedTimeOrderingMatch, NULL, NULL,
4672                 NULL},
4673
4674         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
4675                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4676                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4677                 NULL, NULL,
4678                 integerFirstComponentMatch, NULL, NULL,
4679                 NULL},
4680
4681         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
4682                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4683                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4684                 NULL, NULL,
4685                 objectIdentifierFirstComponentMatch, NULL, NULL,
4686                 NULL},
4687
4688 #ifdef HAVE_TLS
4689         {"( 2.5.13.34 NAME 'certificateExactMatch' "
4690                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
4691                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4692                 certificateExactConvert, NULL,
4693                 certificateExactMatch,
4694                 certificateExactIndexer, certificateExactFilter,
4695                 NULL},
4696 #endif
4697
4698         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
4699                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4700                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4701                 NULL, NULL,
4702                 caseExactIA5Match, caseExactIA5Indexer, caseExactIA5Filter,
4703                 IA5StringApproxMatchOID },
4704
4705         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
4706                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4707                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD,
4708                 NULL, NULL,
4709                 caseIgnoreIA5Match, caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
4710                 IA5StringApproxMatchOID },
4711
4712         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
4713                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4714                 SLAP_MR_SUBSTR,
4715                 NULL, NULL,
4716                 caseIgnoreIA5SubstringsMatch,
4717                 caseIgnoreIA5SubstringsIndexer,
4718                 caseIgnoreIA5SubstringsFilter,
4719                 NULL},
4720
4721         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
4722                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4723                 SLAP_MR_SUBSTR,
4724                 NULL, NULL,
4725                 caseExactIA5SubstringsMatch,
4726                 caseExactIA5SubstringsIndexer,
4727                 caseExactIA5SubstringsFilter,
4728                 NULL},
4729
4730 #ifdef SLAPD_AUTHPASSWD
4731         /* needs updating */
4732         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
4733                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4734                 SLAP_MR_EQUALITY,
4735                 NULL, NULL,
4736                 authPasswordMatch, NULL, NULL,
4737                 NULL},
4738 #endif
4739
4740 #ifdef SLAPD_ACI_ENABLED
4741         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
4742                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
4743                 SLAP_MR_EQUALITY,
4744                 NULL, NULL,
4745                 OpenLDAPaciMatch, NULL, NULL,
4746                 NULL},
4747 #endif
4748
4749         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
4750                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4751                 SLAP_MR_EXT,
4752                 NULL, NULL,
4753                 integerBitAndMatch, NULL, NULL,
4754                 NULL},
4755
4756         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
4757                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4758                 SLAP_MR_EXT,
4759                 NULL, NULL,
4760                 integerBitOrMatch, NULL, NULL,
4761                 NULL},
4762
4763         {NULL, SLAP_MR_NONE, NULL, NULL, NULL, NULL}
4764 };
4765
4766 int
4767 slap_schema_init( void )
4768 {
4769         int             res;
4770         int             i = 0;
4771
4772         /* we should only be called once (from main) */
4773         assert( schema_init_done == 0 );
4774
4775         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
4776                 res = register_syntax( syntax_defs[i].sd_desc,
4777                         syntax_defs[i].sd_flags,
4778                         syntax_defs[i].sd_validate,
4779                         syntax_defs[i].sd_normalize,
4780                         syntax_defs[i].sd_pretty
4781 #ifdef SLAPD_BINARY_CONVERSION
4782                         ,
4783                         syntax_defs[i].sd_ber2str,
4784                         syntax_defs[i].sd_str2ber
4785 #endif
4786                 );
4787
4788                 if ( res ) {
4789                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
4790                                  syntax_defs[i].sd_desc );
4791                         return LDAP_OTHER;
4792                 }
4793         }
4794
4795         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
4796                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE ) {
4797                         fprintf( stderr,
4798                                 "slap_schema_init: Ingoring unusable matching rule %s\n",
4799                                  mrule_defs[i].mrd_desc );
4800                         continue;
4801                 }
4802
4803                 res = register_matching_rule(
4804                         mrule_defs[i].mrd_desc,
4805                         mrule_defs[i].mrd_usage,
4806                         mrule_defs[i].mrd_convert,
4807                         mrule_defs[i].mrd_normalize,
4808                         mrule_defs[i].mrd_match,
4809                         mrule_defs[i].mrd_indexer,
4810                         mrule_defs[i].mrd_filter,
4811                         mrule_defs[i].mrd_associated );
4812
4813                 if ( res ) {
4814                         fprintf( stderr,
4815                                 "slap_schema_init: Error registering matching rule %s\n",
4816                                  mrule_defs[i].mrd_desc );
4817                         return LDAP_OTHER;
4818                 }
4819         }
4820
4821         for ( i=0; i < (int)(sizeof(mr_ptr)/sizeof(mr_ptr[0])); i++ )
4822                 *mr_ptr[i].mr = mr_find( mr_ptr[i].oid );
4823
4824         res = slap_schema_load();
4825         schema_init_done = 1;
4826         return res;
4827 }
4828
4829 void
4830 schema_destroy( void )
4831 {
4832         int i;
4833         oidm_destroy();
4834         oc_destroy();
4835         at_destroy();
4836         for ( i=0; i < (int)(sizeof(mr_ptr)/sizeof(mr_ptr[0])); i++ )
4837                 *mr_ptr[i].mr = NULL;
4838         mr_destroy();
4839         syn_destroy();
4840 }