]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
1230963e1316a51dcb08cb03b15d2d86ea44d115
[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 #define SLAP_NVALUES 1
32
33 #define SLAP_MR_ASSOCIATED(mr, with) \
34         ((mr) == (with) || (mr)->smr_associated == (with))
35
36 #define xUTF8StringNormalize NULL
37 #define xIA5StringNormalize NULL
38 #define xtelephoneNumberNormalize NULL
39 #define xgeneralizedTimeNormalize NULL
40 #define xintegerNormalize NULL
41 #define xnumericStringNormalize NULL
42 #define xnameUIDNormalize NULL
43 #define xdnNormalize NULL
44
45 /* (new) normalization routines */
46 #define caseExactIA5Normalize                                           IA5StringNormalize
47 #define caseIgnoreIA5Normalize                                          IA5StringNormalize
48 #define caseExactNormalize                                                      UTF8StringNormalize
49 #define caseIgnoreNormalize                                                     UTF8StringNormalize
50
51 #define integerFirstComponentNormalize                          NULL
52 #define objectIdentifierNormalize                                       NULL
53 #define objectIdentifierFirstComponentNormalize         NULL
54
55 #define distinguishedNameNormalize      dnNormalize
56 #define distinguishedNameMatch          dnMatch
57 #define distinguishedNameIndexer        octetStringIndexer
58 #define distinguishedNameFilter         octetStringFilter
59
60 #define integerOrderingMatch                    integerMatch
61 #define integerFirstComponentMatch              NULL
62 #define integerIndexer                          octetStringIndexer
63 #define integerFilter                           octetStringFilter
64
65 #define generalizedTimeMatch                    caseIgnoreIA5Match
66 #define generalizedTimeOrderingMatch    caseIgnoreIA5Match
67
68 #define uniqueMemberMatch                       dnMatch /* FIXME! */
69
70 #define objectIdentifierMatch   octetStringMatch
71 #define objectIdentifierIndexer octetStringIndexer
72 #define objectIdentifierFilter  octetStringFilter
73
74 #define OpenLDAPaciMatch                                                NULL
75
76 #define bitStringMatch                  octetStringMatch
77 #define bitStringIndexer                octetStringIndexer
78 #define bitStringFilter                 octetStringFilter
79
80 #define caseIgnoreMatch         octetStringMatch
81 #define caseIgnoreOrderingMatch         octetStringOrderingMatch
82 #define caseIgnoreIndexer       octetStringIndexer
83 #define caseIgnoreFilter        octetStringFilter
84
85 #define caseIgnoreSubstringsMatch               octetStringSubstringsMatch
86 #define caseIgnoreSubstringsIndexer             octetStringSubstringsIndexer
87 #define caseIgnoreSubstringsFilter              octetStringSubstringsFilter
88
89 #define caseExactMatch          octetStringMatch
90 #define caseExactOrderingMatch          octetStringOrderingMatch
91 #define caseExactIndexer        octetStringIndexer
92 #define caseExactFilter         octetStringFilter
93
94 #define caseExactSubstringsMatch                octetStringSubstringsMatch
95 #define caseExactSubstringsIndexer              octetStringSubstringsIndexer
96 #define caseExactSubstringsFilter               octetStringSubstringsFilter
97
98 #define caseExactIA5Match               octetStringMatch
99 #define caseExactIA5Indexer             octetStringIndexer
100 #define caseExactIA5Filter              octetStringFilter
101
102 #define caseExactIA5SubstringsMatch                     octetStringSubstringsMatch
103 #define caseExactIA5SubstringsIndexer           octetStringSubstringsIndexer
104 #define caseExactIA5SubstringsFilter            octetStringSubstringsFilter
105
106 #define caseIgnoreIA5Match              octetStringMatch
107 #define caseIgnoreIA5Indexer    octetStringIndexer
108 #define caseIgnoreIA5Filter             octetStringFilter
109
110 #define caseIgnoreIA5SubstringsMatch            caseExactIA5SubstringsMatch
111 #define caseIgnoreIA5SubstringsIndexer          caseExactIA5SubstringsIndexer
112 #define caseIgnoreIA5SubstringsFilter           caseExactIA5SubstringsFilter
113
114 #define numericStringMatch              octetStringMatch
115 #define numericStringIndexer    octetStringIndexer
116 #define numericStringFilter             octetStringFilter
117
118 #define numericStringSubstringsMatch            caseExactIA5SubstringsMatch
119 #define numericStringSubstringsIndexer          caseExactIA5SubstringsIndexer
120 #define numericStringSubstringsFilter           caseExactIA5SubstringsFilter
121
122 #define telephoneNumberMatch            octetStringMatch
123 #define telephoneNumberIndexer          octetStringIndexer
124 #define telephoneNumberFilter           octetStringFilter
125
126 #define telephoneNumberSubstringsMatch          caseExactIA5SubstringsMatch
127 #define telephoneNumberSubstringsIndexer        caseExactIA5SubstringsIndexer
128 #define telephoneNumberSubstringsFilter         caseExactIA5SubstringsFilter
129
130 #define booleanIndexer                                  octetStringIndexer
131 #define booleanFilter                                   octetStringFilter
132
133 /* validatation routines */
134 #define berValidate                                             blobValidate
135
136 /* approx matching rules */
137 #ifdef SLAP_NVALUES
138 #define directoryStringApproxMatchOID   NULL
139 #define IA5StringApproxMatchOID                 NULL
140 #else
141 #define directoryStringApproxMatchOID   "1.3.6.1.4.1.4203.666.4.4"
142 #define directoryStringApproxMatch      approxMatch
143 #define directoryStringApproxIndexer    approxIndexer
144 #define directoryStringApproxFilter     approxFilter
145 #define IA5StringApproxMatchOID                 "1.3.6.1.4.1.4203.666.4.5"
146 #define IA5StringApproxMatch                    approxMatch
147 #define IA5StringApproxIndexer                  approxIndexer
148 #define IA5StringApproxFilter                   approxFilter
149 #endif
150
151 static char *bvcasechr( struct berval *bv, unsigned char c, ber_len_t *len )
152 {
153         ber_len_t i;
154         char lower = TOLOWER( c );
155         char upper = TOUPPER( c );
156
157         if( c == 0 ) return NULL;
158         
159         for( i=0; i < bv->bv_len; i++ ) {
160                 if( upper == bv->bv_val[i] || lower == bv->bv_val[i] ) {
161                         *len = i;
162                         return &bv->bv_val[i];
163                 }
164         }
165
166         return NULL;
167 }
168
169 static int
170 octetStringMatch(
171         int *matchp,
172         slap_mask_t flags,
173         Syntax *syntax,
174         MatchingRule *mr,
175         struct berval *value,
176         void *assertedValue )
177 {
178         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
179
180         if( match == 0 ) {
181                 match = memcmp( value->bv_val,
182                         ((struct berval *) assertedValue)->bv_val,
183                         value->bv_len );
184         }
185
186         *matchp = match;
187         return LDAP_SUCCESS;
188 }
189
190 static int
191 octetStringOrderingMatch(
192         int *matchp,
193         slap_mask_t flags,
194         Syntax *syntax,
195         MatchingRule *mr,
196         struct berval *value,
197         void *assertedValue )
198 {
199         ber_len_t v_len  = value->bv_len;
200         ber_len_t av_len = ((struct berval *) assertedValue)->bv_len;
201
202         int match = memcmp( value->bv_val,
203                 ((struct berval *) assertedValue)->bv_val,
204                 (v_len < av_len ? v_len : av_len) );
205
206         if( match == 0 ) match = v_len - av_len;
207
208         *matchp = match;
209         return LDAP_SUCCESS;
210 }
211
212 /* Index generation function */
213 int octetStringIndexer(
214         slap_mask_t use,
215         slap_mask_t flags,
216         Syntax *syntax,
217         MatchingRule *mr,
218         struct berval *prefix,
219         BerVarray values,
220         BerVarray *keysp )
221 {
222         int i;
223         size_t slen, mlen;
224         BerVarray keys;
225         HASH_CONTEXT   HASHcontext;
226         unsigned char   HASHdigest[HASH_BYTES];
227         struct berval digest;
228         digest.bv_val = HASHdigest;
229         digest.bv_len = sizeof(HASHdigest);
230
231         for( i=0; values[i].bv_val != NULL; i++ ) {
232                 /* just count them */
233         }
234
235         /* we should have at least one value at this point */
236         assert( i > 0 );
237
238         keys = ch_malloc( sizeof( struct berval ) * (i+1) );
239
240         slen = syntax->ssyn_oidlen;
241         mlen = mr->smr_oidlen;
242
243         for( i=0; values[i].bv_val != NULL; i++ ) {
244                 HASH_Init( &HASHcontext );
245                 if( prefix != NULL && prefix->bv_len > 0 ) {
246                         HASH_Update( &HASHcontext,
247                                 prefix->bv_val, prefix->bv_len );
248                 }
249                 HASH_Update( &HASHcontext,
250                         syntax->ssyn_oid, slen );
251                 HASH_Update( &HASHcontext,
252                         mr->smr_oid, mlen );
253                 HASH_Update( &HASHcontext,
254                         values[i].bv_val, values[i].bv_len );
255                 HASH_Final( HASHdigest, &HASHcontext );
256
257                 ber_dupbv( &keys[i], &digest );
258         }
259
260         keys[i].bv_val = NULL;
261         keys[i].bv_len = 0;
262
263         *keysp = keys;
264
265         return LDAP_SUCCESS;
266 }
267
268 /* Index generation function */
269 int octetStringFilter(
270         slap_mask_t use,
271         slap_mask_t flags,
272         Syntax *syntax,
273         MatchingRule *mr,
274         struct berval *prefix,
275         void * assertedValue,
276         BerVarray *keysp )
277 {
278         size_t slen, mlen;
279         BerVarray keys;
280         HASH_CONTEXT   HASHcontext;
281         unsigned char   HASHdigest[HASH_BYTES];
282         struct berval *value = (struct berval *) assertedValue;
283         struct berval digest;
284         digest.bv_val = HASHdigest;
285         digest.bv_len = sizeof(HASHdigest);
286
287         slen = syntax->ssyn_oidlen;
288         mlen = mr->smr_oidlen;
289
290         keys = ch_malloc( sizeof( struct berval ) * 2 );
291
292         HASH_Init( &HASHcontext );
293         if( prefix != NULL && prefix->bv_len > 0 ) {
294                 HASH_Update( &HASHcontext,
295                         prefix->bv_val, prefix->bv_len );
296         }
297         HASH_Update( &HASHcontext,
298                 syntax->ssyn_oid, slen );
299         HASH_Update( &HASHcontext,
300                 mr->smr_oid, mlen );
301         HASH_Update( &HASHcontext,
302                 value->bv_val, value->bv_len );
303         HASH_Final( HASHdigest, &HASHcontext );
304
305         ber_dupbv( keys, &digest );
306         keys[1].bv_val = NULL;
307         keys[1].bv_len = 0;
308
309         *keysp = keys;
310
311         return LDAP_SUCCESS;
312 }
313
314 static int
315 inValidate(
316         Syntax *syntax,
317         struct berval *in )
318 {
319         /* no value allowed */
320         return LDAP_INVALID_SYNTAX;
321 }
322
323 static int
324 blobValidate(
325         Syntax *syntax,
326         struct berval *in )
327 {
328         /* any value allowed */
329         return LDAP_SUCCESS;
330 }
331
332 static int
333 bitStringValidate(
334         Syntax *syntax,
335         struct berval *in )
336 {
337         ber_len_t i;
338
339         /* very unforgiving validation, requires no normalization
340          * before simplistic matching
341          */
342         if( in->bv_len < 3 ) {
343                 return LDAP_INVALID_SYNTAX;
344         }
345
346         /*
347          * rfc 2252 section 6.3 Bit String
348          * bitstring = "'" *binary-digit "'"
349          * binary-digit = "0" / "1"
350          * example: '0101111101'B
351          */
352         
353         if( in->bv_val[0] != '\'' ||
354                 in->bv_val[in->bv_len-2] != '\'' ||
355                 in->bv_val[in->bv_len-1] != 'B' )
356         {
357                 return LDAP_INVALID_SYNTAX;
358         }
359
360         for( i=in->bv_len-3; i>0; i-- ) {
361                 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
362                         return LDAP_INVALID_SYNTAX;
363                 }
364         }
365
366         return LDAP_SUCCESS;
367 }
368
369 static int
370 nameUIDValidate(
371         Syntax *syntax,
372         struct berval *in )
373 {
374         int rc;
375         struct berval dn;
376
377         if( in->bv_len == 0 ) return LDAP_SUCCESS;
378
379         ber_dupbv( &dn, in );
380         if( !dn.bv_val ) return LDAP_OTHER;
381
382         if( dn.bv_val[dn.bv_len-1] == 'B'
383                 && dn.bv_val[dn.bv_len-2] == '\'' )
384         {
385                 /* assume presence of optional UID */
386                 ber_len_t i;
387
388                 for(i=dn.bv_len-3; i>1; i--) {
389                         if( dn.bv_val[i] != '0' &&      dn.bv_val[i] != '1' ) {
390                                 break;
391                         }
392                 }
393                 if( dn.bv_val[i] != '\'' || dn.bv_val[i-1] != '#' ) {
394                         ber_memfree( dn.bv_val );
395                         return LDAP_INVALID_SYNTAX;
396                 }
397
398                 /* trim the UID to allow use of dnValidate */
399                 dn.bv_val[i-1] = '\0';
400                 dn.bv_len = i-1;
401         }
402
403         rc = dnValidate( NULL, &dn );
404
405         ber_memfree( dn.bv_val );
406         return rc;
407 }
408
409 static int
410 uniqueMemberNormalize(
411         slap_mask_t usage,
412         Syntax *syntax,
413         MatchingRule *mr,
414         struct berval *val,
415         struct berval *normalized )
416 {
417         struct berval out;
418         int rc;
419
420         ber_dupbv( &out, val );
421         if( out.bv_len != 0 ) {
422                 struct berval uid = { 0, NULL };
423
424                 if( out.bv_val[out.bv_len-1] == 'B'
425                         && out.bv_val[out.bv_len-2] == '\'' )
426                 {
427                         /* assume presence of optional UID */
428                         uid.bv_val = strrchr( out.bv_val, '#' );
429
430                         if( uid.bv_val == NULL ) {
431                                 free( out.bv_val );
432                                 return LDAP_INVALID_SYNTAX;
433                         }
434
435                         uid.bv_len = out.bv_len - (uid.bv_val - out.bv_val);
436                         out.bv_len -= uid.bv_len--;
437
438                         /* temporarily trim the UID */
439                         *(uid.bv_val++) = '\0';
440                 }
441
442                 rc = dnNormalize2( NULL, &out, normalized );
443
444                 if( rc != LDAP_SUCCESS ) {
445                         free( out.bv_val );
446                         return LDAP_INVALID_SYNTAX;
447                 }
448
449                 if( uid.bv_len ) {
450                         normalized->bv_val = ch_realloc( normalized->bv_val,
451                                 normalized->bv_len + uid.bv_len + sizeof("#") );
452
453                         /* insert the separator */
454                         normalized->bv_val[normalized->bv_len++] = '#';
455
456                         /* append the UID */
457                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
458                                 uid.bv_val, uid.bv_len );
459                         normalized->bv_len += uid.bv_len;
460
461                         /* terminate */
462                         normalized->bv_val[normalized->bv_len] = '\0';
463                 }
464
465                 free( out.bv_val );
466         }
467
468         return LDAP_SUCCESS;
469 }
470
471 /*
472  * Handling boolean syntax and matching is quite rigid.
473  * A more flexible approach would be to allow a variety
474  * of strings to be normalized and prettied into TRUE
475  * and FALSE.
476  */
477 static int
478 booleanValidate(
479         Syntax *syntax,
480         struct berval *in )
481 {
482         /* very unforgiving validation, requires no normalization
483          * before simplistic matching
484          */
485
486         if( in->bv_len == 4 ) {
487                 if( !memcmp( in->bv_val, "TRUE", 4 ) ) {
488                         return LDAP_SUCCESS;
489                 }
490         } else if( in->bv_len == 5 ) {
491                 if( !memcmp( in->bv_val, "FALSE", 5 ) ) {
492                         return LDAP_SUCCESS;
493                 }
494         }
495
496         return LDAP_INVALID_SYNTAX;
497 }
498
499 static int
500 booleanMatch(
501         int *matchp,
502         slap_mask_t flags,
503         Syntax *syntax,
504         MatchingRule *mr,
505         struct berval *value,
506         void *assertedValue )
507 {
508         /* simplistic matching allowed by rigid validation */
509         struct berval *asserted = (struct berval *) assertedValue;
510         *matchp = value->bv_len != asserted->bv_len;
511         return LDAP_SUCCESS;
512 }
513
514 /*-------------------------------------------------------------------
515 LDAP/X.500 string syntax / matching rules have a few oddities.  This
516 comment attempts to detail how slapd(8) treats them.
517
518 Summary:
519   StringSyntax          X.500   LDAP    Matching/Comments
520   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
521   PrintableString       subset  subset  i/e + ignore insignificant spaces
522   PrintableString       subset  subset  i/e + ignore insignificant spaces
523   NumericString         subset  subset  ignore all spaces
524   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
525   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
526
527   TelephoneNumber subset  subset  i + ignore all spaces and "-"
528
529   See draft-ietf-ldapbis-strpro for details (once published).
530
531
532 Directory String -
533   In X.500(93), a directory string can be either a PrintableString,
534   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
535   In later versions, more CHOICEs were added.  In all cases the string
536   must be non-empty.
537
538   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
539   A directory string cannot be zero length.
540
541   For matching, there are both case ignore and exact rules.  Both
542   also require that "insignificant" spaces be ignored.
543         spaces before the first non-space are ignored;
544         spaces after the last non-space are ignored;
545         spaces after a space are ignored.
546   Note: by these rules (and as clarified in X.520), a string of only
547   spaces is to be treated as if held one space, not empty (which
548   would be a syntax error).
549
550 NumericString
551   In ASN.1, numeric string is just a string of digits and spaces
552   and could be empty.  However, in X.500, all attribute values of
553   numeric string carry a non-empty constraint.  For example:
554
555         internationalISDNNumber ATTRIBUTE ::= {
556                 WITH SYNTAX InternationalISDNNumber
557                 EQUALITY MATCHING RULE numericStringMatch
558                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
559                 ID id-at-internationalISDNNumber }
560         InternationalISDNNumber ::=
561             NumericString (SIZE(1..ub-international-isdn-number))
562
563   Unforunately, some assertion values are don't carry the same
564   constraint (but its unclear how such an assertion could ever
565   be true). In LDAP, there is one syntax (numericString) not two
566   (numericString with constraint, numericString without constraint).
567   This should be treated as numericString with non-empty constraint.
568   Note that while someone may have no ISDN number, there are no ISDN
569   numbers which are zero length.
570
571   In matching, spaces are ignored.
572
573 PrintableString
574   In ASN.1, Printable string is just a string of printable characters
575   and can be empty.  In X.500, semantics much like NumericString (see
576   serialNumber for a like example) excepting uses insignificant space
577   handling instead of ignore all spaces.  
578
579 IA5String
580   Basically same as PrintableString.  There are no examples in X.500,
581   but same logic applies.  So we require them to be non-empty as
582   well.
583
584 -------------------------------------------------------------------*/
585
586 static int
587 UTF8StringValidate(
588         Syntax *syntax,
589         struct berval *in )
590 {
591         ber_len_t count;
592         int len;
593         unsigned char *u = in->bv_val;
594
595         if( in->bv_len == 0 && syntax == slap_schema.si_syn_directoryString ) {
596                 /* directory strings cannot be empty */
597                 return LDAP_INVALID_SYNTAX;
598         }
599
600         for( count = in->bv_len; count > 0; count-=len, u+=len ) {
601                 /* get the length indicated by the first byte */
602                 len = LDAP_UTF8_CHARLEN2( u, len );
603
604                 /* very basic checks */
605                 switch( len ) {
606                         case 6:
607                                 if( (u[5] & 0xC0) != 0x80 ) {
608                                         return LDAP_INVALID_SYNTAX;
609                                 }
610                         case 5:
611                                 if( (u[4] & 0xC0) != 0x80 ) {
612                                         return LDAP_INVALID_SYNTAX;
613                                 }
614                         case 4:
615                                 if( (u[3] & 0xC0) != 0x80 ) {
616                                         return LDAP_INVALID_SYNTAX;
617                                 }
618                         case 3:
619                                 if( (u[2] & 0xC0 )!= 0x80 ) {
620                                         return LDAP_INVALID_SYNTAX;
621                                 }
622                         case 2:
623                                 if( (u[1] & 0xC0) != 0x80 ) {
624                                         return LDAP_INVALID_SYNTAX;
625                                 }
626                         case 1:
627                                 /* CHARLEN already validated it */
628                                 break;
629                         default:
630                                 return LDAP_INVALID_SYNTAX;
631                 }
632
633                 /* make sure len corresponds with the offset
634                         to the next character */
635                 if( LDAP_UTF8_OFFSET( u ) != len ) return LDAP_INVALID_SYNTAX;
636         }
637
638         if( count != 0 ) {
639                 return LDAP_INVALID_SYNTAX;
640         }
641
642         return LDAP_SUCCESS;
643 }
644
645 static int
646 UTF8StringNormalize(
647         slap_mask_t use,
648         Syntax *syntax,
649         MatchingRule *mr,
650         struct berval *val,
651         struct berval *normalized )
652 {
653         struct berval tmp, nvalue;
654         int flags;
655         int i, wasspace;
656
657         if( val->bv_val == NULL ) {
658                 /* assume we're dealing with a syntax (e.g., UTF8String)
659                  * which allows empty strings
660                  */
661                 normalized->bv_len = 0;
662                 normalized->bv_val = NULL;
663                 return LDAP_SUCCESS;
664         }
665
666         flags = SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactMatch )
667                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
668         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
669                 ? LDAP_UTF8_APPROX : 0;
670
671         val = UTF8bvnormalize( val, &tmp, flags );
672         if( val == NULL ) {
673                 return LDAP_OTHER;
674         }
675         
676         /* collapse spaces (in place) */
677         nvalue.bv_len = 0;
678         nvalue.bv_val = tmp.bv_val;
679
680         wasspace=1; /* trim leading spaces */
681         for( i=0; i<tmp.bv_len; i++) {
682                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
683                         if( wasspace++ == 0 ) {
684                                 /* trim repeated spaces */
685                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
686                         }
687                 } else {
688                         wasspace = 0;
689                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
690                 }
691         }
692
693         if( nvalue.bv_len ) {
694                 if( wasspace ) {
695                         /* last character was a space, trim it */
696                         --nvalue.bv_len;
697                 }
698                 nvalue.bv_val[nvalue.bv_len] = '\0';
699
700         } else {
701                 /* string of all spaces is treated as one space */
702                 nvalue.bv_val[0] = ' ';
703                 nvalue.bv_val[1] = '\0';
704                 nvalue.bv_len = 1;
705         }
706
707         *normalized = nvalue;
708         return LDAP_SUCCESS;
709 }
710
711 #ifndef SLAP_NVALUES
712
713 #ifndef SLAPD_APPROX_OLDSINGLESTRING
714 #if defined(SLAPD_APPROX_INITIALS)
715 #define SLAPD_APPROX_DELIMITER "._ "
716 #define SLAPD_APPROX_WORDLEN 2
717 #else
718 #define SLAPD_APPROX_DELIMITER " "
719 #define SLAPD_APPROX_WORDLEN 1
720 #endif
721
722 static int
723 approxMatch(
724         int *matchp,
725         slap_mask_t flags,
726         Syntax *syntax,
727         MatchingRule *mr,
728         struct berval *value,
729         void *assertedValue )
730 {
731         struct berval *nval, *assertv;
732         char *val, **values, **words, *c;
733         int i, count, len, nextchunk=0, nextavail=0;
734
735         /* Yes, this is necessary */
736         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX );
737         if( nval == NULL ) {
738                 *matchp = 1;
739                 return LDAP_SUCCESS;
740         }
741
742         /* Yes, this is necessary */
743         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
744                 NULL, LDAP_UTF8_APPROX );
745         if( assertv == NULL ) {
746                 ber_bvfree( nval );
747                 *matchp = 1;
748                 return LDAP_SUCCESS;
749         }
750
751         /* Isolate how many words there are */
752         for ( c = nval->bv_val, count = 1; *c; c++ ) {
753                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
754                 if ( c == NULL ) break;
755                 *c = '\0';
756                 count++;
757         }
758
759         /* Get a phonetic copy of each word */
760         words = (char **)ch_malloc( count * sizeof(char *) );
761         values = (char **)ch_malloc( count * sizeof(char *) );
762         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
763                 words[i] = c;
764                 values[i] = phonetic(c);
765         }
766
767         /* Work through the asserted value's words, to see if at least some
768            of the words are there, in the same order. */
769         len = 0;
770         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
771                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
772                 if( len == 0 ) {
773                         nextchunk++;
774                         continue;
775                 }
776 #if defined(SLAPD_APPROX_INITIALS)
777                 else if( len == 1 ) {
778                         /* Single letter words need to at least match one word's initial */
779                         for( i=nextavail; i<count; i++ )
780                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
781                                         nextavail=i+1;
782                                         break;
783                                 }
784                 }
785 #endif
786                 else {
787                         /* Isolate the next word in the asserted value and phonetic it */
788                         assertv->bv_val[nextchunk+len] = '\0';
789                         val = phonetic( assertv->bv_val + nextchunk );
790
791                         /* See if this phonetic chunk is in the remaining words of *value */
792                         for( i=nextavail; i<count; i++ ){
793                                 if( !strcmp( val, values[i] ) ){
794                                         nextavail = i+1;
795                                         break;
796                                 }
797                         }
798                         ch_free( val );
799                 }
800
801                 /* This chunk in the asserted value was NOT within the *value. */
802                 if( i >= count ) {
803                         nextavail=-1;
804                         break;
805                 }
806
807                 /* Go on to the next word in the asserted value */
808                 nextchunk += len+1;
809         }
810
811         /* If some of the words were seen, call it a match */
812         if( nextavail > 0 ) {
813                 *matchp = 0;
814         }
815         else {
816                 *matchp = 1;
817         }
818
819         /* Cleanup allocs */
820         ber_bvfree( assertv );
821         for( i=0; i<count; i++ ) {
822                 ch_free( values[i] );
823         }
824         ch_free( values );
825         ch_free( words );
826         ber_bvfree( nval );
827
828         return LDAP_SUCCESS;
829 }
830
831 static int 
832 approxIndexer(
833         slap_mask_t use,
834         slap_mask_t flags,
835         Syntax *syntax,
836         MatchingRule *mr,
837         struct berval *prefix,
838         BerVarray values,
839         BerVarray *keysp )
840 {
841         char *c;
842         int i,j, len, wordcount, keycount=0;
843         struct berval *newkeys;
844         BerVarray keys=NULL;
845
846         for( j=0; values[j].bv_val != NULL; j++ ) {
847                 struct berval val = { 0, NULL };
848                 /* Yes, this is necessary */
849                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX );
850                 assert( val.bv_val != NULL );
851
852                 /* Isolate how many words there are. There will be a key for each */
853                 for( wordcount = 0, c = val.bv_val; *c; c++) {
854                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
855                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
856                         c+= len;
857                         if (*c == '\0') break;
858                         *c = '\0';
859                 }
860
861                 /* Allocate/increase storage to account for new keys */
862                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
863                         * sizeof(struct berval) );
864                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
865                 if( keys ) ch_free( keys );
866                 keys = newkeys;
867
868                 /* Get a phonetic copy of each word */
869                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
870                         len = strlen( c );
871                         if( len < SLAPD_APPROX_WORDLEN ) continue;
872                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
873                         keycount++;
874                         i++;
875                 }
876
877                 ber_memfree( val.bv_val );
878         }
879         keys[keycount].bv_val = NULL;
880         *keysp = keys;
881
882         return LDAP_SUCCESS;
883 }
884
885 static int 
886 approxFilter(
887         slap_mask_t use,
888         slap_mask_t flags,
889         Syntax *syntax,
890         MatchingRule *mr,
891         struct berval *prefix,
892         void * assertedValue,
893         BerVarray *keysp )
894 {
895         char *c;
896         int i, count, len;
897         struct berval *val;
898         BerVarray keys;
899
900         /* Yes, this is necessary */
901         val = UTF8bvnormalize( ((struct berval *)assertedValue),
902                 NULL, LDAP_UTF8_APPROX );
903         if( val == NULL || val->bv_val == NULL ) {
904                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
905                 keys[0].bv_val = NULL;
906                 *keysp = keys;
907                 ber_bvfree( val );
908                 return LDAP_SUCCESS;
909         }
910
911         /* Isolate how many words there are. There will be a key for each */
912         for( count = 0,c = val->bv_val; *c; c++) {
913                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
914                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
915                 c+= len;
916                 if (*c == '\0') break;
917                 *c = '\0';
918         }
919
920         /* Allocate storage for new keys */
921         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
922
923         /* Get a phonetic copy of each word */
924         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
925                 len = strlen(c);
926                 if( len < SLAPD_APPROX_WORDLEN ) continue;
927                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
928                 i++;
929         }
930
931         ber_bvfree( val );
932
933         keys[count].bv_val = NULL;
934         *keysp = keys;
935
936         return LDAP_SUCCESS;
937 }
938
939 #else
940 /* No other form of Approximate Matching is defined */
941
942 static int
943 approxMatch(
944         int *matchp,
945         slap_mask_t flags,
946         Syntax *syntax,
947         MatchingRule *mr,
948         struct berval *value,
949         void *assertedValue )
950 {
951         char *vapprox, *avapprox;
952         char *s, *t;
953
954         /* Yes, this is necessary */
955         s = UTF8normalize( value, UTF8_NOCASEFOLD );
956         if( s == NULL ) {
957                 *matchp = 1;
958                 return LDAP_SUCCESS;
959         }
960
961         /* Yes, this is necessary */
962         t = UTF8normalize( ((struct berval *)assertedValue),
963                            UTF8_NOCASEFOLD );
964         if( t == NULL ) {
965                 free( s );
966                 *matchp = -1;
967                 return LDAP_SUCCESS;
968         }
969
970         vapprox = phonetic( strip8bitChars( s ) );
971         avapprox = phonetic( strip8bitChars( t ) );
972
973         free( s );
974         free( t );
975
976         *matchp = strcmp( vapprox, avapprox );
977
978         ch_free( vapprox );
979         ch_free( avapprox );
980
981         return LDAP_SUCCESS;
982 }
983
984 static int 
985 approxIndexer(
986         slap_mask_t use,
987         slap_mask_t flags,
988         Syntax *syntax,
989         MatchingRule *mr,
990         struct berval *prefix,
991         BerVarray values,
992         BerVarray *keysp )
993 {
994         int i;
995         BerVarray *keys;
996         char *s;
997
998         for( i=0; values[i].bv_val != NULL; i++ ) {
999                 /* empty - just count them */
1000         }
1001
1002         /* we should have at least one value at this point */
1003         assert( i > 0 );
1004
1005         keys = (struct berval *)ch_malloc( sizeof( struct berval ) * (i+1) );
1006
1007         /* Copy each value and run it through phonetic() */
1008         for( i=0; values[i].bv_val != NULL; i++ ) {
1009                 /* Yes, this is necessary */
1010                 s = UTF8normalize( &values[i], UTF8_NOCASEFOLD );
1011
1012                 /* strip 8-bit chars and run through phonetic() */
1013                 ber_str2bv( phonetic( strip8bitChars( s ) ), 0, 0, &keys[i] );
1014                 free( s );
1015         }
1016         keys[i].bv_val = NULL;
1017
1018         *keysp = keys;
1019         return LDAP_SUCCESS;
1020 }
1021
1022 static int 
1023 approxFilter(
1024         slap_mask_t use,
1025         slap_mask_t flags,
1026         Syntax *syntax,
1027         MatchingRule *mr,
1028         struct berval *prefix,
1029         void * assertedValue,
1030         BerVarray *keysp )
1031 {
1032         BerVarray keys;
1033         char *s;
1034
1035         keys = (struct berval *)ch_malloc( sizeof( struct berval * ) * 2 );
1036
1037         /* Yes, this is necessary */
1038         s = UTF8normalize( ((struct berval *)assertedValue),
1039                              UTF8_NOCASEFOLD );
1040         if( s == NULL ) {
1041                 keys[0] = NULL;
1042         } else {
1043                 /* strip 8-bit chars and run through phonetic() */
1044                 keys[0] = ber_bvstr( phonetic( strip8bitChars( s ) ) );
1045                 free( s );
1046                 keys[1] = NULL;
1047         }
1048
1049         *keysp = keys;
1050         return LDAP_SUCCESS;
1051 }
1052 #endif
1053 #endif /* !SLAP_NVALUES */
1054
1055 /* Substrings Index generation function */
1056 static int
1057 octetStringSubstringsIndexer (
1058         slap_mask_t use,
1059         slap_mask_t flags,
1060         Syntax *syntax,
1061         MatchingRule *mr,
1062         struct berval *prefix,
1063         BerVarray values,
1064         BerVarray *keysp )
1065 {
1066         ber_len_t i, j, nkeys;
1067         size_t slen, mlen;
1068         BerVarray keys;
1069
1070         HASH_CONTEXT   HASHcontext;
1071         unsigned char   HASHdigest[HASH_BYTES];
1072         struct berval digest;
1073         digest.bv_val = HASHdigest;
1074         digest.bv_len = sizeof(HASHdigest);
1075
1076         nkeys=0;
1077
1078         for( i=0; values[i].bv_val != NULL; i++ ) {
1079                 /* count number of indices to generate */
1080                 if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
1081                         continue;
1082                 }
1083
1084                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1085                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1086                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
1087                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
1088                         } else {
1089                                 nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
1090                         }
1091                 }
1092
1093                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
1094                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1095                                 nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
1096                         }
1097                 }
1098
1099                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1100                         if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1101                                 nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
1102                                         ( SLAP_INDEX_SUBSTR_MINLEN - 1);
1103                         } else {
1104                                 nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
1105                         }
1106                 }
1107         }
1108
1109         if( nkeys == 0 ) {
1110                 /* no keys to generate */
1111                 *keysp = NULL;
1112                 return LDAP_SUCCESS;
1113         }
1114
1115         keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
1116
1117         slen = syntax->ssyn_oidlen;
1118         mlen = mr->smr_oidlen;
1119
1120         nkeys=0;
1121         for( i=0; values[i].bv_val != NULL; i++ ) {
1122                 ber_len_t j,max;
1123
1124                 if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
1125
1126                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
1127                         ( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
1128                 {
1129                         char pre = SLAP_INDEX_SUBSTR_PREFIX;
1130                         max = values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
1131
1132                         for( j=0; j<max; j++ ) {
1133                                 HASH_Init( &HASHcontext );
1134                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1135                                         HASH_Update( &HASHcontext,
1136                                                 prefix->bv_val, prefix->bv_len );
1137                                 }
1138
1139                                 HASH_Update( &HASHcontext,
1140                                         &pre, sizeof( pre ) );
1141                                 HASH_Update( &HASHcontext,
1142                                         syntax->ssyn_oid, slen );
1143                                 HASH_Update( &HASHcontext,
1144                                         mr->smr_oid, mlen );
1145                                 HASH_Update( &HASHcontext,
1146                                         &values[i].bv_val[j],
1147                                         SLAP_INDEX_SUBSTR_MAXLEN );
1148                                 HASH_Final( HASHdigest, &HASHcontext );
1149
1150                                 ber_dupbv( &keys[nkeys++], &digest );
1151                         }
1152                 }
1153
1154                 max = SLAP_INDEX_SUBSTR_MAXLEN < values[i].bv_len
1155                         ? SLAP_INDEX_SUBSTR_MAXLEN : values[i].bv_len;
1156
1157                 for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
1158                         char pre;
1159
1160                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1161                                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1162                                 HASH_Init( &HASHcontext );
1163                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1164                                         HASH_Update( &HASHcontext,
1165                                                 prefix->bv_val, prefix->bv_len );
1166                                 }
1167                                 HASH_Update( &HASHcontext,
1168                                         &pre, sizeof( pre ) );
1169                                 HASH_Update( &HASHcontext,
1170                                         syntax->ssyn_oid, slen );
1171                                 HASH_Update( &HASHcontext,
1172                                         mr->smr_oid, mlen );
1173                                 HASH_Update( &HASHcontext,
1174                                         values[i].bv_val, j );
1175                                 HASH_Final( HASHdigest, &HASHcontext );
1176
1177                                 ber_dupbv( &keys[nkeys++], &digest );
1178                         }
1179
1180                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1181                                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1182                                 HASH_Init( &HASHcontext );
1183                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1184                                         HASH_Update( &HASHcontext,
1185                                                 prefix->bv_val, prefix->bv_len );
1186                                 }
1187                                 HASH_Update( &HASHcontext,
1188                                         &pre, sizeof( pre ) );
1189                                 HASH_Update( &HASHcontext,
1190                                         syntax->ssyn_oid, slen );
1191                                 HASH_Update( &HASHcontext,
1192                                         mr->smr_oid, mlen );
1193                                 HASH_Update( &HASHcontext,
1194                                         &values[i].bv_val[values[i].bv_len-j], j );
1195                                 HASH_Final( HASHdigest, &HASHcontext );
1196
1197                                 ber_dupbv( &keys[nkeys++], &digest );
1198                         }
1199
1200                 }
1201
1202         }
1203
1204         if( nkeys > 0 ) {
1205                 keys[nkeys].bv_val = NULL;
1206                 *keysp = keys;
1207         } else {
1208                 ch_free( keys );
1209                 *keysp = NULL;
1210         }
1211
1212         return LDAP_SUCCESS;
1213 }
1214
1215 static int
1216 octetStringSubstringsFilter (
1217         slap_mask_t use,
1218         slap_mask_t flags,
1219         Syntax *syntax,
1220         MatchingRule *mr,
1221         struct berval *prefix,
1222         void * assertedValue,
1223         BerVarray *keysp )
1224 {
1225         SubstringsAssertion *sa;
1226         char pre;
1227         unsigned casefold;
1228         ber_len_t nkeys = 0;
1229         size_t slen, mlen, klen;
1230         BerVarray keys;
1231         HASH_CONTEXT   HASHcontext;
1232         unsigned char   HASHdigest[HASH_BYTES];
1233         struct berval *value;
1234         struct berval digest;
1235
1236         sa = (SubstringsAssertion *) assertedValue;
1237
1238         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL
1239                 && sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1240         {
1241                 nkeys++;
1242         }
1243
1244         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1245                 ber_len_t i;
1246                 for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
1247                         if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
1248                                 /* don't bother accounting for stepping */
1249                                 nkeys += sa->sa_any[i].bv_len -
1250                                         ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
1251                         }
1252                 }
1253         }
1254
1255         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
1256                 sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1257         {
1258                 nkeys++;
1259         }
1260
1261         if( nkeys == 0 ) {
1262                 *keysp = NULL;
1263                 return LDAP_SUCCESS;
1264         }
1265
1266         digest.bv_val = HASHdigest;
1267         digest.bv_len = sizeof(HASHdigest);
1268
1269         slen = syntax->ssyn_oidlen;
1270         mlen = mr->smr_oidlen;
1271
1272         keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
1273         nkeys = 0;
1274
1275         if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
1276                 sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1277         {
1278                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1279                 value = &sa->sa_initial;
1280
1281                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
1282                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
1283
1284                 HASH_Init( &HASHcontext );
1285                 if( prefix != NULL && prefix->bv_len > 0 ) {
1286                         HASH_Update( &HASHcontext,
1287                                 prefix->bv_val, prefix->bv_len );
1288                 }
1289                 HASH_Update( &HASHcontext,
1290                         &pre, sizeof( pre ) );
1291                 HASH_Update( &HASHcontext,
1292                         syntax->ssyn_oid, slen );
1293                 HASH_Update( &HASHcontext,
1294                         mr->smr_oid, mlen );
1295                 HASH_Update( &HASHcontext,
1296                         value->bv_val, klen );
1297                 HASH_Final( HASHdigest, &HASHcontext );
1298
1299                 ber_dupbv( &keys[nkeys++], &digest );
1300         }
1301
1302         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1303                 ber_len_t i, j;
1304                 pre = SLAP_INDEX_SUBSTR_PREFIX;
1305                 klen = SLAP_INDEX_SUBSTR_MAXLEN;
1306
1307                 for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
1308                         if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
1309                                 continue;
1310                         }
1311
1312                         value = &sa->sa_any[i];
1313
1314                         for(j=0;
1315                                 j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
1316                                 j += SLAP_INDEX_SUBSTR_STEP )
1317                         {
1318                                 HASH_Init( &HASHcontext );
1319                                 if( prefix != NULL && prefix->bv_len > 0 ) {
1320                                         HASH_Update( &HASHcontext,
1321                                                 prefix->bv_val, prefix->bv_len );
1322                                 }
1323                                 HASH_Update( &HASHcontext,
1324                                         &pre, sizeof( pre ) );
1325                                 HASH_Update( &HASHcontext,
1326                                         syntax->ssyn_oid, slen );
1327                                 HASH_Update( &HASHcontext,
1328                                         mr->smr_oid, mlen );
1329                                 HASH_Update( &HASHcontext,
1330                                         &value->bv_val[j], klen ); 
1331                                 HASH_Final( HASHdigest, &HASHcontext );
1332
1333                                 ber_dupbv( &keys[nkeys++], &digest );
1334                         }
1335
1336                 }
1337         }
1338
1339         if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
1340                 sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
1341         {
1342                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1343                 value = &sa->sa_final;
1344
1345                 klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
1346                         ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
1347
1348                 HASH_Init( &HASHcontext );
1349                 if( prefix != NULL && prefix->bv_len > 0 ) {
1350                         HASH_Update( &HASHcontext,
1351                                 prefix->bv_val, prefix->bv_len );
1352                 }
1353                 HASH_Update( &HASHcontext,
1354                         &pre, sizeof( pre ) );
1355                 HASH_Update( &HASHcontext,
1356                         syntax->ssyn_oid, slen );
1357                 HASH_Update( &HASHcontext,
1358                         mr->smr_oid, mlen );
1359                 HASH_Update( &HASHcontext,
1360                         &value->bv_val[value->bv_len-klen], klen );
1361                 HASH_Final( HASHdigest, &HASHcontext );
1362
1363                 ber_dupbv( &keys[nkeys++], &digest );
1364         }
1365
1366         if( nkeys > 0 ) {
1367                 keys[nkeys].bv_val = NULL;
1368                 *keysp = keys;
1369         } else {
1370                 ch_free( keys );
1371                 *keysp = NULL;
1372         }
1373
1374         return LDAP_SUCCESS;
1375 }
1376
1377 /* Remove all spaces and '-' characters */
1378 static int
1379 telephoneNumberNormalize(
1380         slap_mask_t usage,
1381         Syntax *syntax,
1382         MatchingRule *mr,
1383         struct berval *val,
1384         struct berval *normalized )
1385 {
1386         char *p, *q;
1387
1388         /* validator should have refused an empty string */
1389         assert( val->bv_len );
1390
1391         q = normalized->bv_val = ch_malloc( val->bv_len + 1 );
1392
1393         for( p = val->bv_val; *p; p++ ) {
1394                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1395                         *q++ = *p;
1396                 }
1397         }
1398         *q = '\0';
1399
1400         normalized->bv_len = q - normalized->bv_val;
1401
1402         if( normalized->bv_len == 0 ) {
1403                 free( normalized->bv_val );
1404                 return LDAP_INVALID_SYNTAX;
1405         }
1406
1407         return LDAP_SUCCESS;
1408 }
1409
1410 static int
1411 oidValidate(
1412         Syntax *syntax,
1413         struct berval *val )
1414 {
1415         ber_len_t i;
1416
1417         if( val->bv_len == 0 ) {
1418                 /* disallow empty strings */
1419                 return LDAP_INVALID_SYNTAX;
1420         }
1421
1422         if( OID_LEADCHAR(val->bv_val[0]) ) {
1423                 int dot = 0;
1424                 for(i=1; i < val->bv_len; i++) {
1425                         if( OID_SEPARATOR( val->bv_val[i] ) ) {
1426                                 if( dot++ ) return 1;
1427                         } else if ( OID_CHAR( val->bv_val[i] ) ) {
1428                                 dot = 0;
1429                         } else {
1430                                 return LDAP_INVALID_SYNTAX;
1431                         }
1432                 }
1433
1434                 return !dot ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
1435
1436         } else if( DESC_LEADCHAR(val->bv_val[0]) ) {
1437                 for(i=1; i < val->bv_len; i++) {
1438                         if( !DESC_CHAR(val->bv_val[i] ) ) {
1439                                 return LDAP_INVALID_SYNTAX;
1440                         }
1441                 }
1442
1443                 return LDAP_SUCCESS;
1444         }
1445         
1446         return LDAP_INVALID_SYNTAX;
1447 }
1448
1449 static int
1450 integerMatch(
1451         int *matchp,
1452         slap_mask_t flags,
1453         Syntax *syntax,
1454         MatchingRule *mr,
1455         struct berval *value,
1456         void *assertedValue )
1457 {
1458         char *v, *av;
1459         int vsign = 1, avsign = 1;      /* default sign = '+' */
1460         struct berval *asserted;
1461         ber_len_t vlen, avlen;
1462         int match;
1463
1464         /* Skip leading space/sign/zeroes, and get the sign of the *value number */
1465         v = value->bv_val;
1466         vlen = value->bv_len;
1467
1468 #ifndef SLAP_NVALUES
1469         if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
1470                 char *tmp = memchr( v, '$', vlen );
1471                 if( tmp ) vlen = tmp - v;
1472                 while( vlen && ASCII_SPACE( v[vlen-1] )) vlen--;
1473         }
1474 #endif
1475
1476         for( ; vlen && ( *v < '1' || '9' < *v ); v++, vlen-- ) { /* ANSI 2.2.1 */
1477                 if( *v == '-' ) vsign = -1;
1478         }
1479
1480         if( vlen == 0 ) vsign = 0;
1481
1482         /* Do the same with the *assertedValue number */
1483         asserted = (struct berval *) assertedValue;
1484         av = asserted->bv_val;
1485         avlen = asserted->bv_len;
1486         for( ; avlen && ( *av < '1' || '9' < *av ); av++, avlen-- )
1487                 if( *av == '-' )
1488                         avsign = -1;
1489         if( avlen == 0 )
1490                 avsign = 0;
1491
1492         match = vsign - avsign;
1493         if( match == 0 ) {
1494                 match = (vlen != avlen
1495                              ? ( vlen < avlen ? -1 : 1 )
1496                              : memcmp( v, av, vlen ));
1497                 if( vsign < 0 )
1498                         match = -match;
1499         }
1500
1501         *matchp = match;
1502         return LDAP_SUCCESS;
1503 }
1504         
1505 static int
1506 integerValidate(
1507         Syntax *syntax,
1508         struct berval *val )
1509 {
1510         ber_len_t i;
1511
1512         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
1513
1514         if(( val->bv_val[0] == '+' ) || ( val->bv_val[0] == '-' )) {
1515                 if( val->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
1516
1517         } else if( !ASCII_DIGIT(val->bv_val[0]) ) {
1518                 return LDAP_INVALID_SYNTAX;
1519         }
1520
1521         for( i=1; i < val->bv_len; i++ ) {
1522                 if( !ASCII_DIGIT(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
1523         }
1524
1525         return LDAP_SUCCESS;
1526 }
1527
1528 static int
1529 integerNormalize(
1530         slap_mask_t use,
1531         Syntax *syntax,
1532         MatchingRule *mr,
1533         struct berval *val,
1534         struct berval *normalized )
1535 {
1536         char *p;
1537         int negative=0;
1538         ber_len_t len;
1539
1540
1541         p = val->bv_val;
1542         len = val->bv_len;
1543
1544         /* Ignore leading spaces */
1545         while ( len && ( *p == ' ' )) {
1546                 p++;
1547                 len--;
1548         }
1549
1550         /* save sign */
1551         if( len ) {
1552                 negative = ( *p == '-' );
1553                 if(( *p == '-' ) || ( *p == '+' )) {
1554                         p++;
1555                         len--;
1556                 }
1557         }
1558
1559         /* Ignore leading zeros */
1560         while ( len && ( *p == '0' )) {
1561                 p++;
1562                 len--;
1563         }
1564
1565         /* If there are no non-zero digits left, the number is zero, otherwise
1566            allocate space for the number and copy it into the buffer */
1567         if( len == 0 ) {
1568                 normalized->bv_val = ch_strdup("0");
1569                 normalized->bv_len = 1;
1570
1571         } else {
1572                 normalized->bv_len = len+negative;
1573                 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
1574                 if( negative ) normalized->bv_val[0] = '-';
1575                 AC_MEMCPY( normalized->bv_val + negative, p, len );
1576                 normalized->bv_val[len+negative] = '\0';
1577         }
1578
1579         return LDAP_SUCCESS;
1580 }
1581
1582 static int
1583 countryStringValidate(
1584         Syntax *syntax,
1585         struct berval *val )
1586 {
1587         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
1588
1589         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
1590                 return LDAP_INVALID_SYNTAX;
1591         }
1592         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
1593                 return LDAP_INVALID_SYNTAX;
1594         }
1595
1596         return LDAP_SUCCESS;
1597 }
1598
1599 static int
1600 printableStringValidate(
1601         Syntax *syntax,
1602         struct berval *val )
1603 {
1604         ber_len_t i;
1605
1606         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1607
1608         for(i=0; i < val->bv_len; i++) {
1609                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
1610                         return LDAP_INVALID_SYNTAX;
1611                 }
1612         }
1613
1614         return LDAP_SUCCESS;
1615 }
1616
1617 static int
1618 printablesStringValidate(
1619         Syntax *syntax,
1620         struct berval *val )
1621 {
1622         ber_len_t i, len;
1623
1624         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1625
1626         for(i=0,len=0; i < val->bv_len; i++) {
1627                 int c = val->bv_val[i];
1628
1629                 if( c == '$' ) {
1630                         if( len == 0 ) {
1631                                 return LDAP_INVALID_SYNTAX;
1632                         }
1633                         len = 0;
1634
1635                 } else if ( SLAP_PRINTABLE(c) ) {
1636                         len++;
1637                 } else {
1638                         return LDAP_INVALID_SYNTAX;
1639                 }
1640         }
1641
1642         if( len == 0 ) {
1643                 return LDAP_INVALID_SYNTAX;
1644         }
1645
1646         return LDAP_SUCCESS;
1647 }
1648
1649 static int
1650 IA5StringValidate(
1651         Syntax *syntax,
1652         struct berval *val )
1653 {
1654         ber_len_t i;
1655
1656         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1657
1658         for(i=0; i < val->bv_len; i++) {
1659                 if( !LDAP_ASCII(val->bv_val[i]) ) {
1660                         return LDAP_INVALID_SYNTAX;
1661                 }
1662         }
1663
1664         return LDAP_SUCCESS;
1665 }
1666
1667 static int
1668 IA5StringNormalize(
1669         slap_mask_t use,
1670         Syntax *syntax,
1671         MatchingRule *mr,
1672         struct berval *val,
1673         struct berval *normalized )
1674 {
1675         char *p, *q;
1676         int casefold = !SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
1677
1678         assert( val->bv_len );
1679
1680         p = val->bv_val;
1681
1682         /* Ignore initial whitespace */
1683         while ( ASCII_SPACE( *p ) ) {
1684                 p++;
1685         }
1686
1687         normalized->bv_val = ch_strdup( p );
1688         p = q = normalized->bv_val;
1689
1690         while ( *p ) {
1691                 if ( ASCII_SPACE( *p ) ) {
1692                         *q++ = *p++;
1693
1694                         /* Ignore the extra whitespace */
1695                         while ( ASCII_SPACE( *p ) ) {
1696                                 p++;
1697                         }
1698
1699                 } else if ( casefold ) {
1700                         /* Most IA5 rules require casefolding */
1701                         *q++ = TOLOWER(*p++);
1702
1703                 } else {
1704                         *q++ = *p++;
1705                 }
1706         }
1707
1708         assert( normalized->bv_val <= p );
1709         assert( q <= p );
1710
1711         /*
1712          * If the string ended in space, backup the pointer one
1713          * position.  One is enough because the above loop collapsed
1714          * all whitespace to a single space.
1715          */
1716
1717         if ( ASCII_SPACE( q[-1] ) ) {
1718                 --q;
1719         }
1720
1721         /* null terminate */
1722         *q = '\0';
1723
1724         normalized->bv_len = q - normalized->bv_val;
1725
1726         if( normalized->bv_len == 0 ) {
1727                 normalized->bv_val = ch_realloc( normalized->bv_val, 2 );
1728                 normalized->bv_val[0] = ' ';
1729                 normalized->bv_val[1] = '\0';
1730                 normalized->bv_len = 1;
1731         }
1732
1733         return LDAP_SUCCESS;
1734 }
1735
1736 static int
1737 octetStringSubstringsMatch (
1738         int *matchp,
1739         slap_mask_t flags,
1740         Syntax *syntax,
1741         MatchingRule *mr,
1742         struct berval *value,
1743         void *assertedValue )
1744 {
1745         int match = 0;
1746         SubstringsAssertion *sub = assertedValue;
1747         struct berval left = *value;
1748         int i;
1749         ber_len_t inlen=0;
1750
1751         /* Add up asserted input length */
1752         if( sub->sa_initial.bv_val ) {
1753                 inlen += sub->sa_initial.bv_len;
1754         }
1755         if( sub->sa_any ) {
1756                 for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
1757                         inlen += sub->sa_any[i].bv_len;
1758                 }
1759         }
1760         if( sub->sa_final.bv_val ) {
1761                 inlen += sub->sa_final.bv_len;
1762         }
1763
1764         if( sub->sa_initial.bv_val ) {
1765                 if( inlen > left.bv_len ) {
1766                         match = 1;
1767                         goto done;
1768                 }
1769
1770                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1771                         sub->sa_initial.bv_len );
1772
1773                 if( match != 0 ) {
1774                         goto done;
1775                 }
1776
1777                 left.bv_val += sub->sa_initial.bv_len;
1778                 left.bv_len -= sub->sa_initial.bv_len;
1779                 inlen -= sub->sa_initial.bv_len;
1780         }
1781
1782         if( sub->sa_final.bv_val ) {
1783                 if( inlen > left.bv_len ) {
1784                         match = 1;
1785                         goto done;
1786                 }
1787
1788                 match = memcmp( sub->sa_final.bv_val,
1789                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1790                         sub->sa_final.bv_len );
1791
1792                 if( match != 0 ) {
1793                         goto done;
1794                 }
1795
1796                 left.bv_len -= sub->sa_final.bv_len;
1797                 inlen -= sub->sa_final.bv_len;
1798         }
1799
1800         if( sub->sa_any ) {
1801                 for(i=0; sub->sa_any[i].bv_val; i++) {
1802                         ber_len_t idx;
1803                         char *p;
1804
1805 retry:
1806                         if( inlen > left.bv_len ) {
1807                                 /* not enough length */
1808                                 match = 1;
1809                                 goto done;
1810                         }
1811
1812                         if( sub->sa_any[i].bv_len == 0 ) {
1813                                 continue;
1814                         }
1815
1816                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1817
1818                         if( p == NULL ) {
1819                                 match = 1;
1820                                 goto done;
1821                         }
1822
1823                         idx = p - left.bv_val;
1824
1825                         if( idx >= left.bv_len ) {
1826                                 /* this shouldn't happen */
1827                                 return LDAP_OTHER;
1828                         }
1829
1830                         left.bv_val = p;
1831                         left.bv_len -= idx;
1832
1833                         if( sub->sa_any[i].bv_len > left.bv_len ) {
1834                                 /* not enough left */
1835                                 match = 1;
1836                                 goto done;
1837                         }
1838
1839                         match = memcmp( left.bv_val,
1840                                 sub->sa_any[i].bv_val,
1841                                 sub->sa_any[i].bv_len );
1842
1843                         if( match != 0 ) {
1844                                 left.bv_val++;
1845                                 left.bv_len--;
1846                                 goto retry;
1847                         }
1848
1849                         left.bv_val += sub->sa_any[i].bv_len;
1850                         left.bv_len -= sub->sa_any[i].bv_len;
1851                         inlen -= sub->sa_any[i].bv_len;
1852                 }
1853         }
1854
1855 done:
1856         *matchp = match;
1857         return LDAP_SUCCESS;
1858 }
1859
1860 static int
1861 numericStringValidate(
1862         Syntax *syntax,
1863         struct berval *in )
1864 {
1865         ber_len_t i;
1866
1867         if( in->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1868
1869         for(i=0; i < in->bv_len; i++) {
1870                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
1871                         return LDAP_INVALID_SYNTAX;
1872                 }
1873         }
1874
1875         return LDAP_SUCCESS;
1876 }
1877
1878 static int
1879 numericStringNormalize(
1880         slap_mask_t usage,
1881         Syntax *syntax,
1882         MatchingRule *mr,
1883         struct berval *val,
1884         struct berval *normalized )
1885 {
1886         /* removal all spaces */
1887         char *p, *q;
1888
1889         assert( val->bv_len );
1890
1891         normalized->bv_val = ch_malloc( val->bv_len + 1 );
1892
1893         p = val->bv_val;
1894         q = normalized->bv_val;
1895
1896         while ( *p ) {
1897                 if ( ASCII_SPACE( *p ) ) {
1898                         /* Ignore whitespace */
1899                         p++;
1900                 } else {
1901                         *q++ = *p++;
1902                 }
1903         }
1904
1905         /* we should have copied no more then is in val */
1906         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
1907
1908         /* null terminate */
1909         *q = '\0';
1910
1911         normalized->bv_len = q - normalized->bv_val;
1912
1913         if( normalized->bv_len == 0 ) {
1914                 normalized->bv_val = ch_realloc( normalized->bv_val, 2 );
1915                 normalized->bv_val[0] = ' ';
1916                 normalized->bv_val[1] = '\0';
1917                 normalized->bv_len = 1;
1918         }
1919
1920         return LDAP_SUCCESS;
1921 }
1922
1923 #ifndef SLAP_NVALUES
1924 static int
1925 objectIdentifierFirstComponentMatch(
1926         int *matchp,
1927         slap_mask_t flags,
1928         Syntax *syntax,
1929         MatchingRule *mr,
1930         struct berval *value,
1931         void *assertedValue )
1932 {
1933         int rc = LDAP_SUCCESS;
1934         int match;
1935         struct berval *asserted = (struct berval *) assertedValue;
1936         ber_len_t i, j;
1937         struct berval oid;
1938
1939         if( value->bv_len == 0 || value->bv_val[0] != '(' /*')'*/ ) {
1940                 return LDAP_INVALID_SYNTAX;
1941         }
1942
1943         /* trim leading white space */
1944         for( i=1; ASCII_SPACE(value->bv_val[i]) && i < value->bv_len; i++ ) {
1945                 /* empty */
1946         }
1947
1948         /* grab next word */
1949         oid.bv_val = &value->bv_val[i];
1950         j = value->bv_len - i;
1951         for( i=0; !ASCII_SPACE(oid.bv_val[i]) && i < j; i++ ) {
1952                 /* empty */
1953         }
1954         oid.bv_len = i;
1955
1956         /* insert attributeTypes, objectclass check here */
1957         if( OID_LEADCHAR(asserted->bv_val[0]) ) {
1958                 rc = objectIdentifierMatch( &match, flags, syntax, mr, &oid, asserted );
1959
1960         } else {
1961                 if ( !strcmp( syntax->ssyn_oid, SLAP_SYNTAX_MATCHINGRULES_OID ) ) {
1962                         MatchingRule *asserted_mr = mr_bvfind( asserted );
1963                         MatchingRule *stored_mr = mr_bvfind( &oid );
1964
1965                         if( asserted_mr == NULL ) {
1966                                 rc = SLAPD_COMPARE_UNDEFINED;
1967                         } else {
1968                                 match = asserted_mr != stored_mr;
1969                         }
1970
1971                 } else if ( !strcmp( syntax->ssyn_oid,
1972                         SLAP_SYNTAX_ATTRIBUTETYPES_OID ) )
1973                 {
1974                         AttributeType *asserted_at = at_bvfind( asserted );
1975                         AttributeType *stored_at = at_bvfind( &oid );
1976
1977                         if( asserted_at == NULL ) {
1978                                 rc = SLAPD_COMPARE_UNDEFINED;
1979                         } else {
1980                                 match = asserted_at != stored_at;
1981                         }
1982
1983                 } else if ( !strcmp( syntax->ssyn_oid,
1984                         SLAP_SYNTAX_OBJECTCLASSES_OID ) )
1985                 {
1986                         ObjectClass *asserted_oc = oc_bvfind( asserted );
1987                         ObjectClass *stored_oc = oc_bvfind( &oid );
1988
1989                         if( asserted_oc == NULL ) {
1990                                 rc = SLAPD_COMPARE_UNDEFINED;
1991                         } else {
1992                                 match = asserted_oc != stored_oc;
1993                         }
1994                 }
1995         }
1996
1997 #ifdef NEW_LOGGING
1998         LDAP_LOG( CONFIG, ENTRY, 
1999                 "objectIdentifierFirstComponentMatch: %d\n %s\n %s\n",
2000                 match, value->bv_val, asserted->bv_val );
2001 #else
2002         Debug( LDAP_DEBUG_ARGS, "objectIdentifierFirstComponentMatch "
2003                 "%d\n\t\"%s\"\n\t\"%s\"\n",
2004                 match, value->bv_val, asserted->bv_val );
2005 #endif
2006
2007         if( rc == LDAP_SUCCESS ) *matchp = match;
2008         return rc;
2009 }
2010 #endif
2011
2012 static int
2013 integerBitAndMatch(
2014         int *matchp,
2015         slap_mask_t flags,
2016         Syntax *syntax,
2017         MatchingRule *mr,
2018         struct berval *value,
2019         void *assertedValue )
2020 {
2021         long lValue, lAssertedValue;
2022
2023         /* safe to assume integers are NUL terminated? */
2024         lValue = strtol(value->bv_val, NULL, 10);
2025         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
2026                 return LDAP_CONSTRAINT_VIOLATION;
2027         }
2028
2029         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
2030         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
2031                 && errno == ERANGE )
2032         {
2033                 return LDAP_CONSTRAINT_VIOLATION;
2034         }
2035
2036         *matchp = (lValue & lAssertedValue) ? 0 : 1;
2037         return LDAP_SUCCESS;
2038 }
2039
2040 static int
2041 integerBitOrMatch(
2042         int *matchp,
2043         slap_mask_t flags,
2044         Syntax *syntax,
2045         MatchingRule *mr,
2046         struct berval *value,
2047         void *assertedValue )
2048 {
2049         long lValue, lAssertedValue;
2050
2051         /* safe to assume integers are NUL terminated? */
2052         lValue = strtol(value->bv_val, NULL, 10);
2053         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
2054                 return LDAP_CONSTRAINT_VIOLATION;
2055         }
2056
2057         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
2058         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
2059                 && errno == ERANGE )
2060         {
2061                 return LDAP_CONSTRAINT_VIOLATION;
2062         }
2063
2064         *matchp = (lValue | lAssertedValue) ? 0 : -1;
2065         return LDAP_SUCCESS;
2066 }
2067
2068 #ifndef SLAP_NVALUES
2069 #ifdef HAVE_TLS
2070 #include <openssl/x509.h>
2071 #include <openssl/err.h>
2072
2073 /*
2074  * Next function returns a string representation of a ASN1_INTEGER.
2075  * It works for unlimited lengths.
2076  */
2077
2078 static struct berval *
2079 asn1_integer2str(ASN1_INTEGER *a, struct berval *bv)
2080 {
2081         char buf[256];
2082         char *p;
2083         static char digit[] = "0123456789";
2084   
2085         /* We work backwards, make it fill from the end of buf */
2086         p = buf + sizeof(buf) - 1;
2087         *p = '\0';
2088
2089         if ( a == NULL || a->length == 0 ) {
2090                 *--p = '0';
2091         } else {
2092                 int i;
2093                 int n = a->length;
2094                 int base = 0;
2095                 unsigned int *copy;
2096
2097                 /* We want to preserve the original */
2098                 copy = ch_malloc(n*sizeof(unsigned int));
2099                 for (i = 0; i<n; i++) {
2100                         copy[i] = a->data[i];
2101                 }
2102
2103                 /* 
2104                  * base indicates the index of the most significant
2105                  * byte that might be nonzero.  When it goes off the
2106                  * end, we now there is nothing left to do.
2107                  */
2108                 while (base < n) {
2109                         unsigned int carry;
2110
2111                         carry = 0;
2112                         for (i = base; i<n; i++ ) {
2113                                 copy[i] += carry*256;
2114                                 carry = copy[i] % 10;
2115                                 copy[i] /= 10;
2116                         }
2117                         if (p <= buf+1) {
2118                                 /*
2119                                  * Way too large, we need to leave
2120                                  * room for sign if negative
2121                                  */
2122                                 free(copy);
2123                                 return NULL;
2124                         }
2125                         *--p = digit[carry];
2126
2127                         if (copy[base] == 0) base++;
2128                 }
2129                 free(copy);
2130         }
2131
2132         if ( a->type == V_ASN1_NEG_INTEGER ) {
2133                 *--p = '-';
2134         }
2135
2136         return ber_str2bv( p, 0, 1, bv );
2137 }
2138
2139 /*
2140  * Given a certificate in DER format, extract the corresponding
2141  * assertion value for certificateExactMatch
2142  */
2143 static int
2144 certificateExactConvert(
2145         struct berval * in,
2146         struct berval * out )
2147 {
2148         X509 *xcert;
2149         unsigned char *p = in->bv_val;
2150         struct berval serial;
2151         struct berval issuer_dn;
2152
2153         xcert = d2i_X509(NULL, &p, in->bv_len);
2154         if ( !xcert ) {
2155 #ifdef NEW_LOGGING
2156                 LDAP_LOG( CONFIG, ENTRY, 
2157                         "certificateExactConvert: error parsing cert: %s\n",
2158                         ERR_error_string(ERR_get_error(),NULL), 0, 0 );
2159 #else
2160                 Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: "
2161                        "error parsing cert: %s\n",
2162                        ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
2163 #endif
2164                 return LDAP_INVALID_SYNTAX;
2165         }
2166
2167         if ( !asn1_integer2str(xcert->cert_info->serialNumber, &serial) ) {
2168                 X509_free(xcert);
2169                 return LDAP_INVALID_SYNTAX;
2170         }
2171         if ( dnX509normalize(X509_get_issuer_name(xcert), &issuer_dn )
2172                 != LDAP_SUCCESS )
2173         {
2174                 X509_free(xcert);
2175                 ber_memfree(serial.bv_val);
2176                 return LDAP_INVALID_SYNTAX;
2177         }
2178
2179         X509_free(xcert);
2180
2181         out->bv_len = serial.bv_len + issuer_dn.bv_len + sizeof(" $ ");
2182         out->bv_val = ch_malloc(out->bv_len);
2183         p = out->bv_val;
2184         AC_MEMCPY(p, serial.bv_val, serial.bv_len);
2185         p += serial.bv_len;
2186         AC_MEMCPY(p, " $ ", sizeof(" $ ")-1);
2187         p += 3;
2188         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2189         p += issuer_dn.bv_len;
2190         *p++ = '\0';
2191
2192 #ifdef NEW_LOGGING
2193         LDAP_LOG( CONFIG, ARGS, 
2194                 "certificateExactConvert: \n    %s\n", out->bv_val, 0, 0 );
2195 #else
2196         Debug( LDAP_DEBUG_ARGS, "certificateExactConvert "
2197                 "\n\t\"%s\"\n",
2198                 out->bv_val, NULL, NULL );
2199 #endif
2200
2201         ber_memfree(serial.bv_val);
2202         ber_memfree(issuer_dn.bv_val);
2203
2204         return LDAP_SUCCESS;
2205 }
2206
2207 static int
2208 serial_and_issuer_parse(
2209         struct berval *assertion,
2210         struct berval *serial,
2211         struct berval *issuer_dn
2212 )
2213 {
2214         char *begin;
2215         char *end;
2216         char *p;
2217         struct berval bv;
2218
2219         begin = assertion->bv_val;
2220         end = assertion->bv_val+assertion->bv_len-1;
2221         for (p=begin; p<=end && *p != '$'; p++) /* empty */ ;
2222         if ( p > end ) return LDAP_INVALID_SYNTAX;
2223
2224         /* p now points at the $ sign, now use
2225          * begin and end to delimit the serial number
2226          */
2227         while (ASCII_SPACE(*begin)) begin++;
2228         end = p-1;
2229         while (ASCII_SPACE(*end)) end--;
2230
2231         if( end <= begin ) return LDAP_INVALID_SYNTAX;
2232
2233         bv.bv_len = end-begin+1;
2234         bv.bv_val = begin;
2235         ber_dupbv(serial, &bv);
2236
2237         /* now extract the issuer, remember p was at the dollar sign */
2238         begin = p+1;
2239         end = assertion->bv_val+assertion->bv_len-1;
2240         while (ASCII_SPACE(*begin)) begin++;
2241         /* should we trim spaces at the end too? is it safe always? no, no */
2242
2243         if( end <= begin ) return LDAP_INVALID_SYNTAX;
2244
2245         if ( issuer_dn ) {
2246                 bv.bv_len = end-begin+1;
2247                 bv.bv_val = begin;
2248
2249                 dnNormalize2( NULL, &bv, issuer_dn );
2250         }
2251
2252         return LDAP_SUCCESS;
2253 }
2254
2255 static int
2256 certificateExactMatch(
2257         int *matchp,
2258         slap_mask_t flags,
2259         Syntax *syntax,
2260         MatchingRule *mr,
2261         struct berval *value,
2262         void *assertedValue )
2263 {
2264         X509 *xcert;
2265         unsigned char *p = value->bv_val;
2266         struct berval serial;
2267         struct berval issuer_dn;
2268         struct berval asserted_serial;
2269         struct berval asserted_issuer_dn;
2270         int ret;
2271
2272         xcert = d2i_X509(NULL, &p, value->bv_len);
2273         if ( !xcert ) {
2274 #ifdef NEW_LOGGING
2275                 LDAP_LOG( CONFIG, ENTRY, 
2276                         "certificateExactMatch: error parsing cert: %s\n",
2277                         ERR_error_string(ERR_get_error(),NULL), 0, 0 );
2278 #else
2279                 Debug( LDAP_DEBUG_ARGS, "certificateExactMatch: "
2280                        "error parsing cert: %s\n",
2281                        ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
2282 #endif
2283                 return LDAP_INVALID_SYNTAX;
2284         }
2285
2286         asn1_integer2str(xcert->cert_info->serialNumber, &serial);
2287         dnX509normalize(X509_get_issuer_name(xcert), &issuer_dn);
2288
2289         X509_free(xcert);
2290
2291         serial_and_issuer_parse(assertedValue,
2292                 &asserted_serial, &asserted_issuer_dn);
2293
2294         ret = integerMatch(
2295                 matchp,
2296                 flags,
2297                 slap_schema.si_syn_integer,
2298                 slap_schema.si_mr_integerMatch,
2299                 &serial,
2300                 &asserted_serial);
2301         if ( ret == LDAP_SUCCESS ) {
2302                 if ( *matchp == 0 ) {
2303                         /* We need to normalize everything for dnMatch */
2304                         ret = dnMatch(
2305                                 matchp,
2306                                 flags,
2307                                 slap_schema.si_syn_distinguishedName,
2308                                 slap_schema.si_mr_distinguishedNameMatch,
2309                                 &issuer_dn,
2310                                 &asserted_issuer_dn);
2311                 }
2312         }
2313
2314 #ifdef NEW_LOGGING
2315         LDAP_LOG( CONFIG, ARGS, "certificateExactMatch "
2316                 "%d\n\t\"%s $ %s\"\n",
2317                 *matchp, serial.bv_val, issuer_dn.bv_val );
2318         LDAP_LOG( CONFIG, ARGS, "\t\"%s $ %s\"\n",
2319                 asserted_serial.bv_val, asserted_issuer_dn.bv_val,
2320                 0 );
2321 #else
2322         Debug( LDAP_DEBUG_ARGS, "certificateExactMatch "
2323                 "%d\n\t\"%s $ %s\"\n",
2324                 *matchp, serial.bv_val, issuer_dn.bv_val );
2325         Debug( LDAP_DEBUG_ARGS, "\t\"%s $ %s\"\n",
2326                 asserted_serial.bv_val, asserted_issuer_dn.bv_val,
2327                 NULL );
2328 #endif
2329
2330         ber_memfree(serial.bv_val);
2331         ber_memfree(issuer_dn.bv_val);
2332         ber_memfree(asserted_serial.bv_val);
2333         ber_memfree(asserted_issuer_dn.bv_val);
2334
2335         return ret;
2336 }
2337
2338 /* 
2339  * Index generation function
2340  * We just index the serials, in most scenarios the issuer DN is one of
2341  * a very small set of values.
2342  */
2343 static int certificateExactIndexer(
2344         slap_mask_t use,
2345         slap_mask_t flags,
2346         Syntax *syntax,
2347         MatchingRule *mr,
2348         struct berval *prefix,
2349         BerVarray values,
2350         BerVarray *keysp )
2351 {
2352         int i;
2353         BerVarray keys;
2354         X509 *xcert;
2355         unsigned char *p;
2356         struct berval serial;
2357
2358         /* we should have at least one value at this point */
2359         assert( values != NULL && values[0].bv_val != NULL );
2360
2361         for( i=0; values[i].bv_val != NULL; i++ ) {
2362                 /* empty -- just count them */
2363         }
2364
2365         keys = ch_malloc( sizeof( struct berval ) * (i+1) );
2366
2367         for( i=0; values[i].bv_val != NULL; i++ ) {
2368                 p = values[i].bv_val;
2369                 xcert = d2i_X509(NULL, &p, values[i].bv_len);
2370                 if ( !xcert ) {
2371 #ifdef NEW_LOGGING
2372                         LDAP_LOG( CONFIG, ENTRY, 
2373                                 "certificateExactIndexer: error parsing cert: %s\n",
2374                                 ERR_error_string(ERR_get_error(),NULL), 0, 0);
2375 #else
2376                         Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
2377                                "error parsing cert: %s\n",
2378                                ERR_error_string(ERR_get_error(),NULL),
2379                                NULL, NULL );
2380 #endif
2381                         /* Do we leak keys on error? */
2382                         return LDAP_INVALID_SYNTAX;
2383                 }
2384
2385                 asn1_integer2str(xcert->cert_info->serialNumber, &serial);
2386                 X509_free(xcert);
2387                 xintegerNormalize( slap_schema.si_syn_integer,
2388                         &serial, &keys[i] );
2389                 ber_memfree(serial.bv_val);
2390 #ifdef NEW_LOGGING
2391                 LDAP_LOG( CONFIG, ENTRY, 
2392                         "certificateExactIndexer: returning: %s\n", keys[i].bv_val, 0, 0);
2393 #else
2394                 Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
2395                        "returning: %s\n",
2396                        keys[i].bv_val,
2397                        NULL, NULL );
2398 #endif
2399         }
2400
2401         keys[i].bv_val = NULL;
2402         *keysp = keys;
2403         return LDAP_SUCCESS;
2404 }
2405
2406 /* Index generation function */
2407 /* We think this is always called with a value in matching rule syntax */
2408 static int certificateExactFilter(
2409         slap_mask_t use,
2410         slap_mask_t flags,
2411         Syntax *syntax,
2412         MatchingRule *mr,
2413         struct berval *prefix,
2414         void * assertedValue,
2415         BerVarray *keysp )
2416 {
2417         BerVarray keys;
2418         struct berval asserted_serial;
2419         int ret;
2420
2421         ret = serial_and_issuer_parse( assertedValue, &asserted_serial, NULL );
2422         if( ret != LDAP_SUCCESS ) return ret;
2423
2424         keys = ch_malloc( sizeof( struct berval ) * 2 );
2425         xintegerNormalize( syntax, &asserted_serial, &keys[0] );
2426         keys[1].bv_val = NULL;
2427         *keysp = keys;
2428
2429         ber_memfree(asserted_serial.bv_val);
2430         return LDAP_SUCCESS;
2431 }
2432 #endif
2433 #endif
2434
2435 static int
2436 check_time_syntax (struct berval *val,
2437         int start,
2438         int *parts)
2439 {
2440         static int ceiling[9] = { 99, 99, 11, 30, 23, 59, 59, 12, 59 };
2441         static int mdays[2][12] = {
2442                 /* non-leap years */
2443                 { 30, 27, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 },
2444                 /* leap years */
2445                 { 30, 28, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 }
2446         };
2447         char *p, *e;
2448         int part, c, tzoffset, leapyear = 0 ;
2449
2450         if( val->bv_len == 0 ) {
2451                 return LDAP_INVALID_SYNTAX;
2452         }
2453
2454         p = (char *)val->bv_val;
2455         e = p + val->bv_len;
2456
2457         /* Ignore initial whitespace */
2458         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
2459                 p++;
2460         }
2461
2462         if (e - p < 13 - (2 * start)) {
2463                 return LDAP_INVALID_SYNTAX;
2464         }
2465
2466         for (part = 0; part < 9; part++) {
2467                 parts[part] = 0;
2468         }
2469
2470         for (part = start; part < 7; part++) {
2471                 c = *p;
2472                 if ((part == 6) && (c == 'Z' || c == '+' || c == '-')) {
2473                         part++;
2474                         break;
2475                 }
2476                 p++;
2477                 c -= '0';
2478                 if (p == e) {
2479                         return LDAP_INVALID_SYNTAX;
2480                 }
2481                 if (c < 0 || c > 9) {
2482                         return LDAP_INVALID_SYNTAX;
2483                 }
2484                 parts[part] = c;
2485
2486                 c = *p++ - '0';
2487                 if (p == e) {
2488                         return LDAP_INVALID_SYNTAX;
2489                 }
2490                 if (c < 0 || c > 9) {
2491                         return LDAP_INVALID_SYNTAX;
2492                 }
2493                 parts[part] *= 10;
2494                 parts[part] += c;
2495
2496                 if (part == 2 || part == 3) {
2497                         parts[part]--;
2498                 }
2499                 if (parts[part] < 0) {
2500                         return LDAP_INVALID_SYNTAX;
2501                 }
2502                 if (parts[part] > ceiling[part]) {
2503                         return LDAP_INVALID_SYNTAX;
2504                 }
2505         }
2506
2507         /* leapyear check for the Gregorian calendar (year>1581) */
2508         if (((parts[1] % 4 == 0) && (parts[1] != 0)) ||
2509                 ((parts[0] % 4 == 0) && (parts[1] == 0)))
2510         {
2511                 leapyear = 1;
2512         }
2513
2514         if (parts[3] > mdays[leapyear][parts[2]]) {
2515                 return LDAP_INVALID_SYNTAX;
2516         }
2517         
2518         c = *p++;
2519         if (c == 'Z') {
2520                 tzoffset = 0; /* UTC */
2521         } else if (c != '+' && c != '-') {
2522                 return LDAP_INVALID_SYNTAX;
2523         } else {
2524                 if (c == '-') {
2525                         tzoffset = -1;
2526                 } else /* c == '+' */ {
2527                         tzoffset = 1;
2528                 }
2529
2530                 if (p > e - 4) {
2531                         return LDAP_INVALID_SYNTAX;
2532                 }
2533
2534                 for (part = 7; part < 9; part++) {
2535                         c = *p++ - '0';
2536                         if (c < 0 || c > 9) {
2537                                 return LDAP_INVALID_SYNTAX;
2538                         }
2539                         parts[part] = c;
2540
2541                         c = *p++ - '0';
2542                         if (c < 0 || c > 9) {
2543                                 return LDAP_INVALID_SYNTAX;
2544                         }
2545                         parts[part] *= 10;
2546                         parts[part] += c;
2547                         if (parts[part] < 0 || parts[part] > ceiling[part]) {
2548                                 return LDAP_INVALID_SYNTAX;
2549                         }
2550                 }
2551         }
2552
2553         /* Ignore trailing whitespace */
2554         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
2555                 p++;
2556         }
2557         if (p != e) {
2558                 return LDAP_INVALID_SYNTAX;
2559         }
2560
2561         switch ( tzoffset ) {
2562         case -1: /* negativ offset to UTC, ie west of Greenwich  */
2563                 parts[4] += parts[7];
2564                 parts[5] += parts[8];
2565                 for (part = 6; --part > 0; ) { /* offset is just hhmm, no seconds */
2566                         if (part != 3) {
2567                                 c = ceiling[part];
2568                         } else {
2569                                 c = mdays[leapyear][parts[2]];
2570                         }
2571                         if (parts[part] > c) {
2572                                 parts[part] -= c + 1;
2573                                 parts[part - 1]++;
2574                         }
2575                 }
2576                 break;
2577         case 1: /* positive offset to UTC, ie east of Greenwich */
2578                 parts[4] -= parts[7];
2579                 parts[5] -= parts[8];
2580                 for (part = 6; --part > 0; ) {
2581                         if (part != 3) {
2582                                 c = ceiling[part];
2583                         } else {
2584                                 /* first arg to % needs to be non negativ */
2585                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2586                         }
2587                         if (parts[part] < 0) {
2588                                 parts[part] += c + 1;
2589                                 parts[part - 1]--;
2590                         }
2591                 }
2592                 break;
2593         case 0: /* already UTC */
2594                 break;
2595         }
2596
2597         return LDAP_SUCCESS;
2598 }
2599
2600 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2601 static int
2602 xutcTimeNormalize(
2603         Syntax *syntax,
2604         struct berval *val,
2605         struct berval *normalized )
2606 {
2607         int parts[9], rc;
2608
2609         rc = check_time_syntax(val, 1, parts);
2610         if (rc != LDAP_SUCCESS) {
2611                 return rc;
2612         }
2613
2614         normalized->bv_val = ch_malloc( 14 );
2615         if ( normalized->bv_val == NULL ) {
2616                 return LBER_ERROR_MEMORY;
2617         }
2618
2619         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2620                 parts[1], parts[2] + 1, parts[3] + 1,
2621                 parts[4], parts[5], parts[6] );
2622         normalized->bv_len = 13;
2623
2624         return LDAP_SUCCESS;
2625 }
2626
2627 static int
2628 utcTimeValidate(
2629         Syntax *syntax,
2630         struct berval *in )
2631 {
2632         int parts[9];
2633
2634         return check_time_syntax(in, 1, parts);
2635 }
2636 #endif
2637
2638 static int
2639 generalizedTimeValidate(
2640         Syntax *syntax,
2641         struct berval *in )
2642 {
2643         int parts[9];
2644
2645         return check_time_syntax(in, 0, parts);
2646 }
2647
2648 static int
2649 generalizedTimeNormalize(
2650         slap_mask_t usage,
2651         Syntax *syntax,
2652         MatchingRule *mr,
2653         struct berval *val,
2654         struct berval *normalized )
2655 {
2656         int parts[9], rc;
2657
2658         rc = check_time_syntax(val, 0, parts);
2659         if (rc != LDAP_SUCCESS) {
2660                 return rc;
2661         }
2662
2663         normalized->bv_val = ch_malloc( 16 );
2664         if ( normalized->bv_val == NULL ) {
2665                 return LBER_ERROR_MEMORY;
2666         }
2667
2668         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02dZ",
2669                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2670                 parts[4], parts[5], parts[6] );
2671         normalized->bv_len = 15;
2672
2673         return LDAP_SUCCESS;
2674 }
2675
2676 static int
2677 nisNetgroupTripleValidate(
2678         Syntax *syntax,
2679         struct berval *val )
2680 {
2681         char *p, *e;
2682         int commas = 0;
2683
2684         if ( val->bv_len == 0 ) {
2685                 return LDAP_INVALID_SYNTAX;
2686         }
2687
2688         p = (char *)val->bv_val;
2689         e = p + val->bv_len;
2690
2691         if ( *p != '(' /*')'*/ ) {
2692                 return LDAP_INVALID_SYNTAX;
2693         }
2694
2695         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
2696                 if ( *p == ',' ) {
2697                         commas++;
2698                         if ( commas > 2 ) {
2699                                 return LDAP_INVALID_SYNTAX;
2700                         }
2701
2702                 } else if ( !AD_CHAR( *p ) ) {
2703                         return LDAP_INVALID_SYNTAX;
2704                 }
2705         }
2706
2707         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
2708                 return LDAP_INVALID_SYNTAX;
2709         }
2710
2711         p++;
2712
2713         if (p != e) {
2714                 return LDAP_INVALID_SYNTAX;
2715         }
2716
2717         return LDAP_SUCCESS;
2718 }
2719
2720 static int
2721 bootParameterValidate(
2722         Syntax *syntax,
2723         struct berval *val )
2724 {
2725         char *p, *e;
2726
2727         if ( val->bv_len == 0 ) {
2728                 return LDAP_INVALID_SYNTAX;
2729         }
2730
2731         p = (char *)val->bv_val;
2732         e = p + val->bv_len;
2733
2734         /* key */
2735         for (; ( p < e ) && ( *p != '=' ); p++ ) {
2736                 if ( !AD_CHAR( *p ) ) {
2737                         return LDAP_INVALID_SYNTAX;
2738                 }
2739         }
2740
2741         if ( *p != '=' ) {
2742                 return LDAP_INVALID_SYNTAX;
2743         }
2744
2745         /* server */
2746         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
2747                 if ( !AD_CHAR( *p ) ) {
2748                         return LDAP_INVALID_SYNTAX;
2749                 }
2750         }
2751
2752         if ( *p != ':' ) {
2753                 return LDAP_INVALID_SYNTAX;
2754         }
2755
2756         /* path */
2757         for ( p++; p < e; p++ ) {
2758                 if ( !SLAP_PRINTABLE( *p ) ) {
2759                         return LDAP_INVALID_SYNTAX;
2760                 }
2761         }
2762
2763         return LDAP_SUCCESS;
2764 }
2765
2766 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
2767 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
2768
2769 static slap_syntax_defs_rec syntax_defs[] = {
2770         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
2771                 X_BINARY X_NOT_H_R ")",
2772                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
2773         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
2774                 0, NULL, NULL, NULL},
2775         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
2776                 0, NULL, NULL, NULL},
2777         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
2778                 X_NOT_H_R ")",
2779                 SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
2780         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
2781                 X_NOT_H_R ")",
2782                 SLAP_SYNTAX_BER, berValidate, NULL, NULL},
2783         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
2784                 0, bitStringValidate, NULL, NULL },
2785         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
2786                 0, booleanValidate, NULL, NULL},
2787         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
2788                 X_BINARY X_NOT_H_R ")",
2789                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
2790         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
2791                 X_BINARY X_NOT_H_R ")",
2792                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
2793         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
2794                 X_BINARY X_NOT_H_R ")",
2795                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
2796         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
2797                 0, countryStringValidate, xIA5StringNormalize, NULL},
2798         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
2799                 0, dnValidate, xdnNormalize, dnPretty2},
2800         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
2801                 0, NULL, NULL, NULL},
2802         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
2803                 0, NULL, NULL, NULL},
2804         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
2805                 0, UTF8StringValidate, xUTF8StringNormalize, NULL},
2806         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
2807                 0, NULL, NULL, NULL},
2808         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
2809                 0, NULL, NULL, NULL},
2810         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
2811                 0, NULL, NULL, NULL},
2812         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
2813                 0, NULL, NULL, NULL},
2814         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
2815                 0, NULL, NULL, NULL},
2816         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
2817                 0, printablesStringValidate, xtelephoneNumberNormalize, NULL},
2818         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
2819                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
2820         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
2821                 0, generalizedTimeValidate, xgeneralizedTimeNormalize, NULL},
2822         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
2823                 0, NULL, NULL, NULL},
2824         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
2825                 0, IA5StringValidate, xIA5StringNormalize, NULL},
2826         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
2827                 0, integerValidate, xintegerNormalize, NULL},
2828         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
2829                 SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
2830         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
2831                 0, NULL, NULL, NULL},
2832         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
2833                 0, NULL, NULL, NULL},
2834         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
2835                 0, NULL, NULL, NULL},
2836         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
2837                 0, NULL, NULL, NULL},
2838         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
2839                 0, NULL, NULL, NULL},
2840         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
2841                 0, nameUIDValidate, xnameUIDNormalize, NULL},
2842         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
2843                 0, NULL, NULL, NULL},
2844         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
2845                 0, numericStringValidate, xnumericStringNormalize, NULL},
2846         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
2847                 0, NULL, NULL, NULL},
2848         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
2849                 0, oidValidate, NULL, NULL},
2850         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
2851                 0, IA5StringValidate, xIA5StringNormalize, NULL},
2852         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
2853                 0, blobValidate, NULL, NULL},
2854         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
2855                 0, UTF8StringValidate, xUTF8StringNormalize, NULL},
2856         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
2857                 0, NULL, NULL, NULL},
2858         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
2859                 0, NULL, NULL, NULL},
2860         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
2861                 0, printableStringValidate, xIA5StringNormalize, NULL},
2862         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' "
2863                 X_BINARY X_NOT_H_R ")",
2864                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
2865         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
2866                 X_BINARY X_NOT_H_R ")",
2867                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
2868         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
2869                 0, printableStringValidate, xtelephoneNumberNormalize, NULL},
2870         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
2871                 0, NULL, NULL, NULL},
2872         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
2873                 0, printablesStringValidate, xIA5StringNormalize, NULL},
2874 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2875         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
2876                 0, utcTimeValidate, xutcTimeNormalize, NULL},
2877 #endif
2878         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
2879                 0, NULL, NULL, NULL},
2880         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
2881                 0, NULL, NULL, NULL},
2882         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
2883                 0, NULL, NULL, NULL},
2884         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
2885                 0, NULL, NULL, NULL},
2886         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
2887                 0, NULL, NULL, NULL},
2888
2889         /* RFC 2307 NIS Syntaxes */
2890         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
2891                 0, nisNetgroupTripleValidate, NULL, NULL},
2892         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
2893                 0, bootParameterValidate, NULL, NULL},
2894
2895 #ifdef HAVE_TLS
2896         /* From PKIX */
2897         /* These OIDs are not published yet, but will be in the next
2898          * I-D for PKIX LDAPv3 schema as have been advanced by David
2899          * Chadwick in private mail.
2900          */
2901         {"( 1.2.826.0.1.3344810.7.1 DESC 'Serial Number and Issuer' )",
2902                 0, UTF8StringValidate, NULL, NULL},
2903 #endif
2904
2905         /* OpenLDAP Experimental Syntaxes */
2906 #ifdef SLAPD_ACI_ENABLED
2907         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
2908                 SLAP_SYNTAX_HIDE,
2909                 UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
2910                 NULL, NULL},
2911 #endif
2912
2913 #ifdef SLAPD_AUTHPASSWD
2914         /* needs updating */
2915         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
2916                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
2917 #endif
2918
2919         /* OpenLDAP Void Syntax */
2920         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
2921                 SLAP_SYNTAX_HIDE, inValidate, NULL, NULL},
2922         {NULL, 0, NULL, NULL, NULL}
2923 };
2924
2925 #ifdef HAVE_TLS
2926 char *certificateExactMatchSyntaxes[] = {
2927         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
2928         NULL
2929 };
2930 #endif
2931 char *directoryStringSyntaxes[] = {
2932         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
2933         NULL
2934 };
2935 char *integerFirstComponentMatchSyntaxes[] = {
2936         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
2937         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
2938         NULL
2939 };
2940 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
2941         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
2942         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
2943         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
2944         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
2945         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
2946         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
2947         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
2948         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
2949         NULL
2950 };
2951
2952 /*
2953  * Other matching rules in X.520 that we do not use (yet):
2954  *
2955  * 2.5.13.9             numericStringOrderingMatch
2956  * 2.5.13.25    uTCTimeMatch
2957  * 2.5.13.26    uTCTimeOrderingMatch
2958  * 2.5.13.31    directoryStringFirstComponentMatch
2959  * 2.5.13.32    wordMatch
2960  * 2.5.13.33    keywordMatch
2961  * 2.5.13.35    certificateMatch
2962  * 2.5.13.36    certificatePairExactMatch
2963  * 2.5.13.37    certificatePairMatch
2964  * 2.5.13.38    certificateListExactMatch
2965  * 2.5.13.39    certificateListMatch
2966  * 2.5.13.40    algorithmIdentifierMatch
2967  * 2.5.13.41    storedPrefixMatch
2968  * 2.5.13.42    attributeCertificateMatch
2969  * 2.5.13.43    readerAndKeyIDMatch
2970  * 2.5.13.44    attributeIntegrityMatch
2971  */
2972 static slap_mrule_defs_rec mrule_defs[] = {
2973         /*
2974          * EQUALITY matching rules must be listed after associated APPROX
2975          * matching rules.  So, we list all APPROX matching rules first.
2976          */
2977 #ifndef SLAP_NVALUES
2978         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
2979                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2980                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
2981                 NULL, NULL, directoryStringApproxMatch,
2982                 directoryStringApproxIndexer, directoryStringApproxFilter,
2983                 NULL},
2984
2985         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
2986                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
2987                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
2988                 NULL, NULL, IA5StringApproxMatch,
2989                 IA5StringApproxIndexer, IA5StringApproxFilter,
2990                 NULL},
2991 #endif
2992
2993         /*
2994          * Other matching rules
2995          */
2996         
2997         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
2998                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
2999                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3000                 NULL,
3001                 objectIdentifierNormalize, objectIdentifierMatch,
3002                 objectIdentifierIndexer, objectIdentifierFilter,
3003                 NULL},
3004
3005         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
3006                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3007                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3008                 NULL,
3009                 distinguishedNameNormalize, distinguishedNameMatch,
3010                 distinguishedNameIndexer, distinguishedNameFilter,
3011                 NULL},
3012
3013         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
3014                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3015                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3016                         directoryStringSyntaxes,
3017                 NULL,
3018                 caseIgnoreNormalize, caseIgnoreMatch,
3019                 caseIgnoreIndexer, caseIgnoreFilter,
3020                 directoryStringApproxMatchOID },
3021
3022         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
3023                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3024                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3025                 NULL, caseIgnoreNormalize, caseIgnoreOrderingMatch,
3026                 NULL, NULL, NULL},
3027
3028         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
3029                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3030                 SLAP_MR_SUBSTR, NULL,
3031                 NULL, NULL,
3032                 caseIgnoreSubstringsMatch,
3033                 caseIgnoreSubstringsIndexer, caseIgnoreSubstringsFilter,
3034                 NULL},
3035
3036         {"( 2.5.13.5 NAME 'caseExactMatch' "
3037                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3038                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3039                 NULL,
3040                 caseExactNormalize, caseExactMatch,
3041                 caseExactIndexer, caseExactFilter,
3042                 directoryStringApproxMatchOID },
3043
3044         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
3045                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3046                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3047                 NULL, caseExactNormalize, caseExactOrderingMatch,
3048                 NULL, NULL, NULL},
3049
3050         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
3051                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3052                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3053                 NULL,
3054                 NULL, caseExactSubstringsMatch,
3055                 caseExactSubstringsIndexer, caseExactSubstringsFilter,
3056                 NULL},
3057
3058         {"( 2.5.13.8 NAME 'numericStringMatch' "
3059                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3060                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3061                 NULL,
3062                 numericStringNormalize, numericStringMatch,
3063                 numericStringIndexer, numericStringFilter,
3064                 NULL},
3065
3066         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
3067                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3068                 SLAP_MR_SUBSTR, NULL,
3069                 NULL,
3070                 NULL, numericStringSubstringsMatch,
3071                 numericStringSubstringsIndexer, numericStringSubstringsFilter,
3072                 NULL},
3073
3074         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
3075                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
3076                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3077                 NULL, NULL, NULL, NULL, NULL, NULL},
3078
3079         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
3080                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3081                 SLAP_MR_SUBSTR, NULL,
3082                 NULL, NULL, NULL, NULL, NULL, NULL},
3083
3084         {"( 2.5.13.13 NAME 'booleanMatch' "
3085                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
3086                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3087                 NULL,
3088                 NULL, booleanMatch,
3089                 booleanIndexer, booleanFilter,
3090                 NULL},
3091
3092         {"( 2.5.13.14 NAME 'integerMatch' "
3093                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3094                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3095                 NULL,
3096                 integerNormalize, integerMatch,
3097                 integerIndexer, integerFilter,
3098                 NULL},
3099
3100         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
3101                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3102                 SLAP_MR_ORDERING, NULL, NULL,
3103                 integerNormalize, integerOrderingMatch,
3104                 integerIndexer, integerFilter,
3105                 NULL},
3106
3107         {"( 2.5.13.16 NAME 'bitStringMatch' "
3108                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
3109                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3110                 NULL,
3111                 NULL, bitStringMatch,
3112                 bitStringIndexer, bitStringFilter,
3113                 NULL},
3114
3115         {"( 2.5.13.17 NAME 'octetStringMatch' "
3116                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3117                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3118                 NULL, NULL,
3119                 octetStringMatch, octetStringIndexer, octetStringFilter,
3120                 NULL},
3121
3122         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
3123                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3124                 SLAP_MR_ORDERING, NULL,
3125                 NULL, NULL,
3126                 octetStringOrderingMatch, NULL, NULL,
3127                 NULL},
3128
3129         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
3130                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3131                 SLAP_MR_SUBSTR, NULL,
3132                 NULL, NULL,
3133                 octetStringSubstringsMatch, NULL, NULL,
3134                 NULL},
3135
3136         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
3137                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
3138                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3139                 NULL,
3140                 telephoneNumberNormalize, telephoneNumberMatch,
3141                 telephoneNumberIndexer, telephoneNumberFilter,
3142                 NULL},
3143
3144         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
3145                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3146                 SLAP_MR_SUBSTR, NULL,
3147                 NULL, NULL, telephoneNumberSubstringsMatch,
3148                 telephoneNumberSubstringsIndexer, telephoneNumberSubstringsFilter,
3149                 NULL},
3150
3151         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
3152                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
3153                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3154                 NULL, NULL,
3155                 NULL, NULL, NULL,
3156                 NULL},
3157
3158         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
3159                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
3160                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3161                 NULL,
3162                 uniqueMemberNormalize, uniqueMemberMatch,
3163                 NULL, NULL,
3164                 NULL},
3165
3166         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
3167                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
3168                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3169                 NULL, NULL, NULL, NULL, NULL, NULL},
3170
3171         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
3172                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3173                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3174                 NULL,
3175                 generalizedTimeNormalize, generalizedTimeMatch,
3176                 NULL, NULL,
3177                 NULL},
3178
3179         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
3180                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3181                 SLAP_MR_ORDERING, NULL,
3182                 NULL,
3183                 generalizedTimeNormalize, generalizedTimeOrderingMatch,
3184                 NULL, NULL,
3185                 NULL},
3186
3187         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
3188                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3189                 SLAP_MR_EQUALITY | SLAP_MR_EXT, integerFirstComponentMatchSyntaxes,
3190                 NULL,
3191                 integerFirstComponentNormalize, integerMatch,
3192                 NULL, NULL,
3193                 NULL},
3194
3195         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
3196                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3197                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3198                         objectIdentifierFirstComponentMatchSyntaxes,
3199                 NULL,
3200                 objectIdentifierFirstComponentNormalize, objectIdentifierMatch,
3201                 NULL, NULL,
3202                 NULL},
3203
3204 #ifndef SLAP_NVALUES
3205 #ifdef HAVE_TLS
3206         {"( 2.5.13.34 NAME 'certificateExactMatch' "
3207                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
3208                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
3209                 certificateExactConvert, NULL,
3210                 certificateExactMatch,
3211                 certificateExactIndexer, certificateExactFilter,
3212                 NULL},
3213 #endif
3214 #endif
3215
3216         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3217                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3218                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3219                 NULL,
3220                 caseExactIA5Normalize, caseExactIA5Match,
3221                 caseExactIA5Indexer, caseExactIA5Filter,
3222                 IA5StringApproxMatchOID },
3223
3224         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3225                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3226                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3227                 NULL,
3228                 NULL, caseIgnoreIA5Match,
3229                 caseIgnoreIA5Indexer, caseIgnoreIA5Filter,
3230                 IA5StringApproxMatchOID },
3231
3232         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3233                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3234                 SLAP_MR_SUBSTR, NULL,
3235                 NULL,
3236                 NULL, caseIgnoreIA5SubstringsMatch,
3237                 caseIgnoreIA5SubstringsIndexer, caseIgnoreIA5SubstringsFilter,
3238                 NULL},
3239
3240         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3241                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3242                 SLAP_MR_SUBSTR, NULL,
3243                 NULL,
3244                 NULL, caseExactIA5SubstringsMatch,
3245                 caseExactIA5SubstringsIndexer, caseExactIA5SubstringsFilter,
3246                 NULL},
3247
3248 #ifdef SLAPD_AUTHPASSWD
3249         /* needs updating */
3250         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3251                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3252                 SLAP_MR_EQUALITY, NULL,
3253                 NULL, NULL,
3254                 authPasswordMatch, NULL, NULL,
3255                 NULL},
3256 #endif
3257
3258 #ifdef SLAPD_ACI_ENABLED
3259         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
3260                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
3261                 SLAP_MR_EQUALITY, NULL,
3262                 NULL, NULL,
3263                 OpenLDAPaciMatch, NULL, NULL,
3264                 NULL},
3265 #endif
3266
3267         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3268                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3269                 SLAP_MR_EXT, NULL,
3270                 NULL,
3271                 NULL, integerBitAndMatch, NULL, NULL,
3272                 NULL},
3273
3274         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3275                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3276                 SLAP_MR_EXT, NULL,
3277                 NULL,
3278                 NULL, integerBitOrMatch, NULL, NULL,
3279                 NULL},
3280
3281         {NULL, SLAP_MR_NONE, NULL,
3282                 NULL, NULL, NULL, NULL, NULL,
3283                 NULL }
3284 };
3285
3286 int
3287 slap_schema_init( void )
3288 {
3289         int             res;
3290         int             i = 0;
3291
3292         /* we should only be called once (from main) */
3293         assert( schema_init_done == 0 );
3294
3295         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3296                 res = register_syntax( &syntax_defs[i] );
3297
3298                 if ( res ) {
3299                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3300                                  syntax_defs[i].sd_desc );
3301                         return LDAP_OTHER;
3302                 }
3303         }
3304
3305         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3306                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3307                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3308                 {
3309                         fprintf( stderr,
3310                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3311                                  mrule_defs[i].mrd_desc );
3312                         continue;
3313                 }
3314
3315                 res = register_matching_rule( &mrule_defs[i] );
3316
3317                 if ( res ) {
3318                         fprintf( stderr,
3319                                 "slap_schema_init: Error registering matching rule %s\n",
3320                                  mrule_defs[i].mrd_desc );
3321                         return LDAP_OTHER;
3322                 }
3323         }
3324
3325         res = slap_schema_load();
3326         schema_init_done = 1;
3327         return res;
3328 }
3329
3330 void
3331 schema_destroy( void )
3332 {
3333         int i;
3334         oidm_destroy();
3335         oc_destroy();
3336         at_destroy();
3337         mr_destroy();
3338         mru_destroy();
3339         syn_destroy();
3340 }