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