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