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