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