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