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