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