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