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