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