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