]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
Merge remote branch 'origin/mdb.master'
[openldap] / servers / slapd / schema_init.c
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2011 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 /*
18  * Syntaxes - implementation notes:
19  *
20  * Validate function(syntax, value):
21  *   Called before the other functions here to check if the value
22  *   is valid according to the syntax.
23  *
24  * Pretty function(syntax, input value, output prettified...):
25  *   If it exists, maps different notations of the same value to a
26  *   unique representation which can be stored in the directory and
27  *   possibly be passed to the Match/Indexer/Filter() functions.
28  *
29  *   E.g. DN "2.5.4.3 = foo\,bar, o = BAZ" -> "cn=foo\2Cbar,o=BAZ",
30  *   but unlike DN normalization, "BAZ" is not mapped to "baz".
31  */
32
33 /*
34  * Matching rules - implementation notes:
35  *
36  * Matching rules match an attribute value (often from the directory)
37  * against an asserted value (e.g. from a filter).
38  *
39  * Invoked with validated and commonly pretty/normalized arguments, thus
40  * a number of matching rules can simply use the octetString functions.
41  *
42  * Normalize function(...input value, output normalized...):
43  *   If it exists, maps matching values to a unique representation
44  *   which is passed to the Match/Indexer/Filter() functions.
45  *
46  *   Different matching rules can normalize values of the same syntax
47  *   differently.  E.g. caseIgnore rules normalize to lowercase,
48  *   caseExact rules do not.
49  *
50  * Match function(*output matchp, ...value, asserted value):
51  *   On success, set *matchp.  0 means match.  For ORDERING/most EQUALITY,
52  *   less/greater than 0 means value less/greater than asserted.  However:
53  *
54  *   In extensible match filters, ORDERING rules match if value<asserted.
55  *
56  *   EQUALITY rules may order values differently than ORDERING rules for
57  *   speed, since EQUALITY ordering is only used for SLAP_AT_SORTED_VAL.
58  *   Some EQUALITY rules do not order values (ITS#6722).
59  *
60  * Indexer function(...attribute values, *output keysp,...):
61  *   Generates index keys for the attribute values.  Backends can store
62  *   them in an index, a {key->entry ID set} mapping, for the attribute.
63  *
64  *   A search can look up the DN/scope and asserted values in the
65  *   indexes, if any, to narrow down the number of entires to check
66  *   against the search criteria.
67  *
68  * Filter function(...asserted value, *output keysp,...):
69  *   Generates index key(s) for the asserted value, to be looked up in
70  *   the index from the Indexer function.  *keysp is an array because
71  *   substring matching rules can generate multiple lookup keys.
72  *
73  * Index keys:
74  *   A key is usually a hash of match type, attribute value and schema
75  *   info, because one index can contain keys for many filtering types.
76  *
77  *   Some indexes instead have EQUALITY keys ordered so that if
78  *   key(val1) < key(val2), then val1 < val2 by the ORDERING rule.
79  *   That way the ORDERING rule can use the EQUALITY index.
80  *
81  * Substring indexing:
82  *   This chops the attribute values up in small chunks and indexes all
83  *   possible chunks of certain sizes.  Substring filtering looks up
84  *   SOME of the asserted value's chunks, and the caller uses the
85  *   intersection of the resulting entry ID sets.
86  *   See the index_substr_* keywords in slapd.conf(5).
87  */
88
89 #include "portable.h"
90
91 #include <stdio.h>
92 #ifdef HAVE_LIMITS_H
93 #include <limits.h>
94 #endif
95
96 #include <ac/ctype.h>
97 #include <ac/errno.h>
98 #include <ac/string.h>
99 #include <ac/socket.h>
100
101 #include "slap.h"
102 #include "../../libraries/liblber/lber-int.h" /* get ber_ptrlen() */
103
104 #include "ldap_utf8.h"
105
106 #include "lutil.h"
107 #include "lutil_hash.h"
108 #define HASH_BYTES                              LUTIL_HASH_BYTES
109 #define HASH_CONTEXT                    lutil_HASH_CTX
110 #define HASH_Init(c)                    lutil_HASHInit(c)
111 #define HASH_Update(c,buf,len)  lutil_HASHUpdate(c,buf,len)
112 #define HASH_Final(d,c)                 lutil_HASHFinal(d,c)
113
114 /* approx matching rules */
115 #define directoryStringApproxMatchOID   "1.3.6.1.4.1.4203.666.4.4"
116 #define directoryStringApproxMatch              approxMatch
117 #define directoryStringApproxIndexer    approxIndexer
118 #define directoryStringApproxFilter             approxFilter
119 #define IA5StringApproxMatchOID                 "1.3.6.1.4.1.4203.666.4.5"
120 #define IA5StringApproxMatch                    approxMatch
121 #define IA5StringApproxIndexer                  approxIndexer
122 #define IA5StringApproxFilter                   approxFilter
123
124 /* Change Sequence Number (CSN) - much of this will change */
125 #define csnMatch                                octetStringMatch
126 #define csnOrderingMatch                octetStringOrderingMatch
127 #define csnIndexer                              generalizedTimeIndexer
128 #define csnFilter                               generalizedTimeFilter
129
130 #define authzMatch                              octetStringMatch
131
132 /* X.509 PMI ldapSyntaxes */
133 /* FIXME: need to create temporary OIDs under OpenLDAP's arc;
134  * these are currently hijacked
135  *
136  *      1.3.6.1.4.1.4203.666            OpenLDAP
137  *      1.3.6.1.4.1.4203.666.11         self-contained works
138  *      1.3.6.1.4.1.4203.666.11.10      X.509 PMI
139  *      1.3.6.1.4.1.4203.666.11.10.2    X.509 PMI ldapSyntaxes
140  *      1.3.6.1.4.1.4203.666.11.10.2.1  AttributeCertificate (supported)
141  *      1.3.6.1.4.1.4203.666.11.10.2.2  AttributeCertificateExactAssertion (supported)
142  *      1.3.6.1.4.1.4203.666.11.10.2.3  AttributeCertificateAssertion (not supported)
143  *      1.3.6.1.4.1.4203.666.11.10.2.4  AttCertPath (X-SUBST'ed right now in pmi.schema)
144  *      1.3.6.1.4.1.4203.666.11.10.2.5  PolicySyntax (X-SUBST'ed right now in pmi.schema)
145  *      1.3.6.1.4.1.4203.666.11.10.2.6  RoleSyntax (X-SUBST'ed right now in pmi.schema)
146  */
147 #if 0 /* from <draft-ietf-pkix-ldap-schema-02.txt> (expired) */
148 #define attributeCertificateSyntaxOID                   "1.2.826.0.1.3344810.7.5"
149 #define attributeCertificateExactAssertionSyntaxOID     "1.2.826.0.1.3344810.7.6"
150 #define attributeCertificateAssertionSyntaxOID          "1.2.826.0.1.3344810.7.7"
151 #else /* from OpenLDAP's experimental oid arc */
152 #define X509_PMI_SyntaxOID                              "1.3.6.1.4.1.4203.666.11.10.2"
153 #define attributeCertificateSyntaxOID                   X509_PMI_SyntaxOID ".1"
154 #define attributeCertificateExactAssertionSyntaxOID     X509_PMI_SyntaxOID ".2"
155 #define attributeCertificateAssertionSyntaxOID          X509_PMI_SyntaxOID ".3"
156 #endif
157
158 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
159 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
160 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
161 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
162
163 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
164 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
165         SLAP_INDEX_INTLEN_DEFAULT );
166
167 ldap_pvt_thread_mutex_t ad_index_mutex;
168 ldap_pvt_thread_mutex_t ad_undef_mutex;
169 ldap_pvt_thread_mutex_t oc_undef_mutex;
170
171 static int
172 generalizedTimeValidate(
173         Syntax *syntax,
174         struct berval *in );
175
176 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
177 static int
178 utcTimeValidate(
179         Syntax *syntax,
180         struct berval *in );
181 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
182
183 static int
184 inValidate(
185         Syntax *syntax,
186         struct berval *in )
187 {
188         /* no value allowed */
189         return LDAP_INVALID_SYNTAX;
190 }
191
192 static int
193 blobValidate(
194         Syntax *syntax,
195         struct berval *in )
196 {
197         /* any value allowed */
198         return LDAP_SUCCESS;
199 }
200
201 #define berValidate blobValidate
202
203 static int
204 sequenceValidate(
205         Syntax *syntax,
206         struct berval *in )
207 {
208         if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
209         if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
210
211         return LDAP_SUCCESS;
212 }
213
214 /* X.509 related stuff */
215
216 enum {
217         SLAP_X509_V1            = 0,
218         SLAP_X509_V2            = 1,
219         SLAP_X509_V3            = 2
220 };
221
222 enum {
223         SLAP_TAG_UTCTIME                = 0x17U,
224         SLAP_TAG_GENERALIZEDTIME        = 0x18U
225 };
226
227
228 #define SLAP_X509_OPTION        (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
229
230 enum {
231         SLAP_X509_OPT_C_VERSION         = SLAP_X509_OPTION + 0,
232         SLAP_X509_OPT_C_ISSUERUNIQUEID  = LBER_CLASS_CONTEXT + 1,
233         SLAP_X509_OPT_C_SUBJECTUNIQUEID = LBER_CLASS_CONTEXT + 2,
234         SLAP_X509_OPT_C_EXTENSIONS      = SLAP_X509_OPTION + 3
235 };
236
237 enum {
238         SLAP_X509_OPT_CL_CRLEXTENSIONS  = SLAP_X509_OPTION + 0
239 };
240
241 /*
242 GeneralName ::= CHOICE {
243   otherName                 [0] INSTANCE OF OTHER-NAME,
244   rfc822Name                [1] IA5String,
245   dNSName                   [2] IA5String,
246   x400Address               [3] ORAddress,
247   directoryName             [4] Name,
248   ediPartyName              [5] EDIPartyName,
249   uniformResourceIdentifier [6] IA5String,
250   iPAddress                 [7] OCTET STRING,
251   registeredID              [8] OBJECT IDENTIFIER }
252 */
253 enum {
254         SLAP_X509_GN_OTHERNAME          = SLAP_X509_OPTION + 0,
255         SLAP_X509_GN_RFC822NAME         = SLAP_X509_OPTION + 1,
256         SLAP_X509_GN_DNSNAME            = SLAP_X509_OPTION + 2,
257         SLAP_X509_GN_X400ADDRESS        = SLAP_X509_OPTION + 3,
258         SLAP_X509_GN_DIRECTORYNAME      = SLAP_X509_OPTION + 4,
259         SLAP_X509_GN_EDIPARTYNAME       = SLAP_X509_OPTION + 5,
260         SLAP_X509_GN_URI                = SLAP_X509_OPTION + 6,
261         SLAP_X509_GN_IPADDRESS          = SLAP_X509_OPTION + 7,
262         SLAP_X509_GN_REGISTEREDID       = SLAP_X509_OPTION + 8
263 };
264
265 /* X.509 PMI related stuff */
266 enum {
267         SLAP_X509AC_V1          = 0,
268         SLAP_X509AC_V2          = 1
269 };
270
271 enum {
272         SLAP_X509AC_ISSUER      = SLAP_X509_OPTION + 0
273 };
274
275 /* X.509 certificate validation */
276 static int
277 certificateValidate( Syntax *syntax, struct berval *in )
278 {
279         BerElementBuffer berbuf;
280         BerElement *ber = (BerElement *)&berbuf;
281         ber_tag_t tag;
282         ber_len_t len;
283         ber_int_t version = SLAP_X509_V1;
284
285         ber_init2( ber, in, LBER_USE_DER );
286         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
287         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
288         tag = ber_skip_tag( ber, &len );        /* Sequence */
289         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
290         tag = ber_peek_tag( ber, &len );
291         /* Optional version */
292         if ( tag == SLAP_X509_OPT_C_VERSION ) {
293                 tag = ber_skip_tag( ber, &len );
294                 tag = ber_get_int( ber, &version );
295                 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
296         }
297         /* NOTE: don't try to parse Serial, because it might be longer
298          * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
299         tag = ber_skip_tag( ber, &len );        /* Serial */
300         if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
301         ber_skip_data( ber, len );
302         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
303         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
304         ber_skip_data( ber, len );
305         tag = ber_skip_tag( ber, &len );        /* Issuer DN */
306         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
307         ber_skip_data( ber, len );
308         tag = ber_skip_tag( ber, &len );        /* Validity */
309         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
310         ber_skip_data( ber, len );
311         tag = ber_skip_tag( ber, &len );        /* Subject DN */
312         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
313         ber_skip_data( ber, len );
314         tag = ber_skip_tag( ber, &len );        /* Subject PublicKeyInfo */
315         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
316         ber_skip_data( ber, len );
317         tag = ber_skip_tag( ber, &len );
318         if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) {  /* issuerUniqueID */
319                 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
320                 ber_skip_data( ber, len );
321                 tag = ber_skip_tag( ber, &len );
322         }
323         if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) { /* subjectUniqueID */
324                 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
325                 ber_skip_data( ber, len );
326                 tag = ber_skip_tag( ber, &len );
327         }
328         if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) {      /* Extensions */
329                 if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
330                 tag = ber_skip_tag( ber, &len );
331                 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
332                 ber_skip_data( ber, len );
333                 tag = ber_skip_tag( ber, &len );
334         }
335         /* signatureAlgorithm */
336         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
337         ber_skip_data( ber, len );
338         tag = ber_skip_tag( ber, &len );
339         /* Signature */
340         if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; 
341         ber_skip_data( ber, len );
342         tag = ber_skip_tag( ber, &len );
343         /* Must be at end now */
344         if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
345         return LDAP_SUCCESS;
346 }
347
348 /* X.509 certificate list validation */
349 static int
350 checkTime( struct berval *in, struct berval *out );
351
352 static int
353 certificateListValidate( Syntax *syntax, struct berval *in )
354 {
355         BerElementBuffer berbuf;
356         BerElement *ber = (BerElement *)&berbuf;
357         ber_tag_t tag;
358         ber_len_t len, wrapper_len;
359         char *wrapper_start;
360         int wrapper_ok = 0;
361         ber_int_t version = SLAP_X509_V1;
362         struct berval bvdn, bvtu;
363
364         ber_init2( ber, in, LBER_USE_DER );
365         tag = ber_skip_tag( ber, &wrapper_len );        /* Signed wrapper */
366         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
367         wrapper_start = ber->ber_ptr;
368         tag = ber_skip_tag( ber, &len );        /* Sequence */
369         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
370         tag = ber_peek_tag( ber, &len );
371         /* Optional version */
372         if ( tag == LBER_INTEGER ) {
373                 tag = ber_get_int( ber, &version );
374                 assert( tag == LBER_INTEGER );
375                 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
376         }
377         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
378         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
379         ber_skip_data( ber, len );
380         tag = ber_peek_tag( ber, &len );        /* Issuer DN */
381         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
382         len = ber_ptrlen( ber );
383         bvdn.bv_val = in->bv_val + len;
384         bvdn.bv_len = in->bv_len - len;
385         tag = ber_skip_tag( ber, &len );
386         ber_skip_data( ber, len );
387         tag = ber_skip_tag( ber, &len );        /* thisUpdate */
388         /* Time is a CHOICE { UTCTime, GeneralizedTime } */
389         if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
390         bvtu.bv_val = (char *)ber->ber_ptr;
391         bvtu.bv_len = len;
392         ber_skip_data( ber, len );
393         /* Optional nextUpdate */
394         tag = ber_skip_tag( ber, &len );
395         if ( tag == SLAP_TAG_UTCTIME || tag == SLAP_TAG_GENERALIZEDTIME ) {
396                 ber_skip_data( ber, len );
397                 tag = ber_skip_tag( ber, &len );
398         }
399         /* revokedCertificates - Sequence of Sequence, Optional */
400         if ( tag == LBER_SEQUENCE ) {
401                 ber_len_t seqlen;
402                 ber_tag_t stag;
403                 stag = ber_peek_tag( ber, &seqlen );
404                 if ( stag == LBER_SEQUENCE || !len ) {
405                         /* RFC5280 requires non-empty, but X.509(2005) allows empty. */
406                         if ( len )
407                                 ber_skip_data( ber, len );
408                         tag = ber_skip_tag( ber, &len );
409                 }
410         }
411         /* Optional Extensions - Sequence of Sequence */
412         if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
413                 ber_len_t seqlen;
414                 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
415                 tag = ber_peek_tag( ber, &seqlen );
416                 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
417                 ber_skip_data( ber, len );
418                 tag = ber_skip_tag( ber, &len );
419         }
420         /* signatureAlgorithm */
421         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
422         ber_skip_data( ber, len );
423         tag = ber_skip_tag( ber, &len );
424         /* Signature */
425         if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; 
426         ber_skip_data( ber, len );
427         if ( ber->ber_ptr == wrapper_start + wrapper_len ) wrapper_ok = 1;
428         tag = ber_skip_tag( ber, &len );
429         /* Must be at end now */
430         /* NOTE: OpenSSL tolerates CL with garbage past the end */
431         if ( len || tag != LBER_DEFAULT ) {
432                 struct berval issuer_dn = BER_BVNULL, thisUpdate;
433                 char tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
434                 int rc;
435
436                 if ( ! wrapper_ok ) {
437                         return LDAP_INVALID_SYNTAX;
438                 }
439
440                 rc = dnX509normalize( &bvdn, &issuer_dn );
441                 if ( rc != LDAP_SUCCESS ) {
442                         rc = LDAP_INVALID_SYNTAX;
443                         goto done;
444                 }
445
446                 thisUpdate.bv_val = tubuf;
447                 thisUpdate.bv_len = sizeof(tubuf); 
448                 if ( checkTime( &bvtu, &thisUpdate ) ) {
449                         rc = LDAP_INVALID_SYNTAX;
450                         goto done;
451                 }
452
453                 Debug( LDAP_DEBUG_ANY,
454                         "certificateListValidate issuer=\"%s\", thisUpdate=%s: extra cruft past end of certificateList\n",
455                         issuer_dn.bv_val, thisUpdate.bv_val, 0 );
456
457 done:;
458                 if ( ! BER_BVISNULL( &issuer_dn ) ) {
459                         ber_memfree( issuer_dn.bv_val );
460                 }
461
462                 return rc;
463         }
464
465         return LDAP_SUCCESS;
466 }
467
468 /* X.509 PMI Attribute Certificate Validate */
469 static int
470 attributeCertificateValidate( Syntax *syntax, struct berval *in )
471 {
472         BerElementBuffer berbuf;
473         BerElement *ber = (BerElement *)&berbuf;
474         ber_tag_t tag;
475         ber_len_t len;
476         ber_int_t version;
477         int cont = 0;
478
479         ber_init2( ber, in, LBER_USE_DER );
480         
481         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
482         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
483
484         tag = ber_skip_tag( ber, &len );        /* Sequence */
485         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
486
487         tag = ber_peek_tag( ber, &len );        /* Version */
488         if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
489         tag = ber_get_int( ber, &version );     /* X.509 only allows v2 */
490         if ( version != SLAP_X509AC_V2 ) return LDAP_INVALID_SYNTAX;
491
492         tag = ber_skip_tag( ber, &len );        /* Holder */
493         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
494         ber_skip_data( ber, len );
495
496         tag = ber_skip_tag( ber, &len );        /* Issuer */
497         if ( tag != SLAP_X509AC_ISSUER ) return LDAP_INVALID_SYNTAX;
498         ber_skip_data( ber, len );
499
500         tag = ber_skip_tag( ber, &len );        /* Signature */
501         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
502         ber_skip_data( ber, len );
503
504         tag = ber_skip_tag( ber, &len );        /* Serial number */
505         if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
506         ber_skip_data( ber, len );
507
508         tag = ber_skip_tag( ber, &len );        /* AttCertValidityPeriod */
509         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
510         ber_skip_data( ber, len );
511
512         tag = ber_skip_tag( ber, &len );        /* Attributes */
513         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
514         ber_skip_data( ber, len );
515
516         tag = ber_peek_tag( ber, &len );
517
518         if ( tag == LBER_BITSTRING ) {  /* issuerUniqueID */
519                 tag = ber_skip_tag( ber, &len );
520                 ber_skip_data( ber, len );
521                 tag = ber_peek_tag( ber, &len );
522         }
523
524         if ( tag == LBER_SEQUENCE ) {   /* extensions or signatureAlgorithm */
525                 tag = ber_skip_tag( ber, &len );
526                 ber_skip_data( ber, len );
527                 cont++;
528                 tag = ber_peek_tag( ber, &len );
529         }
530
531         if ( tag == LBER_SEQUENCE ) {   /* signatureAlgorithm */
532                 tag = ber_skip_tag( ber, &len );
533                 ber_skip_data( ber, len );
534                 cont++;
535                 tag = ber_peek_tag( ber, &len );
536         }
537
538         if ( tag == LBER_BITSTRING ) {  /* Signature */
539                 tag = ber_skip_tag( ber, &len );
540                 ber_skip_data( ber, len );
541                 cont++;
542                 tag = ber_peek_tag( ber, &len );
543         }
544
545         /* Must be at end now */
546         if ( len != 0 || tag != LBER_DEFAULT || cont < 2 ) return LDAP_INVALID_SYNTAX;
547
548         return LDAP_SUCCESS;
549 }
550
551 int
552 octetStringMatch(
553         int *matchp,
554         slap_mask_t flags,
555         Syntax *syntax,
556         MatchingRule *mr,
557         struct berval *value,
558         void *assertedValue )
559 {
560         struct berval *asserted = (struct berval *) assertedValue;
561         ber_slen_t d = (ber_slen_t) value->bv_len - (ber_slen_t) asserted->bv_len;
562
563         /* For speed, order first by length, then by contents */
564         *matchp = d ? (sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1)
565                 : memcmp( value->bv_val, asserted->bv_val, value->bv_len );
566
567         return LDAP_SUCCESS;
568 }
569
570 int
571 octetStringOrderingMatch(
572         int *matchp,
573         slap_mask_t flags,
574         Syntax *syntax,
575         MatchingRule *mr,
576         struct berval *value,
577         void *assertedValue )
578 {
579         struct berval *asserted = (struct berval *) assertedValue;
580         ber_len_t v_len  = value->bv_len;
581         ber_len_t av_len = asserted->bv_len;
582
583         int match = memcmp( value->bv_val, asserted->bv_val,
584                 (v_len < av_len ? v_len : av_len) );
585
586         if( match == 0 )
587                 match = sizeof(v_len) == sizeof(int)
588                         ? (int) v_len - (int) av_len
589                         : v_len < av_len ? -1 : v_len > av_len;
590
591         /* If used in extensible match filter, match if value < asserted */
592         if ( flags & SLAP_MR_EXT )
593                 match = (match >= 0);
594
595         *matchp = match;
596         return LDAP_SUCCESS;
597 }
598
599 /* Initialize HASHcontext from match type and schema info */
600 static void
601 hashPreset(
602         HASH_CONTEXT *HASHcontext,
603         struct berval *prefix,
604         char pre,
605         Syntax *syntax,
606         MatchingRule *mr)
607 {
608         HASH_Init(HASHcontext);
609         if(prefix && prefix->bv_len > 0) {
610                 HASH_Update(HASHcontext,
611                         (unsigned char *)prefix->bv_val, prefix->bv_len);
612         }
613         if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
614         HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
615         HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
616         return;
617 }
618
619 /* Set HASHdigest from HASHcontext and value:len */
620 static void
621 hashIter(
622         HASH_CONTEXT *HASHcontext,
623         unsigned char *HASHdigest,
624         unsigned char *value,
625         int len)
626 {
627         HASH_CONTEXT ctx = *HASHcontext;
628         HASH_Update( &ctx, value, len );
629         HASH_Final( HASHdigest, &ctx );
630 }
631
632 /* Index generation function: Attribute values -> index hash keys */
633 int octetStringIndexer(
634         slap_mask_t use,
635         slap_mask_t flags,
636         Syntax *syntax,
637         MatchingRule *mr,
638         struct berval *prefix,
639         BerVarray values,
640         BerVarray *keysp,
641         void *ctx )
642 {
643         int i;
644         size_t slen, mlen;
645         BerVarray keys;
646         HASH_CONTEXT HASHcontext;
647         unsigned char HASHdigest[HASH_BYTES];
648         struct berval digest;
649         digest.bv_val = (char *)HASHdigest;
650         digest.bv_len = sizeof(HASHdigest);
651
652         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
653                 /* just count them */
654         }
655
656         /* we should have at least one value at this point */
657         assert( i > 0 );
658
659         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
660
661         slen = syntax->ssyn_oidlen;
662         mlen = mr->smr_oidlen;
663
664         hashPreset( &HASHcontext, prefix, 0, syntax, mr);
665         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
666                 hashIter( &HASHcontext, HASHdigest,
667                         (unsigned char *)values[i].bv_val, values[i].bv_len );
668                 ber_dupbv_x( &keys[i], &digest, ctx );
669         }
670
671         BER_BVZERO( &keys[i] );
672
673         *keysp = keys;
674
675         return LDAP_SUCCESS;
676 }
677
678 /* Index generation function: Asserted value -> index hash key */
679 int octetStringFilter(
680         slap_mask_t use,
681         slap_mask_t flags,
682         Syntax *syntax,
683         MatchingRule *mr,
684         struct berval *prefix,
685         void * assertedValue,
686         BerVarray *keysp,
687         void *ctx )
688 {
689         size_t slen, mlen;
690         BerVarray keys;
691         HASH_CONTEXT HASHcontext;
692         unsigned char HASHdigest[HASH_BYTES];
693         struct berval *value = (struct berval *) assertedValue;
694         struct berval digest;
695         digest.bv_val = (char *)HASHdigest;
696         digest.bv_len = sizeof(HASHdigest);
697
698         slen = syntax->ssyn_oidlen;
699         mlen = mr->smr_oidlen;
700
701         keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
702
703         hashPreset( &HASHcontext, prefix, 0, syntax, mr );
704         hashIter( &HASHcontext, HASHdigest,
705                 (unsigned char *)value->bv_val, value->bv_len );
706
707         ber_dupbv_x( keys, &digest, ctx );
708         BER_BVZERO( &keys[1] );
709
710         *keysp = keys;
711
712         return LDAP_SUCCESS;
713 }
714
715 static int
716 octetStringSubstringsMatch(
717         int *matchp,
718         slap_mask_t flags,
719         Syntax *syntax,
720         MatchingRule *mr,
721         struct berval *value,
722         void *assertedValue )
723 {
724         int match = 0;
725         SubstringsAssertion *sub = assertedValue;
726         struct berval left = *value;
727         int i;
728         ber_len_t inlen = 0;
729
730         /* Add up asserted input length */
731         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
732                 inlen += sub->sa_initial.bv_len;
733         }
734         if ( sub->sa_any ) {
735                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
736                         inlen += sub->sa_any[i].bv_len;
737                 }
738         }
739         if ( !BER_BVISNULL( &sub->sa_final ) ) {
740                 inlen += sub->sa_final.bv_len;
741         }
742
743         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
744                 if ( inlen > left.bv_len ) {
745                         match = 1;
746                         goto done;
747                 }
748
749                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
750                         sub->sa_initial.bv_len );
751
752                 if ( match != 0 ) {
753                         goto done;
754                 }
755
756                 left.bv_val += sub->sa_initial.bv_len;
757                 left.bv_len -= sub->sa_initial.bv_len;
758                 inlen -= sub->sa_initial.bv_len;
759         }
760
761         if ( !BER_BVISNULL( &sub->sa_final ) ) {
762                 if ( inlen > left.bv_len ) {
763                         match = 1;
764                         goto done;
765                 }
766
767                 match = memcmp( sub->sa_final.bv_val,
768                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
769                         sub->sa_final.bv_len );
770
771                 if ( match != 0 ) {
772                         goto done;
773                 }
774
775                 left.bv_len -= sub->sa_final.bv_len;
776                 inlen -= sub->sa_final.bv_len;
777         }
778
779         if ( sub->sa_any ) {
780                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
781                         ber_len_t idx;
782                         char *p;
783
784 retry:
785                         if ( inlen > left.bv_len ) {
786                                 /* not enough length */
787                                 match = 1;
788                                 goto done;
789                         }
790
791                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
792                                 continue;
793                         }
794
795                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
796
797                         if( p == NULL ) {
798                                 match = 1;
799                                 goto done;
800                         }
801
802                         idx = p - left.bv_val;
803
804                         if ( idx >= left.bv_len ) {
805                                 /* this shouldn't happen */
806                                 return LDAP_OTHER;
807                         }
808
809                         left.bv_val = p;
810                         left.bv_len -= idx;
811
812                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
813                                 /* not enough left */
814                                 match = 1;
815                                 goto done;
816                         }
817
818                         match = memcmp( left.bv_val,
819                                 sub->sa_any[i].bv_val,
820                                 sub->sa_any[i].bv_len );
821
822                         if ( match != 0 ) {
823                                 left.bv_val++;
824                                 left.bv_len--;
825                                 goto retry;
826                         }
827
828                         left.bv_val += sub->sa_any[i].bv_len;
829                         left.bv_len -= sub->sa_any[i].bv_len;
830                         inlen -= sub->sa_any[i].bv_len;
831                 }
832         }
833
834 done:
835         *matchp = match;
836         return LDAP_SUCCESS;
837 }
838
839 /* Substring index generation function: Attribute values -> index hash keys */
840 static int
841 octetStringSubstringsIndexer(
842         slap_mask_t use,
843         slap_mask_t flags,
844         Syntax *syntax,
845         MatchingRule *mr,
846         struct berval *prefix,
847         BerVarray values,
848         BerVarray *keysp,
849         void *ctx )
850 {
851         ber_len_t i, nkeys;
852         size_t slen, mlen;
853         BerVarray keys;
854
855         HASH_CONTEXT HCany, HCini, HCfin;
856         unsigned char HASHdigest[HASH_BYTES];
857         struct berval digest;
858         digest.bv_val = (char *)HASHdigest;
859         digest.bv_len = sizeof(HASHdigest);
860
861         nkeys = 0;
862
863         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
864                 /* count number of indices to generate */
865                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
866                         if( values[i].bv_len >= index_substr_if_maxlen ) {
867                                 nkeys += index_substr_if_maxlen -
868                                         (index_substr_if_minlen - 1);
869                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
870                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
871                         }
872                 }
873
874                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
875                         if( values[i].bv_len >= index_substr_any_len ) {
876                                 nkeys += values[i].bv_len - (index_substr_any_len - 1);
877                         }
878                 }
879
880                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
881                         if( values[i].bv_len >= index_substr_if_maxlen ) {
882                                 nkeys += index_substr_if_maxlen -
883                                         (index_substr_if_minlen - 1);
884                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
885                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
886                         }
887                 }
888         }
889
890         if( nkeys == 0 ) {
891                 /* no keys to generate */
892                 *keysp = NULL;
893                 return LDAP_SUCCESS;
894         }
895
896         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
897
898         slen = syntax->ssyn_oidlen;
899         mlen = mr->smr_oidlen;
900
901         if ( flags & SLAP_INDEX_SUBSTR_ANY )
902                 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
903         if( flags & SLAP_INDEX_SUBSTR_INITIAL )
904                 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
905         if( flags & SLAP_INDEX_SUBSTR_FINAL )
906                 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
907
908         nkeys = 0;
909         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
910                 ber_len_t j,max;
911
912                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
913                         ( values[i].bv_len >= index_substr_any_len ) )
914                 {
915                         max = values[i].bv_len - (index_substr_any_len - 1);
916
917                         for( j=0; j<max; j++ ) {
918                                 hashIter( &HCany, HASHdigest,
919                                         (unsigned char *)&values[i].bv_val[j],
920                                         index_substr_any_len );
921                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
922                         }
923                 }
924
925                 /* skip if too short */ 
926                 if( values[i].bv_len < index_substr_if_minlen ) continue;
927
928                 max = index_substr_if_maxlen < values[i].bv_len
929                         ? index_substr_if_maxlen : values[i].bv_len;
930
931                 for( j=index_substr_if_minlen; j<=max; j++ ) {
932
933                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
934                                 hashIter( &HCini, HASHdigest,
935                                         (unsigned char *)values[i].bv_val, j );
936                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
937                         }
938
939                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
940                                 hashIter( &HCfin, HASHdigest,
941                                         (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
942                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
943                         }
944
945                 }
946         }
947
948         if( nkeys > 0 ) {
949                 BER_BVZERO( &keys[nkeys] );
950                 *keysp = keys;
951         } else {
952                 ch_free( keys );
953                 *keysp = NULL;
954         }
955
956         return LDAP_SUCCESS;
957 }
958
959 /* Substring index generation function: Assertion value -> index hash keys */
960 static int
961 octetStringSubstringsFilter (
962         slap_mask_t use,
963         slap_mask_t flags,
964         Syntax *syntax,
965         MatchingRule *mr,
966         struct berval *prefix,
967         void * assertedValue,
968         BerVarray *keysp,
969         void *ctx)
970 {
971         SubstringsAssertion *sa;
972         char pre;
973         ber_len_t nkeys = 0;
974         size_t slen, mlen, klen;
975         BerVarray keys;
976         HASH_CONTEXT HASHcontext;
977         unsigned char HASHdigest[HASH_BYTES];
978         struct berval *value;
979         struct berval digest;
980
981         sa = (SubstringsAssertion *) assertedValue;
982
983         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
984                 !BER_BVISNULL( &sa->sa_initial ) &&
985                 sa->sa_initial.bv_len >= index_substr_if_minlen )
986         {
987                 nkeys++;
988                 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
989                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
990                 {
991                         nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
992                 }
993         }
994
995         if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
996                 ber_len_t i;
997                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
998                         if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
999                                 /* don't bother accounting with stepping */
1000                                 nkeys += sa->sa_any[i].bv_len -
1001                                         ( index_substr_any_len - 1 );
1002                         }
1003                 }
1004         }
1005
1006         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1007                 !BER_BVISNULL( &sa->sa_final ) &&
1008                 sa->sa_final.bv_len >= index_substr_if_minlen )
1009         {
1010                 nkeys++;
1011                 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
1012                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
1013                 {
1014                         nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1015                 }
1016         }
1017
1018         if( nkeys == 0 ) {
1019                 *keysp = NULL;
1020                 return LDAP_SUCCESS;
1021         }
1022
1023         digest.bv_val = (char *)HASHdigest;
1024         digest.bv_len = sizeof(HASHdigest);
1025
1026         slen = syntax->ssyn_oidlen;
1027         mlen = mr->smr_oidlen;
1028
1029         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
1030         nkeys = 0;
1031
1032         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1033                 !BER_BVISNULL( &sa->sa_initial ) &&
1034                 sa->sa_initial.bv_len >= index_substr_if_minlen )
1035         {
1036                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1037                 value = &sa->sa_initial;
1038
1039                 klen = index_substr_if_maxlen < value->bv_len
1040                         ? index_substr_if_maxlen : value->bv_len;
1041
1042                 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1043                 hashIter( &HASHcontext, HASHdigest,
1044                         (unsigned char *)value->bv_val, klen );
1045                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1046
1047                 /* If initial is too long and we have subany indexed, use it
1048                  * to match the excess...
1049                  */
1050                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1051                 {
1052                         ber_len_t j;
1053                         pre = SLAP_INDEX_SUBSTR_PREFIX;
1054                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1055                         for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
1056                         {
1057                                 hashIter( &HASHcontext, HASHdigest,
1058                                         (unsigned char *)&value->bv_val[j], index_substr_any_len );
1059                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1060                         }
1061                 }
1062         }
1063
1064         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1065                 ber_len_t i, j;
1066                 pre = SLAP_INDEX_SUBSTR_PREFIX;
1067                 klen = index_substr_any_len;
1068
1069                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1070                         if( sa->sa_any[i].bv_len < index_substr_any_len ) {
1071                                 continue;
1072                         }
1073
1074                         value = &sa->sa_any[i];
1075
1076                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1077                         for(j=0;
1078                                 j <= value->bv_len - index_substr_any_len;
1079                                 j += index_substr_any_step )
1080                         {
1081                                 hashIter( &HASHcontext, HASHdigest,
1082                                         (unsigned char *)&value->bv_val[j], klen ); 
1083                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1084                         }
1085                 }
1086         }
1087
1088         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1089                 !BER_BVISNULL( &sa->sa_final ) &&
1090                 sa->sa_final.bv_len >= index_substr_if_minlen )
1091         {
1092                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1093                 value = &sa->sa_final;
1094
1095                 klen = index_substr_if_maxlen < value->bv_len
1096                         ? index_substr_if_maxlen : value->bv_len;
1097
1098                 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1099                 hashIter( &HASHcontext, HASHdigest,
1100                         (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
1101                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1102
1103                 /* If final is too long and we have subany indexed, use it
1104                  * to match the excess...
1105                  */
1106                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1107                 {
1108                         ber_len_t j;
1109                         pre = SLAP_INDEX_SUBSTR_PREFIX;
1110                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1111                         for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
1112                         {
1113                                 hashIter( &HASHcontext, HASHdigest,
1114                                         (unsigned char *)&value->bv_val[j], index_substr_any_len );
1115                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1116                         }
1117                 }
1118         }
1119
1120         if( nkeys > 0 ) {
1121                 BER_BVZERO( &keys[nkeys] );
1122                 *keysp = keys;
1123         } else {
1124                 ch_free( keys );
1125                 *keysp = NULL;
1126         }
1127
1128         return LDAP_SUCCESS;
1129 }
1130
1131 static int
1132 bitStringValidate(
1133         Syntax *syntax,
1134         struct berval *in )
1135 {
1136         ber_len_t i;
1137
1138         /* very unforgiving validation, requires no normalization
1139          * before simplistic matching
1140          */
1141         if( in->bv_len < 3 ) {
1142                 return LDAP_INVALID_SYNTAX;
1143         }
1144
1145         /* RFC 4517 Section 3.3.2 Bit String:
1146          *      BitString    = SQUOTE *binary-digit SQUOTE "B"
1147          *      binary-digit = "0" / "1"
1148          *
1149          * where SQUOTE [RFC4512] is
1150          *      SQUOTE  = %x27 ; single quote ("'")
1151          *
1152          * Example: '0101111101'B
1153          */
1154         
1155         if( in->bv_val[0] != '\'' ||
1156                 in->bv_val[in->bv_len - 2] != '\'' ||
1157                 in->bv_val[in->bv_len - 1] != 'B' )
1158         {
1159                 return LDAP_INVALID_SYNTAX;
1160         }
1161
1162         for( i = in->bv_len - 3; i > 0; i-- ) {
1163                 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
1164                         return LDAP_INVALID_SYNTAX;
1165                 }
1166         }
1167
1168         return LDAP_SUCCESS;
1169 }
1170
1171 /*
1172  * Syntaxes from RFC 4517
1173  *
1174
1175 3.3.2.  Bit String
1176
1177    A value of the Bit String syntax is a sequence of binary digits.  The
1178    LDAP-specific encoding of a value of this syntax is defined by the
1179    following ABNF:
1180
1181       BitString    = SQUOTE *binary-digit SQUOTE "B"
1182
1183       binary-digit = "0" / "1"
1184
1185    The <SQUOTE> rule is defined in [MODELS].
1186
1187       Example:
1188          '0101111101'B
1189
1190    The LDAP definition for the Bit String syntax is:
1191
1192       ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
1193
1194    This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
1195
1196    ...
1197
1198 3.3.21.  Name and Optional UID
1199
1200    A value of the Name and Optional UID syntax is the distinguished name
1201    [MODELS] of an entity optionally accompanied by a unique identifier
1202    that serves to differentiate the entity from others with an identical
1203    distinguished name.
1204
1205    The LDAP-specific encoding of a value of this syntax is defined by
1206    the following ABNF:
1207
1208        NameAndOptionalUID = distinguishedName [ SHARP BitString ]
1209
1210    The <BitString> rule is defined in Section 3.3.2.  The
1211    <distinguishedName> rule is defined in [LDAPDN].  The <SHARP> rule is
1212    defined in [MODELS].
1213
1214    Note that although the '#' character may occur in the string
1215    representation of a distinguished name, no additional escaping of
1216    this character is performed when a <distinguishedName> is encoded in
1217    a <NameAndOptionalUID>.
1218
1219       Example:
1220          1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
1221
1222    The LDAP definition for the Name and Optional UID syntax is:
1223
1224       ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
1225
1226    This syntax corresponds to the NameAndOptionalUID ASN.1 type from
1227    [X.520].
1228
1229  *
1230  * RFC 4512 says:
1231  *
1232
1233 1.4. Common ABNF Productions
1234
1235   ...
1236       SHARP   = %x23 ; octothorpe (or sharp sign) ("#")
1237   ...
1238       SQUOTE  = %x27 ; single quote ("'")
1239   ...
1240       
1241  *
1242  * Note:
1243  * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
1244  * be escaped except when at the beginning of a value, the
1245  * definition of Name and Optional UID appears to be flawed,
1246  * because there is no clear means to determine whether the
1247  * UID part is present or not.
1248  *
1249  * Example:
1250  *
1251  *      cn=Someone,dc=example,dc=com#'1'B
1252  *
1253  * could be either a NameAndOptionalUID with trailing UID, i.e.
1254  *
1255  *      DN = "cn=Someone,dc=example,dc=com"
1256  *      UID = "'1'B"
1257  * 
1258  * or a NameAndOptionalUID with no trailing UID, and the AVA
1259  * in the last RDN made of
1260  *
1261  *      attributeType = dc 
1262  *      attributeValue = com#'1'B
1263  *
1264  * in fact "com#'1'B" is a valid IA5 string.
1265  *
1266  * As a consequence, current slapd code takes the presence of
1267  * #<valid BitString> at the end of the string representation
1268  * of a NameAndOptionalUID to mean this is indeed a BitString.
1269  * This is quite arbitrary - it has changed the past and might
1270  * change in the future.
1271  */
1272
1273
1274 static int
1275 nameUIDValidate(
1276         Syntax *syntax,
1277         struct berval *in )
1278 {
1279         int rc;
1280         struct berval dn, uid;
1281
1282         if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
1283
1284         ber_dupbv( &dn, in );
1285         if( !dn.bv_val ) return LDAP_OTHER;
1286
1287         /* if there's a "#", try bitStringValidate()... */
1288         uid.bv_val = strrchr( dn.bv_val, '#' );
1289         if ( !BER_BVISNULL( &uid ) ) {
1290                 uid.bv_val++;
1291                 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1292
1293                 rc = bitStringValidate( NULL, &uid );
1294                 if ( rc == LDAP_SUCCESS ) {
1295                         /* in case of success, trim the UID,
1296                          * otherwise treat it as part of the DN */
1297                         dn.bv_len -= uid.bv_len + 1;
1298                         uid.bv_val[-1] = '\0';
1299                 }
1300         }
1301
1302         rc = dnValidate( NULL, &dn );
1303
1304         ber_memfree( dn.bv_val );
1305         return rc;
1306 }
1307
1308 int
1309 nameUIDPretty(
1310         Syntax *syntax,
1311         struct berval *val,
1312         struct berval *out,
1313         void *ctx )
1314 {
1315         assert( val != NULL );
1316         assert( out != NULL );
1317
1318
1319         Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1320
1321         if( BER_BVISEMPTY( val ) ) {
1322                 ber_dupbv_x( out, val, ctx );
1323
1324         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1325                 return LDAP_INVALID_SYNTAX;
1326
1327         } else {
1328                 int             rc;
1329                 struct berval   dnval = *val;
1330                 struct berval   uidval = BER_BVNULL;
1331
1332                 uidval.bv_val = strrchr( val->bv_val, '#' );
1333                 if ( !BER_BVISNULL( &uidval ) ) {
1334                         uidval.bv_val++;
1335                         uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1336
1337                         rc = bitStringValidate( NULL, &uidval );
1338
1339                         if ( rc == LDAP_SUCCESS ) {
1340                                 ber_dupbv_x( &dnval, val, ctx );
1341                                 uidval.bv_val--;
1342                                 dnval.bv_len -= ++uidval.bv_len;
1343                                 dnval.bv_val[dnval.bv_len] = '\0';
1344
1345                         } else {
1346                                 BER_BVZERO( &uidval );
1347                         }
1348                 }
1349
1350                 rc = dnPretty( syntax, &dnval, out, ctx );
1351                 if ( dnval.bv_val != val->bv_val ) {
1352                         slap_sl_free( dnval.bv_val, ctx );
1353                 }
1354                 if( rc != LDAP_SUCCESS ) {
1355                         return rc;
1356                 }
1357
1358                 if( !BER_BVISNULL( &uidval ) ) {
1359                         char    *tmp;
1360
1361                         tmp = slap_sl_realloc( out->bv_val, out->bv_len 
1362                                 + uidval.bv_len + 1,
1363                                 ctx );
1364                         if( tmp == NULL ) {
1365                                 ber_memfree_x( out->bv_val, ctx );
1366                                 return LDAP_OTHER;
1367                         }
1368                         out->bv_val = tmp;
1369                         memcpy( out->bv_val + out->bv_len, uidval.bv_val, uidval.bv_len );
1370                         out->bv_len += uidval.bv_len;
1371                         out->bv_val[out->bv_len] = '\0';
1372                 }
1373         }
1374
1375         Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1376
1377         return LDAP_SUCCESS;
1378 }
1379
1380 static int
1381 uniqueMemberNormalize(
1382         slap_mask_t usage,
1383         Syntax *syntax,
1384         MatchingRule *mr,
1385         struct berval *val,
1386         struct berval *normalized,
1387         void *ctx )
1388 {
1389         struct berval out;
1390         int rc;
1391
1392         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1393
1394         ber_dupbv_x( &out, val, ctx );
1395         if ( BER_BVISEMPTY( &out ) ) {
1396                 *normalized = out;
1397
1398         } else {
1399                 struct berval uid = BER_BVNULL;
1400
1401                 uid.bv_val = strrchr( out.bv_val, '#' );
1402                 if ( !BER_BVISNULL( &uid ) ) {
1403                         uid.bv_val++;
1404                         uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1405
1406                         rc = bitStringValidate( NULL, &uid );
1407                         if ( rc == LDAP_SUCCESS ) {
1408                                 uid.bv_val[-1] = '\0';
1409                                 out.bv_len -= uid.bv_len + 1;
1410                         } else {
1411                                 BER_BVZERO( &uid );
1412                         }
1413                 }
1414
1415                 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1416
1417                 if( rc != LDAP_SUCCESS ) {
1418                         slap_sl_free( out.bv_val, ctx );
1419                         return LDAP_INVALID_SYNTAX;
1420                 }
1421
1422                 if( !BER_BVISNULL( &uid ) ) {
1423                         char    *tmp;
1424
1425                         tmp = ch_realloc( normalized->bv_val,
1426                                 normalized->bv_len + uid.bv_len
1427                                 + STRLENOF("#") + 1 );
1428                         if ( tmp == NULL ) {
1429                                 ber_memfree_x( normalized->bv_val, ctx );
1430                                 return LDAP_OTHER;
1431                         }
1432
1433                         normalized->bv_val = tmp;
1434
1435                         /* insert the separator */
1436                         normalized->bv_val[normalized->bv_len++] = '#';
1437
1438                         /* append the UID */
1439                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1440                                 uid.bv_val, uid.bv_len );
1441                         normalized->bv_len += uid.bv_len;
1442
1443                         /* terminate */
1444                         normalized->bv_val[normalized->bv_len] = '\0';
1445                 }
1446
1447                 slap_sl_free( out.bv_val, ctx );
1448         }
1449
1450         return LDAP_SUCCESS;
1451 }
1452
1453 static int
1454 uniqueMemberMatch(
1455         int *matchp,
1456         slap_mask_t flags,
1457         Syntax *syntax,
1458         MatchingRule *mr,
1459         struct berval *value,
1460         void *assertedValue )
1461 {
1462         int match;
1463         struct berval *asserted = (struct berval *) assertedValue;
1464         struct berval assertedDN = *asserted;
1465         struct berval assertedUID = BER_BVNULL;
1466         struct berval valueDN = *value;
1467         struct berval valueUID = BER_BVNULL;
1468         int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1469
1470         if ( !BER_BVISEMPTY( asserted ) ) {
1471                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1472                 if ( !BER_BVISNULL( &assertedUID ) ) {
1473                         assertedUID.bv_val++;
1474                         assertedUID.bv_len = assertedDN.bv_len
1475                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1476
1477                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1478                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1479
1480                         } else {
1481                                 BER_BVZERO( &assertedUID );
1482                         }
1483                 }
1484         }
1485
1486         if ( !BER_BVISEMPTY( value ) ) {
1487
1488                 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1489                 if ( !BER_BVISNULL( &valueUID ) ) {
1490                         valueUID.bv_val++;
1491                         valueUID.bv_len = valueDN.bv_len
1492                                 - ( valueUID.bv_val - valueDN.bv_val );
1493
1494                         if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1495                                 valueDN.bv_len -= valueUID.bv_len + 1;
1496
1497                         } else {
1498                                 BER_BVZERO( &valueUID );
1499                         }
1500                 }
1501         }
1502
1503         if( valueUID.bv_len && assertedUID.bv_len ) {
1504                 ber_slen_t d;
1505                 d = (ber_slen_t) valueUID.bv_len - (ber_slen_t) assertedUID.bv_len;
1506                 if ( d ) {
1507                         *matchp = sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1;
1508                         return LDAP_SUCCESS;
1509                 }
1510
1511                 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1512                 if( match ) {
1513                         *matchp = match;
1514                         return LDAP_SUCCESS;
1515                 }
1516
1517         } else if ( !approx && valueUID.bv_len ) {
1518                 match = -1;
1519                 *matchp = match;
1520                 return LDAP_SUCCESS;
1521
1522         } else if ( !approx && assertedUID.bv_len ) {
1523                 match = 1;
1524                 *matchp = match;
1525                 return LDAP_SUCCESS;
1526         }
1527
1528         return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1529 }
1530
1531 static int 
1532 uniqueMemberIndexer(
1533         slap_mask_t use,
1534         slap_mask_t flags,
1535         Syntax *syntax,
1536         MatchingRule *mr,
1537         struct berval *prefix,
1538         BerVarray values,
1539         BerVarray *keysp,
1540         void *ctx )
1541 {
1542         BerVarray dnvalues;
1543         int rc;
1544         int i;
1545         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1546                 /* just count them */                 
1547         }
1548         assert( i > 0 );
1549
1550         dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1551
1552         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1553                 struct berval assertedDN = values[i];
1554                 struct berval assertedUID = BER_BVNULL;
1555
1556                 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1557                         assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1558                         if ( !BER_BVISNULL( &assertedUID ) ) {
1559                                 assertedUID.bv_val++;
1560                                 assertedUID.bv_len = assertedDN.bv_len
1561                                         - ( assertedUID.bv_val - assertedDN.bv_val );
1562         
1563                                 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1564                                         assertedDN.bv_len -= assertedUID.bv_len + 1;
1565
1566                                 } else {
1567                                         BER_BVZERO( &assertedUID );
1568                                 }
1569                         }
1570                 }
1571
1572                 dnvalues[i] = assertedDN;
1573         }
1574         BER_BVZERO( &dnvalues[i] );
1575
1576         rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1577                 dnvalues, keysp, ctx );
1578
1579         slap_sl_free( dnvalues, ctx );
1580         return rc;
1581 }
1582
1583 static int 
1584 uniqueMemberFilter(
1585         slap_mask_t use,
1586         slap_mask_t flags,
1587         Syntax *syntax,
1588         MatchingRule *mr,
1589         struct berval *prefix,
1590         void * assertedValue,
1591         BerVarray *keysp,
1592         void *ctx )
1593 {
1594         struct berval *asserted = (struct berval *) assertedValue;
1595         struct berval assertedDN = *asserted;
1596         struct berval assertedUID = BER_BVNULL;
1597
1598         if ( !BER_BVISEMPTY( asserted ) ) {
1599                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1600                 if ( !BER_BVISNULL( &assertedUID ) ) {
1601                         assertedUID.bv_val++;
1602                         assertedUID.bv_len = assertedDN.bv_len
1603                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1604
1605                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1606                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1607
1608                         } else {
1609                                 BER_BVZERO( &assertedUID );
1610                         }
1611                 }
1612         }
1613
1614         return octetStringFilter( use, flags, syntax, mr, prefix,
1615                 &assertedDN, keysp, ctx );
1616 }
1617
1618
1619 /*
1620  * Handling boolean syntax and matching is quite rigid.
1621  * A more flexible approach would be to allow a variety
1622  * of strings to be normalized and prettied into TRUE
1623  * and FALSE.
1624  */
1625 static int
1626 booleanValidate(
1627         Syntax *syntax,
1628         struct berval *in )
1629 {
1630         /* very unforgiving validation, requires no normalization
1631          * before simplistic matching
1632          */
1633
1634         if( in->bv_len == 4 ) {
1635                 if( bvmatch( in, &slap_true_bv ) ) {
1636                         return LDAP_SUCCESS;
1637                 }
1638         } else if( in->bv_len == 5 ) {
1639                 if( bvmatch( in, &slap_false_bv ) ) {
1640                         return LDAP_SUCCESS;
1641                 }
1642         }
1643
1644         return LDAP_INVALID_SYNTAX;
1645 }
1646
1647 static int
1648 booleanMatch(
1649         int *matchp,
1650         slap_mask_t flags,
1651         Syntax *syntax,
1652         MatchingRule *mr,
1653         struct berval *value,
1654         void *assertedValue )
1655 {
1656         /* simplistic matching allowed by rigid validation */
1657         struct berval *asserted = (struct berval *) assertedValue;
1658         *matchp = (int) asserted->bv_len - (int) value->bv_len;
1659         return LDAP_SUCCESS;
1660 }
1661
1662 /*-------------------------------------------------------------------
1663 LDAP/X.500 string syntax / matching rules have a few oddities.  This
1664 comment attempts to detail how slapd(8) treats them.
1665
1666 Summary:
1667   StringSyntax          X.500   LDAP    Matching/Comments
1668   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
1669   PrintableString       subset  subset  i/e + ignore insignificant spaces
1670   PrintableString       subset  subset  i/e + ignore insignificant spaces
1671   NumericString         subset  subset  ignore all spaces
1672   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
1673   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
1674
1675   TelephoneNumber       subset  subset  i + ignore all spaces and "-"
1676
1677   See RFC 4518 for details.
1678
1679
1680 Directory String -
1681   In X.500(93), a directory string can be either a PrintableString,
1682   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1683   In later versions, more CHOICEs were added.  In all cases the string
1684   must be non-empty.
1685
1686   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1687   A directory string cannot be zero length.
1688
1689   For matching, there are both case ignore and exact rules.  Both
1690   also require that "insignificant" spaces be ignored.
1691         spaces before the first non-space are ignored;
1692         spaces after the last non-space are ignored;
1693         spaces after a space are ignored.
1694   Note: by these rules (and as clarified in X.520), a string of only
1695   spaces is to be treated as if held one space, not empty (which
1696   would be a syntax error).
1697
1698 NumericString
1699   In ASN.1, numeric string is just a string of digits and spaces
1700   and could be empty.  However, in X.500, all attribute values of
1701   numeric string carry a non-empty constraint.  For example:
1702
1703         internationalISDNNumber ATTRIBUTE ::= {
1704                 WITH SYNTAX InternationalISDNNumber
1705                 EQUALITY MATCHING RULE numericStringMatch
1706                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1707                 ID id-at-internationalISDNNumber }
1708         InternationalISDNNumber ::=
1709             NumericString (SIZE(1..ub-international-isdn-number))
1710
1711   Unforunately, some assertion values are don't carry the same
1712   constraint (but its unclear how such an assertion could ever
1713   be true). In LDAP, there is one syntax (numericString) not two
1714   (numericString with constraint, numericString without constraint).
1715   This should be treated as numericString with non-empty constraint.
1716   Note that while someone may have no ISDN number, there are no ISDN
1717   numbers which are zero length.
1718
1719   In matching, spaces are ignored.
1720
1721 PrintableString
1722   In ASN.1, Printable string is just a string of printable characters
1723   and can be empty.  In X.500, semantics much like NumericString (see
1724   serialNumber for a like example) excepting uses insignificant space
1725   handling instead of ignore all spaces.  They must be non-empty.
1726
1727 IA5String
1728   Basically same as PrintableString.  There are no examples in X.500,
1729   but same logic applies.  Empty strings are allowed.
1730
1731 -------------------------------------------------------------------*/
1732
1733 static int
1734 UTF8StringValidate(
1735         Syntax *syntax,
1736         struct berval *in )
1737 {
1738         ber_len_t count;
1739         int len;
1740         unsigned char *u = (unsigned char *)in->bv_val;
1741
1742         if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1743                 /* directory strings cannot be empty */
1744                 return LDAP_INVALID_SYNTAX;
1745         }
1746
1747         for( count = in->bv_len; count > 0; count -= len, u += len ) {
1748                 /* get the length indicated by the first byte */
1749                 len = LDAP_UTF8_CHARLEN2( u, len );
1750
1751                 /* very basic checks */
1752                 switch( len ) {
1753                         case 6:
1754                                 if( (u[5] & 0xC0) != 0x80 ) {
1755                                         return LDAP_INVALID_SYNTAX;
1756                                 }
1757                         case 5:
1758                                 if( (u[4] & 0xC0) != 0x80 ) {
1759                                         return LDAP_INVALID_SYNTAX;
1760                                 }
1761                         case 4:
1762                                 if( (u[3] & 0xC0) != 0x80 ) {
1763                                         return LDAP_INVALID_SYNTAX;
1764                                 }
1765                         case 3:
1766                                 if( (u[2] & 0xC0 )!= 0x80 ) {
1767                                         return LDAP_INVALID_SYNTAX;
1768                                 }
1769                         case 2:
1770                                 if( (u[1] & 0xC0) != 0x80 ) {
1771                                         return LDAP_INVALID_SYNTAX;
1772                                 }
1773                         case 1:
1774                                 /* CHARLEN already validated it */
1775                                 break;
1776                         default:
1777                                 return LDAP_INVALID_SYNTAX;
1778                 }
1779
1780                 /* make sure len corresponds with the offset
1781                         to the next character */
1782                 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1783         }
1784
1785         if( count != 0 ) {
1786                 return LDAP_INVALID_SYNTAX;
1787         }
1788
1789         return LDAP_SUCCESS;
1790 }
1791
1792 static int
1793 UTF8StringNormalize(
1794         slap_mask_t use,
1795         Syntax *syntax,
1796         MatchingRule *mr,
1797         struct berval *val,
1798         struct berval *normalized,
1799         void *ctx )
1800 {
1801         struct berval tmp, nvalue;
1802         int flags, wasspace;
1803         ber_len_t i;
1804
1805         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1806
1807         if( BER_BVISNULL( val ) ) {
1808                 /* assume we're dealing with a syntax (e.g., UTF8String)
1809                  * which allows empty strings
1810                  */
1811                 BER_BVZERO( normalized );
1812                 return LDAP_SUCCESS;
1813         }
1814
1815         flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1816                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1817         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1818                 ? LDAP_UTF8_APPROX : 0;
1819
1820         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1821         /* out of memory or syntax error, the former is unlikely */
1822         if( val == NULL ) {
1823                 return LDAP_INVALID_SYNTAX;
1824         }
1825         
1826         /* collapse spaces (in place) */
1827         nvalue.bv_len = 0;
1828         nvalue.bv_val = tmp.bv_val;
1829
1830         /* trim leading spaces? */
1831         wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1832                 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1833
1834         for( i = 0; i < tmp.bv_len; i++) {
1835                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1836                         if( wasspace++ == 0 ) {
1837                                 /* trim repeated spaces */
1838                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1839                         }
1840                 } else {
1841                         wasspace = 0;
1842                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1843                 }
1844         }
1845
1846         if( !BER_BVISEMPTY( &nvalue ) ) {
1847                 /* trim trailing space? */
1848                 if( wasspace && (
1849                         (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1850                         ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1851                 {
1852                         --nvalue.bv_len;
1853                 }
1854                 nvalue.bv_val[nvalue.bv_len] = '\0';
1855
1856         } else {
1857                 /* string of all spaces is treated as one space */
1858                 nvalue.bv_val[0] = ' ';
1859                 nvalue.bv_val[1] = '\0';
1860                 nvalue.bv_len = 1;
1861         }
1862
1863         *normalized = nvalue;
1864         return LDAP_SUCCESS;
1865 }
1866
1867 static int
1868 directoryStringSubstringsMatch(
1869         int *matchp,
1870         slap_mask_t flags,
1871         Syntax *syntax,
1872         MatchingRule *mr,
1873         struct berval *value,
1874         void *assertedValue )
1875 {
1876         int match = 0;
1877         SubstringsAssertion *sub = assertedValue;
1878         struct berval left = *value;
1879         ber_len_t i;
1880         int priorspace=0;
1881
1882         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1883                 if ( sub->sa_initial.bv_len > left.bv_len ) {
1884                         /* not enough left */
1885                         match = 1;
1886                         goto done;
1887                 }
1888
1889                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1890                         sub->sa_initial.bv_len );
1891
1892                 if ( match != 0 ) {
1893                         goto done;
1894                 }
1895
1896                 left.bv_val += sub->sa_initial.bv_len;
1897                 left.bv_len -= sub->sa_initial.bv_len;
1898
1899                 priorspace = ASCII_SPACE(
1900                         sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1901         }
1902
1903         if ( sub->sa_any ) {
1904                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1905                         ber_len_t idx;
1906                         char *p;
1907
1908                         if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] ) 
1909                                 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1910                         { 
1911                                 /* allow next space to match */
1912                                 left.bv_val--;
1913                                 left.bv_len++;
1914                         }
1915                         priorspace=0;
1916
1917 retry:
1918                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1919                                 continue;
1920                         }
1921
1922                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1923                                 /* not enough left */
1924                                 match = 1;
1925                                 goto done;
1926                         }
1927
1928                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1929
1930                         if( p == NULL ) {
1931                                 match = 1;
1932                                 goto done;
1933                         }
1934
1935                         idx = p - left.bv_val;
1936
1937                         if ( idx >= left.bv_len ) {
1938                                 /* this shouldn't happen */
1939                                 return LDAP_OTHER;
1940                         }
1941
1942                         left.bv_val = p;
1943                         left.bv_len -= idx;
1944
1945                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1946                                 /* not enough left */
1947                                 match = 1;
1948                                 goto done;
1949                         }
1950
1951                         match = memcmp( left.bv_val,
1952                                 sub->sa_any[i].bv_val,
1953                                 sub->sa_any[i].bv_len );
1954
1955                         if ( match != 0 ) {
1956                                 left.bv_val++;
1957                                 left.bv_len--;
1958                                 goto retry;
1959                         }
1960
1961                         left.bv_val += sub->sa_any[i].bv_len;
1962                         left.bv_len -= sub->sa_any[i].bv_len;
1963
1964                         priorspace = ASCII_SPACE(
1965                                 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1966                 }
1967         }
1968
1969         if ( !BER_BVISNULL( &sub->sa_final ) ) {
1970                 if( priorspace && !BER_BVISEMPTY( &sub->sa_final ) 
1971                         && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1972                 { 
1973                         /* allow next space to match */
1974                         left.bv_val--;
1975                         left.bv_len++;
1976                 }
1977
1978                 if ( sub->sa_final.bv_len > left.bv_len ) {
1979                         /* not enough left */
1980                         match = 1;
1981                         goto done;
1982                 }
1983
1984                 match = memcmp( sub->sa_final.bv_val,
1985                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1986                         sub->sa_final.bv_len );
1987
1988                 if ( match != 0 ) {
1989                         goto done;
1990                 }
1991         }
1992
1993 done:
1994         *matchp = match;
1995         return LDAP_SUCCESS;
1996 }
1997
1998 #if defined(SLAPD_APPROX_INITIALS)
1999 #       define SLAPD_APPROX_DELIMITER "._ "
2000 #       define SLAPD_APPROX_WORDLEN 2
2001 #else
2002 #       define SLAPD_APPROX_DELIMITER " "
2003 #       define SLAPD_APPROX_WORDLEN 1
2004 #endif
2005
2006 static int
2007 approxMatch(
2008         int *matchp,
2009         slap_mask_t flags,
2010         Syntax *syntax,
2011         MatchingRule *mr,
2012         struct berval *value,
2013         void *assertedValue )
2014 {
2015         struct berval *nval, *assertv;
2016         char *val, **values, **words, *c;
2017         int i, count, len, nextchunk=0, nextavail=0;
2018
2019         /* Yes, this is necessary */
2020         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
2021         if( nval == NULL ) {
2022                 *matchp = 1;
2023                 return LDAP_SUCCESS;
2024         }
2025
2026         /* Yes, this is necessary */
2027         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
2028                 NULL, LDAP_UTF8_APPROX, NULL );
2029         if( assertv == NULL ) {
2030                 ber_bvfree( nval );
2031                 *matchp = 1;
2032                 return LDAP_SUCCESS;
2033         }
2034
2035         /* Isolate how many words there are */
2036         for ( c = nval->bv_val, count = 1; *c; c++ ) {
2037                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
2038                 if ( c == NULL ) break;
2039                 *c = '\0';
2040                 count++;
2041         }
2042
2043         /* Get a phonetic copy of each word */
2044         words = (char **)ch_malloc( count * sizeof(char *) );
2045         values = (char **)ch_malloc( count * sizeof(char *) );
2046         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
2047                 words[i] = c;
2048                 values[i] = phonetic(c);
2049         }
2050
2051         /* Work through the asserted value's words, to see if at least some
2052          * of the words are there, in the same order. */
2053         len = 0;
2054         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
2055                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
2056                 if( len == 0 ) {
2057                         nextchunk++;
2058                         continue;
2059                 }
2060 #if defined(SLAPD_APPROX_INITIALS)
2061                 else if( len == 1 ) {
2062                         /* Single letter words need to at least match one word's initial */
2063                         for( i=nextavail; i<count; i++ )
2064                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
2065                                         nextavail=i+1;
2066                                         break;
2067                                 }
2068                 }
2069 #endif
2070                 else {
2071                         /* Isolate the next word in the asserted value and phonetic it */
2072                         assertv->bv_val[nextchunk+len] = '\0';
2073                         val = phonetic( assertv->bv_val + nextchunk );
2074
2075                         /* See if this phonetic chunk is in the remaining words of *value */
2076                         for( i=nextavail; i<count; i++ ){
2077                                 if( !strcmp( val, values[i] ) ){
2078                                         nextavail = i+1;
2079                                         break;
2080                                 }
2081                         }
2082                         ch_free( val );
2083                 }
2084
2085                 /* This chunk in the asserted value was NOT within the *value. */
2086                 if( i >= count ) {
2087                         nextavail=-1;
2088                         break;
2089                 }
2090
2091                 /* Go on to the next word in the asserted value */
2092                 nextchunk += len+1;
2093         }
2094
2095         /* If some of the words were seen, call it a match */
2096         if( nextavail > 0 ) {
2097                 *matchp = 0;
2098         }
2099         else {
2100                 *matchp = 1;
2101         }
2102
2103         /* Cleanup allocs */
2104         ber_bvfree( assertv );
2105         for( i=0; i<count; i++ ) {
2106                 ch_free( values[i] );
2107         }
2108         ch_free( values );
2109         ch_free( words );
2110         ber_bvfree( nval );
2111
2112         return LDAP_SUCCESS;
2113 }
2114
2115 static int 
2116 approxIndexer(
2117         slap_mask_t use,
2118         slap_mask_t flags,
2119         Syntax *syntax,
2120         MatchingRule *mr,
2121         struct berval *prefix,
2122         BerVarray values,
2123         BerVarray *keysp,
2124         void *ctx )
2125 {
2126         char *c;
2127         int i,j, len, wordcount, keycount=0;
2128         struct berval *newkeys;
2129         BerVarray keys=NULL;
2130
2131         for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
2132                 struct berval val = BER_BVNULL;
2133                 /* Yes, this is necessary */
2134                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
2135                 assert( !BER_BVISNULL( &val ) );
2136
2137                 /* Isolate how many words there are. There will be a key for each */
2138                 for( wordcount = 0, c = val.bv_val; *c; c++) {
2139                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
2140                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
2141                         c+= len;
2142                         if (*c == '\0') break;
2143                         *c = '\0';
2144                 }
2145
2146                 /* Allocate/increase storage to account for new keys */
2147                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
2148                         * sizeof(struct berval) );
2149                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
2150                 if( keys ) ch_free( keys );
2151                 keys = newkeys;
2152
2153                 /* Get a phonetic copy of each word */
2154                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
2155                         len = strlen( c );
2156                         if( len < SLAPD_APPROX_WORDLEN ) continue;
2157                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
2158                         keycount++;
2159                         i++;
2160                 }
2161
2162                 ber_memfree( val.bv_val );
2163         }
2164         BER_BVZERO( &keys[keycount] );
2165         *keysp = keys;
2166
2167         return LDAP_SUCCESS;
2168 }
2169
2170 static int 
2171 approxFilter(
2172         slap_mask_t use,
2173         slap_mask_t flags,
2174         Syntax *syntax,
2175         MatchingRule *mr,
2176         struct berval *prefix,
2177         void * assertedValue,
2178         BerVarray *keysp,
2179         void *ctx )
2180 {
2181         char *c;
2182         int i, count, len;
2183         struct berval *val;
2184         BerVarray keys;
2185
2186         /* Yes, this is necessary */
2187         val = UTF8bvnormalize( ((struct berval *)assertedValue),
2188                 NULL, LDAP_UTF8_APPROX, NULL );
2189         if( val == NULL || BER_BVISNULL( val ) ) {
2190                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
2191                 BER_BVZERO( &keys[0] );
2192                 *keysp = keys;
2193                 ber_bvfree( val );
2194                 return LDAP_SUCCESS;
2195         }
2196
2197         /* Isolate how many words there are. There will be a key for each */
2198         for( count = 0,c = val->bv_val; *c; c++) {
2199                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2200                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
2201                 c+= len;
2202                 if (*c == '\0') break;
2203                 *c = '\0';
2204         }
2205
2206         /* Allocate storage for new keys */
2207         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
2208
2209         /* Get a phonetic copy of each word */
2210         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
2211                 len = strlen(c);
2212                 if( len < SLAPD_APPROX_WORDLEN ) continue;
2213                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
2214                 i++;
2215         }
2216
2217         ber_bvfree( val );
2218
2219         BER_BVZERO( &keys[count] );
2220         *keysp = keys;
2221
2222         return LDAP_SUCCESS;
2223 }
2224
2225 /* Remove all spaces and '-' characters */
2226 static int
2227 telephoneNumberNormalize(
2228         slap_mask_t usage,
2229         Syntax *syntax,
2230         MatchingRule *mr,
2231         struct berval *val,
2232         struct berval *normalized,
2233         void *ctx )
2234 {
2235         char *p, *q;
2236
2237         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
2238
2239         /* validator should have refused an empty string */
2240         assert( !BER_BVISEMPTY( val ) );
2241
2242         q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2243
2244         for( p = val->bv_val; *p; p++ ) {
2245                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
2246                         *q++ = *p;
2247                 }
2248         }
2249         *q = '\0';
2250
2251         normalized->bv_len = q - normalized->bv_val;
2252
2253         if( BER_BVISEMPTY( normalized ) ) {
2254                 slap_sl_free( normalized->bv_val, ctx );
2255                 BER_BVZERO( normalized );
2256                 return LDAP_INVALID_SYNTAX;
2257         }
2258
2259         return LDAP_SUCCESS;
2260 }
2261
2262 static int
2263 postalAddressValidate(
2264         Syntax *syntax,
2265         struct berval *in )
2266 {
2267         struct berval bv = *in;
2268         ber_len_t c;
2269
2270         for ( c = 0; c < in->bv_len; c++ ) {
2271                 if ( in->bv_val[c] == '\\' ) {
2272                         c++;
2273                         if ( strncasecmp( &in->bv_val[c], "24", STRLENOF( "24" ) ) != 0
2274                                 && strncasecmp( &in->bv_val[c], "5C", STRLENOF( "5C" ) ) != 0 )
2275                         {
2276                                 return LDAP_INVALID_SYNTAX;
2277                         }
2278                         continue;
2279                 }
2280
2281                 if ( in->bv_val[c] == '$' ) {
2282                         bv.bv_len = &in->bv_val[c] - bv.bv_val;
2283                         if ( UTF8StringValidate( NULL, &bv ) != LDAP_SUCCESS ) {
2284                                 return LDAP_INVALID_SYNTAX;
2285                         }
2286                         bv.bv_val = &in->bv_val[c] + 1;
2287                 }
2288         }
2289
2290         bv.bv_len = &in->bv_val[c] - bv.bv_val;
2291         return UTF8StringValidate( NULL, &bv );
2292 }
2293
2294 static int
2295 postalAddressNormalize(
2296         slap_mask_t usage,
2297         Syntax *syntax,
2298         MatchingRule *mr,
2299         struct berval *val,
2300         struct berval *normalized,
2301         void *ctx )
2302 {
2303         BerVarray lines = NULL, nlines = NULL;
2304         ber_len_t l, c;
2305         int rc = LDAP_SUCCESS;
2306         MatchingRule *xmr = NULL;
2307         char *p;
2308
2309         if ( SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseIgnoreListMatch ) ) {
2310                 xmr = slap_schema.si_mr_caseIgnoreMatch;
2311
2312         } else {
2313                 xmr = slap_schema.si_mr_caseExactMatch;
2314         }
2315
2316         for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2317                 if ( val->bv_val[c] == '$' ) {
2318                         l++;
2319                 }
2320         }
2321
2322         lines = slap_sl_calloc( sizeof( struct berval ), 2 * ( l + 2 ), ctx );
2323         nlines = &lines[l + 2];
2324
2325         lines[0].bv_val = val->bv_val;
2326         for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2327                 if ( val->bv_val[c] == '$' ) {
2328                         lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2329                         l++;
2330                         lines[l].bv_val = &val->bv_val[c + 1];
2331                 }
2332         }
2333         lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2334
2335         normalized->bv_len = l;
2336
2337         for ( l = 0; !BER_BVISNULL( &lines[l] ); l++ ) {
2338                 /* NOTE: we directly normalize each line,
2339                  * without unescaping the values, since the special
2340                  * values '\24' ('$') and '\5C' ('\') are not affected
2341                  * by normalization */
2342                 rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
2343                 if ( rc != LDAP_SUCCESS ) {
2344                         rc = LDAP_INVALID_SYNTAX;
2345                         goto done;
2346                 }
2347
2348                 normalized->bv_len += nlines[l].bv_len;
2349         }
2350
2351         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2352
2353         p = normalized->bv_val;
2354         for ( l = 0; !BER_BVISNULL( &nlines[l] ); l++ ) {
2355                 p = lutil_strbvcopy( p, &nlines[l] );
2356                 *p++ = '$';
2357         }
2358         *--p = '\0';
2359
2360         assert( p == &normalized->bv_val[normalized->bv_len] );
2361
2362 done:;
2363         if ( nlines != NULL ) {
2364                 for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
2365                         slap_sl_free( nlines[l].bv_val, ctx );
2366                 }
2367
2368                 slap_sl_free( lines, ctx );
2369         }
2370
2371         return rc;
2372 }
2373
2374 int
2375 numericoidValidate(
2376         Syntax *syntax,
2377         struct berval *in )
2378 {
2379         struct berval val = *in;
2380
2381         if( BER_BVISEMPTY( &val ) ) {
2382                 /* disallow empty strings */
2383                 return LDAP_INVALID_SYNTAX;
2384         }
2385
2386         while( OID_LEADCHAR( val.bv_val[0] ) ) {
2387                 if ( val.bv_len == 1 ) {
2388                         return LDAP_SUCCESS;
2389                 }
2390
2391                 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2392                         break;
2393                 }
2394
2395                 val.bv_val++;
2396                 val.bv_len--;
2397
2398                 while ( OID_LEADCHAR( val.bv_val[0] )) {
2399                         val.bv_val++;
2400                         val.bv_len--;
2401
2402                         if ( val.bv_len == 0 ) {
2403                                 return LDAP_SUCCESS;
2404                         }
2405                 }
2406
2407                 if( !OID_SEPARATOR( val.bv_val[0] )) {
2408                         break;
2409                 }
2410
2411                 val.bv_val++;
2412                 val.bv_len--;
2413         }
2414
2415         return LDAP_INVALID_SYNTAX;
2416 }
2417
2418 static int
2419 integerValidate(
2420         Syntax *syntax,
2421         struct berval *in )
2422 {
2423         ber_len_t i;
2424         struct berval val = *in;
2425
2426         if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2427
2428         if ( val.bv_val[0] == '-' ) {
2429                 val.bv_len--;
2430                 val.bv_val++;
2431
2432                 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2433                         return LDAP_INVALID_SYNTAX;
2434                 }
2435
2436                 if( val.bv_val[0] == '0' ) { /* "-0" */
2437                         return LDAP_INVALID_SYNTAX;
2438                 }
2439
2440         } else if ( val.bv_val[0] == '0' ) {
2441                 if( val.bv_len > 1 ) { /* "0<more>" */
2442                         return LDAP_INVALID_SYNTAX;
2443                 }
2444
2445                 return LDAP_SUCCESS;
2446         }
2447
2448         for( i=0; i < val.bv_len; i++ ) {
2449                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2450                         return LDAP_INVALID_SYNTAX;
2451                 }
2452         }
2453
2454         return LDAP_SUCCESS;
2455 }
2456
2457 static int
2458 integerMatch(
2459         int *matchp,
2460         slap_mask_t flags,
2461         Syntax *syntax,
2462         MatchingRule *mr,
2463         struct berval *value,
2464         void *assertedValue )
2465 {
2466         struct berval *asserted = (struct berval *) assertedValue;
2467         int vsign = 1, asign = 1;       /* default sign = '+' */
2468         struct berval v, a;
2469         int match;
2470
2471         v = *value;
2472         if( v.bv_val[0] == '-' ) {
2473                 vsign = -1;
2474                 v.bv_val++;
2475                 v.bv_len--;
2476         }
2477
2478         if( BER_BVISEMPTY( &v ) ) vsign = 0;
2479
2480         a = *asserted;
2481         if( a.bv_val[0] == '-' ) {
2482                 asign = -1;
2483                 a.bv_val++;
2484                 a.bv_len--;
2485         }
2486
2487         if( BER_BVISEMPTY( &a ) ) vsign = 0;
2488
2489         match = vsign - asign;
2490         if( match == 0 ) {
2491                 match = ( v.bv_len != a.bv_len
2492                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
2493                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2494                 if( vsign < 0 ) match = -match;
2495         }
2496
2497         /* Ordering rule used in extensible match filter? */
2498         if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) )
2499                 match = (match >= 0);
2500
2501         *matchp = match;
2502         return LDAP_SUCCESS;
2503 }
2504
2505 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2506 #define INDEX_INTLEN_CHOP 7
2507 #define INDEX_INTLEN_CHOPBYTES 3
2508
2509 static int
2510 integerVal2Key(
2511         struct berval *in,
2512         struct berval *key,
2513         struct berval *tmp,
2514         void *ctx )
2515 {
2516         /* Integer index key format, designed for memcmp to collate correctly:
2517          * if too large: one's complement sign*<approx exponent=chopped bytes>,
2518          * two's complement value (sign-extended or chopped as needed),
2519          * however in first byte above, the top <number of exponent-bytes + 1>
2520          * bits are the inverse sign and next bit is the sign as delimiter.
2521          */
2522         ber_slen_t k = index_intlen_strlen;
2523         ber_len_t chop = 0;
2524         unsigned signmask = ~0x7fU;
2525         unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2526         struct berval val = *in, itmp = *tmp;
2527
2528         if ( val.bv_val[0] != '-' ) {
2529                 neg = 0;
2530                 --k;
2531         }
2532
2533         /* Chop least significant digits, increase length instead */
2534         if ( val.bv_len > (ber_len_t) k ) {
2535                 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2536                 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2537                 chop *= INDEX_INTLEN_CHOPBYTES;         /* #bytes added */
2538         }
2539
2540         if ( lutil_str2bin( &val, &itmp, ctx )) {
2541                 return LDAP_INVALID_SYNTAX;
2542         }
2543
2544         /* Omit leading sign byte */
2545         if ( itmp.bv_val[0] == neg ) {
2546                 itmp.bv_val++;
2547                 itmp.bv_len--;
2548         }
2549
2550         k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2551         if ( k > 0 ) {
2552                 assert( chop == 0 );
2553                 memset( key->bv_val, neg, k );  /* sign-extend */
2554         } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2555                 /* Got exponent -k, or no room for 2 sign bits */
2556                 lenp = lenbuf + sizeof(lenbuf);
2557                 chop = - (ber_len_t) k;
2558                 do {
2559                         *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2560                         signmask >>= 1;
2561                 } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2562                 /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2563                  * are 1, and the top n+2 bits of lenp[0] are the sign bit. */
2564                 k = (lenbuf + sizeof(lenbuf)) - lenp;
2565                 if ( k > (ber_slen_t) index_intlen )
2566                         k = index_intlen;
2567                 memcpy( key->bv_val, lenp, k );
2568                 itmp.bv_len = index_intlen - k;
2569         }
2570         memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2571         key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2572         return 0;
2573 }
2574
2575 /* Index generation function: Ordered index */
2576 static int
2577 integerIndexer(
2578         slap_mask_t use,
2579         slap_mask_t flags,
2580         Syntax *syntax,
2581         MatchingRule *mr,
2582         struct berval *prefix,
2583         BerVarray values,
2584         BerVarray *keysp,
2585         void *ctx )
2586 {
2587         char ibuf[64];
2588         struct berval itmp;
2589         BerVarray keys;
2590         ber_len_t vlen;
2591         int i, rc;
2592         unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2593
2594         /* count the values and find max needed length */
2595         vlen = 0;
2596         for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2597                 if ( vlen < values[i].bv_len )
2598                         vlen = values[i].bv_len;
2599         }
2600         if ( vlen > maxstrlen )
2601                 vlen = maxstrlen;
2602
2603         /* we should have at least one value at this point */
2604         assert( i > 0 );
2605
2606         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2607         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2608                 keys[i].bv_len = index_intlen;
2609                 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2610         }
2611         keys[i].bv_len = 0;
2612         keys[i].bv_val = NULL;
2613
2614         if ( vlen > sizeof(ibuf) ) {
2615                 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2616         } else {
2617                 itmp.bv_val = ibuf;
2618         }
2619         itmp.bv_len = sizeof(ibuf);
2620
2621         for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2622                 if ( itmp.bv_val != ibuf ) {
2623                         itmp.bv_len = values[i].bv_len;
2624                         if ( itmp.bv_len <= sizeof(ibuf) )
2625                                 itmp.bv_len = sizeof(ibuf);
2626                         else if ( itmp.bv_len > maxstrlen )
2627                                 itmp.bv_len = maxstrlen;
2628                 }
2629                 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2630                 if ( rc )
2631                         goto func_leave;
2632         }
2633         *keysp = keys;
2634 func_leave:
2635         if ( itmp.bv_val != ibuf ) {
2636                 slap_sl_free( itmp.bv_val, ctx );
2637         }
2638         return rc;
2639 }
2640
2641 /* Index generation function: Ordered index */
2642 static int
2643 integerFilter(
2644         slap_mask_t use,
2645         slap_mask_t flags,
2646         Syntax *syntax,
2647         MatchingRule *mr,
2648         struct berval *prefix,
2649         void * assertedValue,
2650         BerVarray *keysp,
2651         void *ctx )
2652 {
2653         char ibuf[64];
2654         struct berval iv;
2655         BerVarray keys;
2656         struct berval *value;
2657         int rc;
2658
2659         value = (struct berval *) assertedValue;
2660
2661         keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2662
2663         keys[0].bv_len = index_intlen;
2664         keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2665         keys[1].bv_len = 0;
2666         keys[1].bv_val = NULL;
2667
2668         iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2669                 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2670         if ( iv.bv_len > (int) sizeof(ibuf) ) {
2671                 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2672         } else {
2673                 iv.bv_val = ibuf;
2674                 iv.bv_len = sizeof(ibuf);
2675         }
2676
2677         rc = integerVal2Key( value, keys, &iv, ctx );
2678         if ( rc == 0 )
2679                 *keysp = keys;
2680
2681         if ( iv.bv_val != ibuf ) {
2682                 slap_sl_free( iv.bv_val, ctx );
2683         }
2684         return rc;
2685 }
2686
2687 static int
2688 countryStringValidate(
2689         Syntax *syntax,
2690         struct berval *val )
2691 {
2692         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2693
2694         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2695                 return LDAP_INVALID_SYNTAX;
2696         }
2697         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2698                 return LDAP_INVALID_SYNTAX;
2699         }
2700
2701         return LDAP_SUCCESS;
2702 }
2703
2704 static int
2705 printableStringValidate(
2706         Syntax *syntax,
2707         struct berval *val )
2708 {
2709         ber_len_t i;
2710
2711         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2712
2713         for(i=0; i < val->bv_len; i++) {
2714                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2715                         return LDAP_INVALID_SYNTAX;
2716                 }
2717         }
2718
2719         return LDAP_SUCCESS;
2720 }
2721
2722 static int
2723 printablesStringValidate(
2724         Syntax *syntax,
2725         struct berval *val )
2726 {
2727         ber_len_t i, len;
2728
2729         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2730
2731         for(i=0,len=0; i < val->bv_len; i++) {
2732                 int c = val->bv_val[i];
2733
2734                 if( c == '$' ) {
2735                         if( len == 0 ) {
2736                                 return LDAP_INVALID_SYNTAX;
2737                         }
2738                         len = 0;
2739
2740                 } else if ( SLAP_PRINTABLE(c) ) {
2741                         len++;
2742                 } else {
2743                         return LDAP_INVALID_SYNTAX;
2744                 }
2745         }
2746
2747         if( len == 0 ) {
2748                 return LDAP_INVALID_SYNTAX;
2749         }
2750
2751         return LDAP_SUCCESS;
2752 }
2753
2754 static int
2755 IA5StringValidate(
2756         Syntax *syntax,
2757         struct berval *val )
2758 {
2759         ber_len_t i;
2760
2761         for(i=0; i < val->bv_len; i++) {
2762                 if( !LDAP_ASCII(val->bv_val[i]) ) {
2763                         return LDAP_INVALID_SYNTAX;
2764                 }
2765         }
2766
2767         return LDAP_SUCCESS;
2768 }
2769
2770 static int
2771 IA5StringNormalize(
2772         slap_mask_t use,
2773         Syntax *syntax,
2774         MatchingRule *mr,
2775         struct berval *val,
2776         struct berval *normalized,
2777         void *ctx )
2778 {
2779         char *p, *q;
2780         int casefold = !SLAP_MR_ASSOCIATED( mr,
2781                 slap_schema.si_mr_caseExactIA5Match );
2782
2783         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2784
2785         p = val->bv_val;
2786
2787         /* Ignore initial whitespace */
2788         while ( ASCII_SPACE( *p ) ) p++;
2789
2790         normalized->bv_len = val->bv_len - ( p - val->bv_val );
2791         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2792         AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2793         normalized->bv_val[normalized->bv_len] = '\0';
2794
2795         p = q = normalized->bv_val;
2796
2797         while ( *p ) {
2798                 if ( ASCII_SPACE( *p ) ) {
2799                         *q++ = *p++;
2800
2801                         /* Ignore the extra whitespace */
2802                         while ( ASCII_SPACE( *p ) ) {
2803                                 p++;
2804                         }
2805
2806                 } else if ( casefold ) {
2807                         /* Most IA5 rules require casefolding */
2808                         *q++ = TOLOWER(*p); p++;
2809
2810                 } else {
2811                         *q++ = *p++;
2812                 }
2813         }
2814
2815         assert( normalized->bv_val <= p );
2816         assert( q <= p );
2817
2818         /*
2819          * If the string ended in space, backup the pointer one
2820          * position.  One is enough because the above loop collapsed
2821          * all whitespace to a single space.
2822          */
2823         if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2824
2825         /* null terminate */
2826         *q = '\0';
2827
2828         normalized->bv_len = q - normalized->bv_val;
2829
2830         return LDAP_SUCCESS;
2831 }
2832
2833 static int
2834 UUIDValidate(
2835         Syntax *syntax,
2836         struct berval *in )
2837 {
2838         int i;
2839         if( in->bv_len != 36 ) {
2840                 return LDAP_INVALID_SYNTAX;
2841         }
2842
2843         for( i=0; i<36; i++ ) {
2844                 switch(i) {
2845                         case 8:
2846                         case 13:
2847                         case 18:
2848                         case 23:
2849                                 if( in->bv_val[i] != '-' ) {
2850                                         return LDAP_INVALID_SYNTAX;
2851                                 }
2852                                 break;
2853                         default:
2854                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2855                                         return LDAP_INVALID_SYNTAX;
2856                                 }
2857                 }
2858         }
2859         
2860         return LDAP_SUCCESS;
2861 }
2862
2863 static int
2864 UUIDPretty(
2865         Syntax *syntax,
2866         struct berval *in,
2867         struct berval *out,
2868         void *ctx )
2869 {
2870         int i;
2871         int rc=LDAP_INVALID_SYNTAX;
2872
2873         assert( in != NULL );
2874         assert( out != NULL );
2875
2876         if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2877
2878         out->bv_len = 36;
2879         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2880
2881         for( i=0; i<36; i++ ) {
2882                 switch(i) {
2883                         case 8:
2884                         case 13:
2885                         case 18:
2886                         case 23:
2887                                 if( in->bv_val[i] != '-' ) {
2888                                         goto handle_error;
2889                                 }
2890                                 out->bv_val[i] = '-';
2891                                 break;
2892
2893                         default:
2894                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2895                                         goto handle_error;
2896                                 }
2897                                 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2898                 }
2899         }
2900
2901         rc = LDAP_SUCCESS;
2902         out->bv_val[ out->bv_len ] = '\0';
2903
2904         if( 0 ) {
2905 handle_error:
2906                 slap_sl_free( out->bv_val, ctx );
2907                 out->bv_val = NULL;
2908         }
2909
2910         return rc;
2911 }
2912
2913 int
2914 UUIDNormalize(
2915         slap_mask_t usage,
2916         Syntax *syntax,
2917         MatchingRule *mr,
2918         struct berval *val,
2919         struct berval *normalized,
2920         void *ctx )
2921 {
2922         unsigned char octet = '\0';
2923         int i;
2924         int j;
2925
2926         if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2927                 /* NOTE: must be a normalized UUID */
2928                 assert( val->bv_len == 16 );
2929
2930                 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2931                 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2932                         val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2933                 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2934
2935                 return LDAP_SUCCESS;
2936         }
2937
2938         normalized->bv_len = 16;
2939         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2940
2941         for( i=0, j=0; i<36; i++ ) {
2942                 unsigned char nibble;
2943                 if( val->bv_val[i] == '-' ) {
2944                         continue;
2945
2946                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2947                         nibble = val->bv_val[i] - '0';
2948
2949                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2950                         nibble = val->bv_val[i] - ('a'-10);
2951
2952                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2953                         nibble = val->bv_val[i] - ('A'-10);
2954
2955                 } else {
2956                         slap_sl_free( normalized->bv_val, ctx );
2957                         BER_BVZERO( normalized );
2958                         return LDAP_INVALID_SYNTAX;
2959                 }
2960
2961                 if( j & 1 ) {
2962                         octet |= nibble;
2963                         normalized->bv_val[j>>1] = octet;
2964                 } else {
2965                         octet = nibble << 4;
2966                 }
2967                 j++;
2968         }
2969
2970         normalized->bv_val[normalized->bv_len] = 0;
2971         return LDAP_SUCCESS;
2972 }
2973
2974
2975
2976 int
2977 numericStringValidate(
2978         Syntax *syntax,
2979         struct berval *in )
2980 {
2981         ber_len_t i;
2982
2983         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2984
2985         for(i=0; i < in->bv_len; i++) {
2986                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2987                         return LDAP_INVALID_SYNTAX;
2988                 }
2989         }
2990
2991         return LDAP_SUCCESS;
2992 }
2993
2994 static int
2995 numericStringNormalize(
2996         slap_mask_t usage,
2997         Syntax *syntax,
2998         MatchingRule *mr,
2999         struct berval *val,
3000         struct berval *normalized,
3001         void *ctx )
3002 {
3003         /* removal all spaces */
3004         char *p, *q;
3005
3006         assert( !BER_BVISEMPTY( val ) );
3007
3008         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
3009
3010         p = val->bv_val;
3011         q = normalized->bv_val;
3012
3013         while ( *p ) {
3014                 if ( ASCII_SPACE( *p ) ) {
3015                         /* Ignore whitespace */
3016                         p++;
3017                 } else {
3018                         *q++ = *p++;
3019                 }
3020         }
3021
3022         /* we should have copied no more than is in val */
3023         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
3024
3025         /* null terminate */
3026         *q = '\0';
3027
3028         normalized->bv_len = q - normalized->bv_val;
3029
3030         if( BER_BVISEMPTY( normalized ) ) {
3031                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
3032                 normalized->bv_val[0] = ' ';
3033                 normalized->bv_val[1] = '\0';
3034                 normalized->bv_len = 1;
3035         }
3036
3037         return LDAP_SUCCESS;
3038 }
3039
3040 /*
3041  * Integer conversion macros that will use the largest available
3042  * type.
3043  */
3044 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
3045 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
3046 # define SLAP_LONG           long long
3047 #else
3048 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
3049 # define SLAP_LONG           long
3050 #endif /* HAVE_STRTOLL ... */
3051
3052 static int
3053 integerBitAndMatch(
3054         int *matchp,
3055         slap_mask_t flags,
3056         Syntax *syntax,
3057         MatchingRule *mr,
3058         struct berval *value,
3059         void *assertedValue )
3060 {
3061         SLAP_LONG lValue, lAssertedValue;
3062
3063         errno = 0;
3064         /* safe to assume integers are NUL terminated? */
3065         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3066         if( errno == ERANGE )
3067         {
3068                 return LDAP_CONSTRAINT_VIOLATION;
3069         }
3070
3071         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
3072                 NULL, 10);
3073         if( errno == ERANGE )
3074         {
3075                 return LDAP_CONSTRAINT_VIOLATION;
3076         }
3077
3078         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
3079         return LDAP_SUCCESS;
3080 }
3081
3082 static int
3083 integerBitOrMatch(
3084         int *matchp,
3085         slap_mask_t flags,
3086         Syntax *syntax,
3087         MatchingRule *mr,
3088         struct berval *value,
3089         void *assertedValue )
3090 {
3091         SLAP_LONG lValue, lAssertedValue;
3092
3093         errno = 0;
3094         /* safe to assume integers are NUL terminated? */
3095         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3096         if( errno == ERANGE )
3097         {
3098                 return LDAP_CONSTRAINT_VIOLATION;
3099         }
3100
3101         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
3102                 NULL, 10);
3103         if( errno == ERANGE )
3104         {
3105                 return LDAP_CONSTRAINT_VIOLATION;
3106         }
3107
3108         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
3109         return LDAP_SUCCESS;
3110 }
3111
3112 static int
3113 checkNum( struct berval *in, struct berval *out )
3114 {
3115         /* parse serialNumber */
3116         ber_len_t neg = 0, extra = 0;
3117         char first = '\0';
3118
3119         out->bv_val = in->bv_val;
3120         out->bv_len = 0;
3121
3122         if ( out->bv_val[0] == '-' ) {
3123                 neg++;
3124                 out->bv_len++;
3125         }
3126
3127         if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
3128                 first = out->bv_val[2];
3129                 extra = 2;
3130
3131                 out->bv_len += STRLENOF("0x");
3132                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3133                         if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3134                 }
3135
3136         } else if ( out->bv_val[0] == '\'' ) {
3137                 first = out->bv_val[1];
3138                 extra = 3;
3139
3140                 out->bv_len += STRLENOF("'");
3141
3142                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3143                         if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3144                 }
3145                 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3146                         return -1;
3147                 }
3148                 out->bv_len += STRLENOF("'H");
3149
3150         } else {
3151                 first = out->bv_val[0];
3152                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3153                         if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3154                 }
3155         }
3156
3157         if ( !( out->bv_len > neg ) ) {
3158                 return -1;
3159         }
3160
3161         if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3162                 return -1;
3163         }
3164
3165         return 0;
3166 }
3167
3168 static int
3169 serialNumberAndIssuerCheck(
3170         struct berval *in,
3171         struct berval *sn,
3172         struct berval *is,
3173         void *ctx )
3174 {
3175         ber_len_t n;
3176
3177         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3178
3179         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3180                 /* Parse old format */
3181                 is->bv_val = ber_bvchr( in, '$' );
3182                 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3183
3184                 sn->bv_val = in->bv_val;
3185                 sn->bv_len = is->bv_val - in->bv_val;
3186
3187                 is->bv_val++;
3188                 is->bv_len = in->bv_len - (sn->bv_len + 1);
3189
3190                 /* eat leading zeros */
3191                 for( n=0; n < (sn->bv_len-1); n++ ) {
3192                         if( sn->bv_val[n] != '0' ) break;
3193                 }
3194                 sn->bv_val += n;
3195                 sn->bv_len -= n;
3196
3197                 for( n=0; n < sn->bv_len; n++ ) {
3198                         if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3199                 }
3200
3201         } else {
3202                 /* Parse GSER format */ 
3203                 enum {
3204                         HAVE_NONE = 0x0,
3205                         HAVE_ISSUER = 0x1,
3206                         HAVE_SN = 0x2,
3207                         HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3208                 } have = HAVE_NONE;
3209
3210                 int numdquotes = 0;
3211                 struct berval x = *in;
3212                 struct berval ni;
3213                 x.bv_val++;
3214                 x.bv_len -= 2;
3215
3216                 do {
3217                         /* eat leading spaces */
3218                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3219                                 /* empty */;
3220                         }
3221
3222                         /* should be at issuer or serialNumber NamedValue */
3223                         if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3224                                 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3225
3226                                 /* parse issuer */
3227                                 x.bv_val += STRLENOF("issuer");
3228                                 x.bv_len -= STRLENOF("issuer");
3229
3230                                 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3231                                 x.bv_val++;
3232                                 x.bv_len--;
3233
3234                                 /* eat leading spaces */
3235                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3236                                         /* empty */;
3237                                 }
3238
3239                                 /* For backward compatibility, this part is optional */
3240                                 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3241                                         x.bv_val += STRLENOF("rdnSequence:");
3242                                         x.bv_len -= STRLENOF("rdnSequence:");
3243                                 }
3244
3245                                 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3246                                 x.bv_val++;
3247                                 x.bv_len--;
3248
3249                                 is->bv_val = x.bv_val;
3250                                 is->bv_len = 0;
3251
3252                                 for ( ; is->bv_len < x.bv_len; ) {
3253                                         if ( is->bv_val[is->bv_len] != '"' ) {
3254                                                 is->bv_len++;
3255                                                 continue;
3256                                         }
3257                                         if ( is->bv_val[is->bv_len+1] == '"' ) {
3258                                                 /* double dquote */
3259                                                 is->bv_len += 2;
3260                                                 continue;
3261                                         }
3262                                         break;
3263                                 }
3264                                 x.bv_val += is->bv_len + 1;
3265                                 x.bv_len -= is->bv_len + 1;
3266
3267                                 have |= HAVE_ISSUER;
3268
3269                         } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3270                         {
3271                                 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3272
3273                                 /* parse serialNumber */
3274                                 x.bv_val += STRLENOF("serialNumber");
3275                                 x.bv_len -= STRLENOF("serialNumber");
3276
3277                                 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3278                                 x.bv_val++;
3279                                 x.bv_len--;
3280
3281                                 /* eat leading spaces */
3282                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3283                                         /* empty */;
3284                                 }
3285
3286                                 if ( checkNum( &x, sn ) ) {
3287                                         return LDAP_INVALID_SYNTAX;
3288                                 }
3289
3290                                 x.bv_val += sn->bv_len;
3291                                 x.bv_len -= sn->bv_len;
3292
3293                                 have |= HAVE_SN;
3294
3295                         } else {
3296                                 return LDAP_INVALID_SYNTAX;
3297                         }
3298
3299                         /* eat leading spaces */
3300                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3301                                 /* empty */;
3302                         }
3303
3304                         if ( have == HAVE_ALL ) {
3305                                 break;
3306                         }
3307
3308                         if ( x.bv_val[0] != ',' ) {
3309                                 return LDAP_INVALID_SYNTAX;
3310                         }
3311
3312                         x.bv_val++;
3313                         x.bv_len--;
3314                 } while ( 1 );
3315
3316                 /* should have no characters left... */
3317                 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3318
3319                 if ( numdquotes == 0 ) {
3320                         ber_dupbv_x( &ni, is, ctx );
3321
3322                 } else {
3323                         ber_len_t src, dst;
3324
3325                         ni.bv_len = is->bv_len - numdquotes;
3326                         ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3327                         for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3328                                 if ( is->bv_val[src] == '"' ) {
3329                                         src++;
3330                                 }
3331                                 ni.bv_val[dst] = is->bv_val[src];
3332                         }
3333                         ni.bv_val[dst] = '\0';
3334                 }
3335                         
3336                 *is = ni;
3337         }
3338
3339         return 0;
3340 }
3341         
3342 static int
3343 serialNumberAndIssuerValidate(
3344         Syntax *syntax,
3345         struct berval *in )
3346 {
3347         int rc;
3348         struct berval sn, i;
3349
3350         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3351                 in->bv_val, 0, 0 );
3352
3353         rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3354         if ( rc ) {
3355                 goto done;
3356         }
3357
3358         /* validate DN -- doesn't handle double dquote */ 
3359         rc = dnValidate( NULL, &i );
3360         if ( rc ) {
3361                 rc = LDAP_INVALID_SYNTAX;
3362         }
3363
3364         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3365                 slap_sl_free( i.bv_val, NULL );
3366         }
3367
3368         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3369                 in->bv_val, rc, 0 );
3370
3371 done:;
3372         return rc;
3373 }
3374
3375 static int
3376 serialNumberAndIssuerPretty(
3377         Syntax *syntax,
3378         struct berval *in,
3379         struct berval *out,
3380         void *ctx )
3381 {
3382         int rc;
3383         struct berval sn, i, ni = BER_BVNULL;
3384         char *p;
3385
3386         assert( in != NULL );
3387         assert( out != NULL );
3388
3389         BER_BVZERO( out );
3390
3391         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3392                 in->bv_val, 0, 0 );
3393
3394         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3395         if ( rc ) {
3396                 goto done;
3397         }
3398
3399         rc = dnPretty( syntax, &i, &ni, ctx );
3400
3401         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3402                 slap_sl_free( i.bv_val, ctx );
3403         }
3404
3405         if ( rc ) {
3406                 rc = LDAP_INVALID_SYNTAX;
3407                 goto done;
3408         }
3409
3410         /* make room from sn + "$" */
3411         out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3412                 + sn.bv_len + ni.bv_len;
3413         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3414
3415         if ( out->bv_val == NULL ) {
3416                 out->bv_len = 0;
3417                 rc = LDAP_OTHER;
3418                 goto done;
3419         }
3420
3421         p = out->bv_val;
3422         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3423         p = lutil_strbvcopy( p, &sn );
3424         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3425         p = lutil_strbvcopy( p, &ni );
3426         p = lutil_strcopy( p, /*{*/ "\" }" );
3427
3428         assert( p == &out->bv_val[out->bv_len] );
3429
3430 done:;
3431         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3432                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3433
3434         slap_sl_free( ni.bv_val, ctx );
3435
3436         return LDAP_SUCCESS; 
3437 }
3438
3439 static int
3440 slap_bin2hex(
3441         struct berval *in,
3442         struct berval *out,
3443         void *ctx )
3444
3445 {       
3446         /* Use hex format. '123456789abcdef'H */
3447         unsigned char *ptr, zero = '\0';
3448         char *sptr;
3449         int first;
3450         ber_len_t i, len, nlen;
3451
3452         assert( in != NULL );
3453         assert( !BER_BVISNULL( in ) );
3454         assert( out != NULL );
3455         assert( !BER_BVISNULL( out ) );
3456
3457         ptr = (unsigned char *)in->bv_val;
3458         len = in->bv_len;
3459
3460         /* Check for minimal encodings */
3461         if ( len > 1 ) {
3462                 if ( ptr[0] & 0x80 ) {
3463                         if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3464                                 return -1;
3465                         }
3466
3467                 } else if ( ptr[0] == 0 ) {
3468                         if ( !( ptr[1] & 0x80 ) ) {
3469                                 return -1;
3470                         }
3471                         len--;
3472                         ptr++;
3473                 }
3474
3475         } else if ( len == 0 ) {
3476                 /* FIXME: this should not be possible,
3477                  * since a value of zero would have length 1 */
3478                 len = 1;
3479                 ptr = &zero;
3480         }
3481
3482         first = !( ptr[0] & 0xf0U );
3483         nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3484         if ( nlen >= out->bv_len ) {
3485                 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3486         }
3487         sptr = out->bv_val;
3488         *sptr++ = '\'';
3489         i = 0;
3490         if ( first ) {
3491                 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3492                 sptr++;
3493                 i = 1;
3494         }
3495         for ( ; i < len; i++ ) {
3496                 sprintf( sptr, "%02X", ptr[i] );
3497                 sptr += 2;
3498         }
3499         *sptr++ = '\'';
3500         *sptr++ = 'H';
3501         *sptr = '\0';
3502
3503         assert( sptr == &out->bv_val[nlen] );
3504
3505         out->bv_len = nlen;
3506
3507         return 0;
3508 }
3509
3510 #define SLAP_SN_BUFLEN  (64)
3511
3512 /*
3513  * This routine is called by certificateExactNormalize when
3514  * certificateExactNormalize receives a search string instead of
3515  * a certificate. This routine checks if the search value is valid
3516  * and then returns the normalized value
3517  */
3518 static int
3519 serialNumberAndIssuerNormalize(
3520         slap_mask_t usage,
3521         Syntax *syntax,
3522         MatchingRule *mr,
3523         struct berval *in,
3524         struct berval *out,
3525         void *ctx )
3526 {
3527         struct berval sn, sn2, sn3, i, ni;
3528         char sbuf2[SLAP_SN_BUFLEN];
3529         char sbuf3[SLAP_SN_BUFLEN];
3530         char *p;
3531         int rc;
3532
3533         assert( in != NULL );
3534         assert( out != NULL );
3535
3536         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3537                 in->bv_val, 0, 0 );
3538
3539         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3540         if ( rc ) {
3541                 return rc;
3542         }
3543
3544         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3545
3546         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3547                 slap_sl_free( i.bv_val, ctx );
3548         }
3549
3550         if ( rc ) {
3551                 return LDAP_INVALID_SYNTAX;
3552         }
3553
3554         /* Convert sn to canonical hex */
3555         sn2.bv_val = sbuf2;
3556         if ( sn.bv_len > sizeof( sbuf2 ) ) {
3557                 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3558         }
3559         sn2.bv_len = sn.bv_len;
3560         sn3.bv_val = sbuf3;
3561         sn3.bv_len = sizeof(sbuf3);
3562         if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) {
3563                 rc = LDAP_INVALID_SYNTAX;
3564                 goto func_leave;
3565         }
3566
3567         out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3568                 + sn3.bv_len + ni.bv_len;
3569         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3570         if ( out->bv_val == NULL ) {
3571                 out->bv_len = 0;
3572                 rc = LDAP_OTHER;
3573                 goto func_leave;
3574         }
3575
3576         p = out->bv_val;
3577
3578         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3579         p = lutil_strbvcopy( p, &sn3 );
3580         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3581         p = lutil_strbvcopy( p, &ni );
3582         p = lutil_strcopy( p, /*{*/ "\" }" );
3583
3584         assert( p == &out->bv_val[out->bv_len] );
3585
3586 func_leave:
3587         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3588                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3589
3590         if ( sn2.bv_val != sbuf2 ) {
3591                 slap_sl_free( sn2.bv_val, ctx );
3592         }
3593
3594         if ( sn3.bv_val != sbuf3 ) {
3595                 slap_sl_free( sn3.bv_val, ctx );
3596         }
3597
3598         slap_sl_free( ni.bv_val, ctx );
3599
3600         return rc;
3601 }
3602
3603 static int
3604 certificateExactNormalize(
3605         slap_mask_t usage,
3606         Syntax *syntax,
3607         MatchingRule *mr,
3608         struct berval *val,
3609         struct berval *normalized,
3610         void *ctx )
3611 {
3612         BerElementBuffer berbuf;
3613         BerElement *ber = (BerElement *)&berbuf;
3614         ber_tag_t tag;
3615         ber_len_t len;
3616         ber_int_t i;
3617         char serialbuf2[SLAP_SN_BUFLEN];
3618         struct berval sn, sn2 = BER_BVNULL;
3619         struct berval issuer_dn = BER_BVNULL, bvdn;
3620         char *p;
3621         int rc = LDAP_INVALID_SYNTAX;
3622
3623         assert( val != NULL );
3624
3625         Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3626                 val->bv_val, val->bv_len, 0 );
3627
3628         if ( BER_BVISEMPTY( val ) ) goto done;
3629
3630         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3631                 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3632         }
3633
3634         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3635
3636         ber_init2( ber, val, LBER_USE_DER );
3637         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
3638         tag = ber_skip_tag( ber, &len );        /* Sequence */
3639         tag = ber_peek_tag( ber, &len );        /* Optional version? */
3640         if ( tag == SLAP_X509_OPT_C_VERSION ) {
3641                 tag = ber_skip_tag( ber, &len );
3642                 tag = ber_get_int( ber, &i );   /* version */
3643         }
3644
3645         /* NOTE: move the test here from certificateValidate,
3646          * so that we can validate certs with serial longer
3647          * than sizeof(ber_int_t) */
3648         tag = ber_skip_tag( ber, &len );        /* serial */
3649         sn.bv_len = len;
3650         sn.bv_val = (char *)ber->ber_ptr;
3651         sn2.bv_val = serialbuf2;
3652         sn2.bv_len = sizeof(serialbuf2);
3653         if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3654                 rc = LDAP_INVALID_SYNTAX;
3655                 goto done;
3656         }
3657         ber_skip_data( ber, len );
3658
3659         tag = ber_skip_tag( ber, &len );        /* SignatureAlg */
3660         ber_skip_data( ber, len );
3661         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
3662         len = ber_ptrlen( ber );
3663         bvdn.bv_val = val->bv_val + len;
3664         bvdn.bv_len = val->bv_len - len;
3665
3666         rc = dnX509normalize( &bvdn, &issuer_dn );
3667         if ( rc != LDAP_SUCCESS ) goto done;
3668
3669         normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3670                 + sn2.bv_len + issuer_dn.bv_len;
3671         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3672
3673         p = normalized->bv_val;
3674
3675         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3676         p = lutil_strbvcopy( p, &sn2 );
3677         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3678         p = lutil_strbvcopy( p, &issuer_dn );
3679         p = lutil_strcopy( p, /*{*/ "\" }" );
3680
3681         rc = LDAP_SUCCESS;
3682
3683 done:
3684         Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3685                 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3686
3687         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3688         if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3689
3690         return rc;
3691 }
3692
3693 /* X.509 PKI certificateList stuff */
3694 static int
3695 checkTime( struct berval *in, struct berval *out )
3696 {
3697         int rc;
3698         ber_len_t i;
3699         char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3700         struct berval bv;
3701
3702         assert( in != NULL );
3703         assert( !BER_BVISNULL( in ) );
3704         assert( !BER_BVISEMPTY( in ) );
3705
3706         if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3707                 return -1;
3708         }
3709
3710         if ( out != NULL ) {
3711                 assert( !BER_BVISNULL( out ) );
3712                 assert( out->bv_len >= sizeof( buf ) );
3713                 bv.bv_val = out->bv_val;
3714
3715         } else {
3716                 bv.bv_val = buf;
3717         }
3718
3719         for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3720                 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3721         }
3722
3723         if ( in->bv_val[i] != 'Z' ) {
3724                 return -1;
3725         }
3726         i++;
3727
3728         if ( i != in->bv_len ) {
3729                 return -1;
3730         }
3731
3732         if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3733                 lutil_strncopy( bv.bv_val, in->bv_val, i );
3734                 bv.bv_len = i;
3735                 
3736         } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3737                 char *p = bv.bv_val;
3738                 if ( in->bv_val[0] < '7' ) {
3739                         p = lutil_strcopy( p, "20" );
3740
3741                 } else {
3742                         p = lutil_strcopy( p, "19" );
3743                 }
3744                 lutil_strncopy( p, in->bv_val, i );
3745                 bv.bv_len = 2 + i;
3746
3747         } else {
3748                 return -1;
3749         }
3750
3751         rc = generalizedTimeValidate( NULL, &bv );
3752         if ( rc == LDAP_SUCCESS && out != NULL ) {
3753                 if ( out->bv_len > bv.bv_len ) {
3754                         out->bv_val[ bv.bv_len ] = '\0';
3755                 }
3756                 out->bv_len = bv.bv_len;
3757         }
3758
3759         return rc != LDAP_SUCCESS;
3760 }
3761
3762 static int
3763 issuerAndThisUpdateCheck(
3764         struct berval *in,
3765         struct berval *is,
3766         struct berval *tu,
3767         void *ctx )
3768 {
3769         int numdquotes = 0;
3770         struct berval x = *in;
3771         struct berval ni = BER_BVNULL;
3772         /* Parse GSER format */ 
3773         enum {
3774                 HAVE_NONE = 0x0,
3775                 HAVE_ISSUER = 0x1,
3776                 HAVE_THISUPDATE = 0x2,
3777                 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3778         } have = HAVE_NONE;
3779
3780
3781         if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3782
3783         if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3784                 return LDAP_INVALID_SYNTAX;
3785         }
3786
3787         x.bv_val++;
3788         x.bv_len -= STRLENOF("{}");
3789
3790         do {
3791                 /* eat leading spaces */
3792                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3793                         /* empty */;
3794                 }
3795
3796                 /* should be at issuer or thisUpdate */
3797                 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3798                         if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3799
3800                         /* parse issuer */
3801                         x.bv_val += STRLENOF("issuer");
3802                         x.bv_len -= STRLENOF("issuer");
3803
3804                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3805                         x.bv_val++;
3806                         x.bv_len--;
3807
3808                         /* eat leading spaces */
3809                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3810                                 /* empty */;
3811                         }
3812
3813                         /* For backward compatibility, this part is optional */
3814                         if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3815                                 return LDAP_INVALID_SYNTAX;
3816                         }
3817                         x.bv_val += STRLENOF("rdnSequence:");
3818                         x.bv_len -= STRLENOF("rdnSequence:");
3819
3820                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3821                         x.bv_val++;
3822                         x.bv_len--;
3823
3824                         is->bv_val = x.bv_val;
3825                         is->bv_len = 0;
3826
3827                         for ( ; is->bv_len < x.bv_len; ) {
3828                                 if ( is->bv_val[is->bv_len] != '"' ) {
3829                                         is->bv_len++;
3830                                         continue;
3831                                 }
3832                                 if ( is->bv_val[is->bv_len+1] == '"' ) {
3833                                         /* double dquote */
3834                                         is->bv_len += 2;
3835                                         continue;
3836                                 }
3837                                 break;
3838                         }
3839                         x.bv_val += is->bv_len + 1;
3840                         x.bv_len -= is->bv_len + 1;
3841
3842                         have |= HAVE_ISSUER;
3843
3844                 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3845                 {
3846                         if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3847
3848                         /* parse thisUpdate */
3849                         x.bv_val += STRLENOF("thisUpdate");
3850                         x.bv_len -= STRLENOF("thisUpdate");
3851
3852                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3853                         x.bv_val++;
3854                         x.bv_len--;
3855
3856                         /* eat leading spaces */
3857                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3858                                 /* empty */;
3859                         }
3860
3861                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3862                         x.bv_val++;
3863                         x.bv_len--;
3864
3865                         tu->bv_val = x.bv_val;
3866                         tu->bv_len = 0;
3867
3868                         for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3869                                 if ( tu->bv_val[tu->bv_len] == '"' ) {
3870                                         break;
3871                                 }
3872                         }
3873                         x.bv_val += tu->bv_len + 1;
3874                         x.bv_len -= tu->bv_len + 1;
3875
3876                         have |= HAVE_THISUPDATE;
3877
3878                 } else {
3879                         return LDAP_INVALID_SYNTAX;
3880                 }
3881
3882                 /* eat leading spaces */
3883                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3884                         /* empty */;
3885                 }
3886
3887                 if ( have == HAVE_ALL ) {
3888                         break;
3889                 }
3890
3891                 if ( x.bv_val[0] != ',' ) {
3892                         return LDAP_INVALID_SYNTAX;
3893                 }
3894
3895                 x.bv_val++;
3896                 x.bv_len--;
3897         } while ( 1 );
3898
3899         /* should have no characters left... */
3900         if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3901
3902         if ( numdquotes == 0 ) {
3903                 ber_dupbv_x( &ni, is, ctx );
3904
3905         } else {
3906                 ber_len_t src, dst;
3907
3908                 ni.bv_len = is->bv_len - numdquotes;
3909                 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3910                 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3911                         if ( is->bv_val[src] == '"' ) {
3912                                 src++;
3913                         }
3914                         ni.bv_val[dst] = is->bv_val[src];
3915                 }
3916                 ni.bv_val[dst] = '\0';
3917         }
3918                 
3919         *is = ni;
3920
3921         return 0;
3922 }
3923
3924 static int
3925 issuerAndThisUpdateValidate(
3926         Syntax *syntax,
3927         struct berval *in )
3928 {
3929         int rc;
3930         struct berval i, tu;
3931
3932         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
3933                 in->bv_val, 0, 0 );
3934
3935         rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
3936         if ( rc ) {
3937                 goto done;
3938         }
3939
3940         /* validate DN -- doesn't handle double dquote */ 
3941         rc = dnValidate( NULL, &i );
3942         if ( rc ) {
3943                 rc = LDAP_INVALID_SYNTAX;
3944
3945         } else if ( checkTime( &tu, NULL ) ) {
3946                 rc = LDAP_INVALID_SYNTAX;
3947         }
3948
3949         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3950                 slap_sl_free( i.bv_val, NULL );
3951         }
3952
3953         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
3954                 in->bv_val, rc, 0 );
3955
3956 done:;
3957         return rc;
3958 }
3959
3960 static int
3961 issuerAndThisUpdatePretty(
3962         Syntax *syntax,
3963         struct berval *in,
3964         struct berval *out,
3965         void *ctx )
3966 {
3967         int rc;
3968         struct berval i, tu, ni = BER_BVNULL;
3969         char *p;
3970
3971         assert( in != NULL );
3972         assert( out != NULL );
3973
3974         BER_BVZERO( out );
3975
3976         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
3977                 in->bv_val, 0, 0 );
3978
3979         rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3980         if ( rc ) {
3981                 goto done;
3982         }
3983
3984         rc = dnPretty( syntax, &i, &ni, ctx );
3985
3986         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3987                 slap_sl_free( i.bv_val, ctx );
3988         }
3989
3990         if ( rc || checkTime( &tu, NULL ) ) {
3991                 rc = LDAP_INVALID_SYNTAX;
3992                 goto done;
3993         }
3994
3995         /* make room */
3996         out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
3997                 + ni.bv_len + tu.bv_len;
3998         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3999
4000         if ( out->bv_val == NULL ) {
4001                 out->bv_len = 0;
4002                 rc = LDAP_OTHER;
4003                 goto done;
4004         }
4005
4006         p = out->bv_val;
4007         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4008         p = lutil_strbvcopy( p, &ni );
4009         p = lutil_strcopy( p, "\", thisUpdate \"" );
4010         p = lutil_strbvcopy( p, &tu );
4011         p = lutil_strcopy( p, /*{*/ "\" }" );
4012
4013         assert( p == &out->bv_val[out->bv_len] );
4014
4015 done:;
4016         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
4017                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4018
4019         slap_sl_free( ni.bv_val, ctx );
4020
4021         return rc; 
4022 }
4023
4024 static int
4025 issuerAndThisUpdateNormalize(
4026         slap_mask_t usage,
4027         Syntax *syntax,
4028         MatchingRule *mr,
4029         struct berval *in,
4030         struct berval *out,
4031         void *ctx )
4032 {
4033         struct berval i, ni, tu, tu2;
4034         char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4035         char *p;
4036         int rc;
4037
4038         assert( in != NULL );
4039         assert( out != NULL );
4040
4041         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
4042                 in->bv_val, 0, 0 );
4043
4044         rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4045         if ( rc ) {
4046                 return rc;
4047         }
4048
4049         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4050
4051         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4052                 slap_sl_free( i.bv_val, ctx );
4053         }
4054
4055         tu2.bv_val = sbuf;
4056         tu2.bv_len = sizeof( sbuf );
4057         if ( rc || checkTime( &tu, &tu2 ) ) {
4058                 return LDAP_INVALID_SYNTAX;
4059         }
4060
4061         out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4062                 + ni.bv_len + tu2.bv_len;
4063         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4064
4065         if ( out->bv_val == NULL ) {
4066                 out->bv_len = 0;
4067                 rc = LDAP_OTHER;
4068                 goto func_leave;
4069         }
4070
4071         p = out->bv_val;
4072
4073         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4074         p = lutil_strbvcopy( p, &ni );
4075         p = lutil_strcopy( p, "\", thisUpdate \"" );
4076         p = lutil_strbvcopy( p, &tu2 );
4077         p = lutil_strcopy( p, /*{*/ "\" }" );
4078
4079         assert( p == &out->bv_val[out->bv_len] );
4080
4081 func_leave:
4082         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
4083                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4084
4085         slap_sl_free( ni.bv_val, ctx );
4086
4087         return rc;
4088 }
4089
4090 static int
4091 certificateListExactNormalize(
4092         slap_mask_t usage,
4093         Syntax *syntax,
4094         MatchingRule *mr,
4095         struct berval *val,
4096         struct berval *normalized,
4097         void *ctx )
4098 {
4099         BerElementBuffer berbuf;
4100         BerElement *ber = (BerElement *)&berbuf;
4101         ber_tag_t tag;
4102         ber_len_t len;
4103         ber_int_t version;
4104         struct berval issuer_dn = BER_BVNULL, bvdn,
4105                 thisUpdate, bvtu;
4106         char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4107         int rc = LDAP_INVALID_SYNTAX;
4108
4109         assert( val != NULL );
4110
4111         Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
4112                 val->bv_val, val->bv_len, 0 );
4113
4114         if ( BER_BVISEMPTY( val ) ) goto done;
4115
4116         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4117                 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4118         }
4119
4120         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4121
4122         ber_init2( ber, val, LBER_USE_DER );
4123         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
4124         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4125         tag = ber_skip_tag( ber, &len );        /* Sequence */
4126         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4127         tag = ber_peek_tag( ber, &len );
4128         /* Optional version */
4129         if ( tag == LBER_INTEGER ) {
4130                 tag = ber_get_int( ber, &version );
4131                 assert( tag == LBER_INTEGER );
4132                 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4133         }
4134         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
4135         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4136         ber_skip_data( ber, len );
4137
4138         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
4139         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4140         len = ber_ptrlen( ber );
4141         bvdn.bv_val = val->bv_val + len;
4142         bvdn.bv_len = val->bv_len - len;
4143         tag = ber_skip_tag( ber, &len );
4144         ber_skip_data( ber, len );
4145
4146         tag = ber_skip_tag( ber, &len );        /* thisUpdate */
4147         /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4148         if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4149         bvtu.bv_val = (char *)ber->ber_ptr;
4150         bvtu.bv_len = len;
4151
4152         rc = dnX509normalize( &bvdn, &issuer_dn );
4153         if ( rc != LDAP_SUCCESS ) goto done;
4154
4155         thisUpdate.bv_val = tubuf;
4156         thisUpdate.bv_len = sizeof(tubuf);
4157         if ( checkTime( &bvtu, &thisUpdate ) ) {
4158                 rc = LDAP_INVALID_SYNTAX;
4159                 goto done;
4160         }
4161
4162         normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4163                 + issuer_dn.bv_len + thisUpdate.bv_len;
4164         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4165
4166         p = normalized->bv_val;
4167
4168         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4169         p = lutil_strbvcopy( p, &issuer_dn );
4170         p = lutil_strcopy( p, "\", thisUpdate \"" );
4171         p = lutil_strbvcopy( p, &thisUpdate );
4172         p = lutil_strcopy( p, /*{*/ "\" }" );
4173
4174         rc = LDAP_SUCCESS;
4175
4176 done:
4177         Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4178                 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4179
4180         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4181
4182         return rc;
4183 }
4184
4185 /* X.509 PMI serialNumberAndIssuerSerialCheck
4186
4187 AttributeCertificateExactAssertion     ::= SEQUENCE {
4188    serialNumber              CertificateSerialNumber,
4189    issuer                    AttCertIssuer }
4190
4191 CertificateSerialNumber ::= INTEGER
4192
4193 AttCertIssuer ::=    [0] SEQUENCE {
4194 issuerName                     GeneralNames OPTIONAL,
4195 baseCertificateID         [0] IssuerSerial OPTIONAL,
4196 objectDigestInfo          [1] ObjectDigestInfo OPTIONAL }
4197 -- At least one component shall be present
4198
4199 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4200
4201 GeneralName ::= CHOICE {
4202   otherName                 [0] INSTANCE OF OTHER-NAME,
4203   rfc822Name                [1] IA5String,
4204   dNSName                   [2] IA5String,
4205   x400Address               [3] ORAddress,
4206   directoryName             [4] Name,
4207   ediPartyName              [5] EDIPartyName,
4208   uniformResourceIdentifier [6] IA5String,
4209   iPAddress                 [7] OCTET STRING,
4210   registeredID              [8] OBJECT IDENTIFIER }
4211
4212 IssuerSerial ::= SEQUENCE {
4213    issuer       GeneralNames,
4214    serial       CertificateSerialNumber,
4215    issuerUID UniqueIdentifier OPTIONAL }
4216
4217 ObjectDigestInfo ::= SEQUENCE {
4218    digestedObjectType ENUMERATED {
4219       publicKey           (0),
4220       publicKeyCert       (1),
4221       otherObjectTypes    (2) },
4222    otherObjectTypeID      OBJECT IDENTIFIER OPTIONAL,
4223    digestAlgorithm        AlgorithmIdentifier,
4224    objectDigest           BIT STRING }
4225
4226  * The way I interpret it, an assertion should look like
4227
4228  { serialNumber 'dd'H,
4229    issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4230             baseCertificateID { serial '1d'H,
4231                                 issuer { directoryName:rdnSequence:"cn=zzz" },
4232                                 issuerUID <value>              -- optional
4233                               },                               -- optional
4234             objectDigestInfo { ... }                           -- optional
4235           }
4236  }
4237  
4238  * with issuerName, baseCertificateID and objectDigestInfo optional,
4239  * at least one present; the way it's currently implemented, it is
4240
4241  { serialNumber 'dd'H,
4242    issuer { baseCertificateID { serial '1d'H,
4243                                 issuer { directoryName:rdnSequence:"cn=zzz" }
4244                               }
4245           }
4246  }
4247
4248  * with all the above parts mandatory.
4249  */
4250 static int
4251 serialNumberAndIssuerSerialCheck(
4252         struct berval *in,
4253         struct berval *sn,
4254         struct berval *is,
4255         struct berval *i_sn,    /* contain serial of baseCertificateID */
4256         void *ctx )
4257 {
4258         /* Parse GSER format */ 
4259         enum {
4260                 HAVE_NONE = 0x0,
4261                 HAVE_SN = 0x1,
4262                 HAVE_ISSUER = 0x2,
4263                 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4264         } have = HAVE_NONE, have2 = HAVE_NONE;
4265         int numdquotes = 0;
4266         struct berval x = *in;
4267         struct berval ni;
4268
4269         if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4270
4271         /* no old format */
4272         if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4273
4274         x.bv_val++;
4275         x.bv_len -= 2;
4276
4277         do {
4278
4279                 /* eat leading spaces */
4280                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4281                         /* empty */;
4282                 }
4283
4284                 /* should be at issuer or serialNumber NamedValue */
4285                 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4286                         if ( have & HAVE_ISSUER ) {
4287                                 return LDAP_INVALID_SYNTAX;
4288                         }
4289
4290                         /* parse IssuerSerial */
4291                         x.bv_val += STRLENOF("issuer");
4292                         x.bv_len -= STRLENOF("issuer");
4293
4294                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4295                         x.bv_val++;
4296                         x.bv_len--;
4297
4298                         /* eat leading spaces */
4299                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4300                                 /* empty */;
4301                         }
4302
4303                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4304                         x.bv_val++;
4305                         x.bv_len--;
4306
4307                         /* eat leading spaces */
4308                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4309                                 /* empty */;
4310                         }
4311
4312                         if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4313                                 return LDAP_INVALID_SYNTAX;
4314                         }
4315                         x.bv_val += STRLENOF("baseCertificateID ");
4316                         x.bv_len -= STRLENOF("baseCertificateID ");
4317
4318                         /* eat leading spaces */
4319                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4320                                 /* empty */;
4321                         }
4322
4323                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4324                         x.bv_val++;
4325                         x.bv_len--;
4326
4327                         do {
4328                                 /* eat leading spaces */
4329                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4330                                         /* empty */;
4331                                 }
4332
4333                                 /* parse issuer of baseCertificateID */
4334                                 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4335                                         if ( have2 & HAVE_ISSUER ) {
4336                                                 return LDAP_INVALID_SYNTAX;
4337                                         }
4338
4339                                         x.bv_val += STRLENOF("issuer ");
4340                                         x.bv_len -= STRLENOF("issuer ");
4341
4342                                         /* eat leading spaces */
4343                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4344                                                 /* empty */;
4345                                         }
4346
4347                                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4348                                         x.bv_val++;
4349                                         x.bv_len--;
4350
4351                                         /* eat leading spaces */
4352                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4353                                                 /* empty */;
4354                                         }
4355
4356                                         if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4357                                                 return LDAP_INVALID_SYNTAX;
4358                                         }
4359                                         x.bv_val += STRLENOF("directoryName:rdnSequence:");
4360                                         x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4361
4362                                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4363                                         x.bv_val++;
4364                                         x.bv_len--;
4365
4366                                         is->bv_val = x.bv_val;
4367                                         is->bv_len = 0;
4368
4369                                         for ( ; is->bv_len < x.bv_len; ) {
4370                                                 if ( is->bv_val[is->bv_len] != '"' ) {
4371                                                         is->bv_len++;
4372                                                         continue;
4373                                                 }
4374                                                 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4375                                                         /* double dquote */
4376                                                         is->bv_len += 2;
4377                                                         continue;
4378                                                 }
4379                                                 break;
4380                                         }
4381                                         x.bv_val += is->bv_len + 1;
4382                                         x.bv_len -= is->bv_len + 1;
4383
4384                                         /* eat leading spaces */
4385                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4386                                                 /* empty */;
4387                                         }
4388
4389                                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4390                                         x.bv_val++;
4391                                         x.bv_len--;
4392
4393                                         have2 |= HAVE_ISSUER;
4394
4395                                 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4396                                         if ( have2 & HAVE_SN ) {
4397                                                 return LDAP_INVALID_SYNTAX;
4398                                         }
4399
4400                                         x.bv_val += STRLENOF("serial ");
4401                                         x.bv_len -= STRLENOF("serial ");
4402
4403                                         /* eat leading spaces */
4404                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4405                                                 /* empty */;
4406                                         }
4407
4408                                         if ( checkNum( &x, i_sn ) ) {
4409                                                 return LDAP_INVALID_SYNTAX;
4410                                         }
4411
4412                                         x.bv_val += i_sn->bv_len;
4413                                         x.bv_len -= i_sn->bv_len;
4414
4415                                         have2 |= HAVE_SN;
4416
4417                                 } else {
4418                                         return LDAP_INVALID_SYNTAX;
4419                                 }
4420
4421                                 /* eat leading spaces */
4422                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4423                                         /* empty */;
4424                                 }
4425
4426                                 if ( have2 == HAVE_ALL ) {
4427                                         break;
4428                                 }
4429
4430                                 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4431                                 x.bv_val++;
4432                                 x.bv_len--;
4433                         } while ( 1 );
4434
4435                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4436                         x.bv_val++;
4437                         x.bv_len--;
4438
4439                         /* eat leading spaces */
4440                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4441                                 /* empty */;
4442                         }
4443
4444                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4445                         x.bv_val++;
4446                         x.bv_len--;
4447
4448                         have |= HAVE_ISSUER;
4449
4450                 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4451                         if ( have & HAVE_SN ) {
4452                                 return LDAP_INVALID_SYNTAX;
4453                         }
4454
4455                         /* parse serialNumber */
4456                         x.bv_val += STRLENOF("serialNumber");
4457                         x.bv_len -= STRLENOF("serialNumber");
4458
4459                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4460                         x.bv_val++;
4461                         x.bv_len--;
4462
4463                         /* eat leading spaces */
4464                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4465                                 /* empty */;
4466                         }
4467                         
4468                         if ( checkNum( &x, sn ) ) {
4469                                 return LDAP_INVALID_SYNTAX;
4470                         }
4471
4472                         x.bv_val += sn->bv_len;
4473                         x.bv_len -= sn->bv_len;
4474
4475                         have |= HAVE_SN;
4476
4477                 } else {
4478                         return LDAP_INVALID_SYNTAX;
4479                 }
4480
4481                 /* eat spaces */
4482                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4483                         /* empty */;
4484                 }
4485
4486                 if ( have == HAVE_ALL ) {
4487                         break;
4488                 }
4489
4490                 if ( x.bv_val[0] != ',' ) {
4491                         return LDAP_INVALID_SYNTAX;
4492                 }
4493                 x.bv_val++ ;
4494                 x.bv_len--;
4495         } while ( 1 );
4496
4497         /* should have no characters left... */
4498         if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4499
4500         if ( numdquotes == 0 ) {
4501                 ber_dupbv_x( &ni, is, ctx );
4502
4503         } else {
4504                 ber_len_t src, dst;
4505
4506                 ni.bv_len = is->bv_len - numdquotes;
4507                 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4508                 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4509                         if ( is->bv_val[src] == '"' ) {
4510                                 src++;
4511                         }
4512                         ni.bv_val[dst] = is->bv_val[src];
4513                 }
4514                 ni.bv_val[dst] = '\0';
4515         }
4516
4517         *is = ni;
4518
4519         /* need to handle double dquotes here */
4520         return 0;
4521 }
4522
4523 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4524 static int
4525 serialNumberAndIssuerSerialValidate(
4526         Syntax *syntax,
4527         struct berval *in )
4528 {
4529         int rc;
4530         struct berval sn, i, i_sn;
4531
4532         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4533                 in->bv_val, 0, 0 );
4534
4535         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4536         if ( rc ) {
4537                 goto done;
4538         }
4539
4540         /* validate DN -- doesn't handle double dquote */ 
4541         rc = dnValidate( NULL, &i );
4542         if ( rc ) {
4543                 rc = LDAP_INVALID_SYNTAX;
4544         }
4545
4546         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4547                 slap_sl_free( i.bv_val, NULL );
4548         }
4549
4550 done:;
4551         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4552                 in->bv_val, rc, 0 );
4553
4554         return rc;
4555 }
4556
4557 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4558 static int
4559 serialNumberAndIssuerSerialPretty(
4560         Syntax *syntax,
4561         struct berval *in,
4562         struct berval *out,
4563         void *ctx )
4564 {
4565         struct berval sn, i, i_sn, ni = BER_BVNULL;
4566         char *p;
4567         int rc;
4568
4569         assert( in != NULL );
4570         assert( out != NULL );
4571
4572         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4573                 in->bv_val, 0, 0 );
4574
4575         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4576         if ( rc ) {
4577                 goto done;
4578         }
4579
4580         rc = dnPretty( syntax, &i, &ni, ctx );
4581
4582         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4583                 slap_sl_free( i.bv_val, ctx );
4584         }
4585
4586         if ( rc ) {
4587                 rc = LDAP_INVALID_SYNTAX;
4588                 goto done;
4589         }
4590
4591         /* make room from sn + "$" */
4592         out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
4593                 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4594         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4595
4596         if ( out->bv_val == NULL ) {
4597                 out->bv_len = 0;
4598                 rc = LDAP_OTHER;
4599                 goto done;
4600         }
4601
4602         p = out->bv_val;
4603         p = lutil_strcopy( p, "{ serialNumber " );
4604         p = lutil_strbvcopy( p, &sn );
4605         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4606         p = lutil_strbvcopy( p, &ni );
4607         p = lutil_strcopy( p, "\" }, serial " );
4608         p = lutil_strbvcopy( p, &i_sn );
4609         p = lutil_strcopy( p, " } } }" );
4610
4611         assert( p == &out->bv_val[out->bv_len] );
4612
4613 done:;
4614         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4615                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4616
4617         slap_sl_free( ni.bv_val, ctx );
4618
4619         return rc; 
4620 }
4621
4622 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4623 /*
4624  * This routine is called by attributeCertificateExactNormalize
4625  * when attributeCertificateExactNormalize receives a search 
4626  * string instead of a attribute certificate. This routine 
4627  * checks if the search value is valid and then returns the 
4628  * normalized value
4629  */
4630 static int
4631 serialNumberAndIssuerSerialNormalize(
4632         slap_mask_t usage,
4633         Syntax *syntax,
4634         MatchingRule *mr,
4635         struct berval *in,
4636         struct berval *out,
4637         void *ctx )
4638 {
4639         struct berval i, ni = BER_BVNULL,
4640                 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4641                 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4642         char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4643                 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4644         char *p;
4645         int rc;
4646
4647         assert( in != NULL );
4648         assert( out != NULL );
4649
4650         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4651                 in->bv_val, 0, 0 );
4652
4653         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4654         if ( rc ) {
4655                 goto func_leave;
4656         }
4657
4658         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4659
4660         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4661                 slap_sl_free( i.bv_val, ctx );
4662         }
4663
4664         if ( rc ) {
4665                 rc = LDAP_INVALID_SYNTAX;
4666                 goto func_leave;
4667         }
4668
4669         /* Convert sn to canonical hex */
4670         sn2.bv_val = sbuf2;
4671         sn2.bv_len = sn.bv_len;
4672         if ( sn.bv_len > sizeof( sbuf2 ) ) {
4673                 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4674         }
4675         if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4676                 rc = LDAP_INVALID_SYNTAX;
4677                 goto func_leave;
4678         }
4679
4680         /* Convert i_sn to canonical hex */
4681         i_sn2.bv_val = i_sbuf2;
4682         i_sn2.bv_len = i_sn.bv_len;
4683         if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4684                 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4685         }
4686         if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4687                 rc = LDAP_INVALID_SYNTAX;
4688                 goto func_leave;
4689         }
4690
4691         sn3.bv_val = sbuf3;
4692         sn3.bv_len = sizeof(sbuf3);
4693         if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4694                 rc = LDAP_INVALID_SYNTAX;
4695                 goto func_leave;
4696         }
4697
4698         i_sn3.bv_val = i_sbuf3;
4699         i_sn3.bv_len = sizeof(i_sbuf3);
4700         if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4701                 rc = LDAP_INVALID_SYNTAX;
4702                 goto func_leave;
4703         }
4704
4705         out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
4706                 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4707         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4708
4709         if ( out->bv_val == NULL ) {
4710                 out->bv_len = 0;
4711                 rc = LDAP_OTHER;
4712                 goto func_leave;
4713         }
4714
4715         p = out->bv_val;
4716
4717         p = lutil_strcopy( p, "{ serialNumber " );
4718         p = lutil_strbvcopy( p, &sn3 );
4719         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4720         p = lutil_strbvcopy( p, &ni );
4721         p = lutil_strcopy( p, "\" }, serial " );
4722         p = lutil_strbvcopy( p, &i_sn3 );
4723         p = lutil_strcopy( p, " } } }" );
4724
4725         assert( p == &out->bv_val[out->bv_len] );
4726
4727 func_leave:
4728         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4729                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4730
4731         if ( sn2.bv_val != sbuf2 ) {
4732                 slap_sl_free( sn2.bv_val, ctx );
4733         }
4734
4735         if ( i_sn2.bv_val != i_sbuf2 ) {
4736                 slap_sl_free( i_sn2.bv_val, ctx );
4737         }
4738
4739         if ( sn3.bv_val != sbuf3 ) {
4740                 slap_sl_free( sn3.bv_val, ctx );
4741         }
4742
4743         if ( i_sn3.bv_val != i_sbuf3 ) {
4744                 slap_sl_free( i_sn3.bv_val, ctx );
4745         }
4746
4747         slap_sl_free( ni.bv_val, ctx );
4748
4749         return rc;
4750 }
4751
4752 /* X.509 PMI attributeCertificateExactNormalize */
4753 static int
4754 attributeCertificateExactNormalize(
4755         slap_mask_t usage,
4756         Syntax *syntax,
4757         MatchingRule *mr,
4758         struct berval *val,
4759         struct berval *normalized,
4760         void *ctx )
4761 {
4762         BerElementBuffer berbuf;
4763         BerElement *ber = (BerElement *)&berbuf;
4764         ber_tag_t tag;
4765         ber_len_t len;
4766         char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4767         struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL;
4768         struct berval issuer_dn = BER_BVNULL, bvdn;
4769         char *p;
4770         int rc = LDAP_INVALID_SYNTAX;
4771
4772         if ( BER_BVISEMPTY( val ) ) {
4773                 return rc;
4774         }
4775
4776         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4777                 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4778         }
4779
4780         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4781
4782         ber_init2( ber, val, LBER_USE_DER );
4783         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
4784         tag = ber_skip_tag( ber, &len );        /* Sequence */
4785         tag = ber_skip_tag( ber, &len );        /* (Mandatory) version; must be v2(1) */
4786         ber_skip_data( ber, len );
4787         tag = ber_skip_tag( ber, &len );        /* Holder Sequence */
4788         ber_skip_data( ber, len );
4789
4790         /* Issuer */
4791         tag = ber_skip_tag( ber, &len );        /* Sequence */
4792                                                 /* issuerName (GeneralNames sequence; optional)? */
4793         tag = ber_skip_tag( ber, &len );        /* baseCertificateID (sequence; optional)? */
4794         tag = ber_skip_tag( ber, &len );        /* GeneralNames (sequence) */
4795         tag = ber_skip_tag( ber, &len );        /* directoryName (we only accept this form of GeneralName) */
4796         if ( tag != SLAP_X509_GN_DIRECTORYNAME ) { 
4797                 return LDAP_INVALID_SYNTAX; 
4798         }
4799         tag = ber_peek_tag( ber, &len );        /* sequence of RDN */
4800         len = ber_ptrlen( ber );
4801         bvdn.bv_val = val->bv_val + len;
4802         bvdn.bv_len = val->bv_len - len;
4803         rc = dnX509normalize( &bvdn, &issuer_dn );
4804         if ( rc != LDAP_SUCCESS ) goto done;
4805         
4806         tag = ber_skip_tag( ber, &len );        /* sequence of RDN */
4807         ber_skip_data( ber, len ); 
4808         tag = ber_skip_tag( ber, &len );        /* serial number */
4809         if ( tag != LBER_INTEGER ) {
4810                 rc = LDAP_INVALID_SYNTAX; 
4811                 goto done;
4812         }
4813         i_sn.bv_val = (char *)ber->ber_ptr;
4814         i_sn.bv_len = len;
4815         i_sn2.bv_val = issuer_serialbuf;
4816         i_sn2.bv_len = sizeof(issuer_serialbuf);
4817         if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4818                 rc = LDAP_INVALID_SYNTAX;
4819                 goto done;
4820         }
4821         ber_skip_data( ber, len );
4822
4823                                                 /* issuerUID (bitstring; optional)? */
4824                                                 /* objectDigestInfo (sequence; optional)? */
4825
4826         tag = ber_skip_tag( ber, &len );        /* Signature (sequence) */
4827         ber_skip_data( ber, len );
4828         tag = ber_skip_tag( ber, &len );        /* serial number */ 
4829         if ( tag != LBER_INTEGER ) {
4830                 rc = LDAP_INVALID_SYNTAX; 
4831                 goto done;
4832         }
4833         sn.bv_val = (char *)ber->ber_ptr;
4834         sn.bv_len = len;
4835         sn2.bv_val = serialbuf;
4836         sn2.bv_len = sizeof(serialbuf);
4837         if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4838                 rc = LDAP_INVALID_SYNTAX;
4839                 goto done;
4840         }
4841         ber_skip_data( ber, len );
4842
4843         normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }" )
4844                 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4845         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4846
4847         p = normalized->bv_val;
4848
4849         p = lutil_strcopy( p, "{ serialNumber " );
4850         p = lutil_strbvcopy( p, &sn2 );
4851         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4852         p = lutil_strbvcopy( p, &issuer_dn );
4853         p = lutil_strcopy( p, "\" }, serial " );
4854         p = lutil_strbvcopy( p, &i_sn2 );
4855         p = lutil_strcopy( p, " } } }" );
4856
4857         Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4858                 normalized->bv_val, NULL, NULL );
4859
4860         rc = LDAP_SUCCESS;
4861
4862 done:
4863         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4864         if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4865         if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4866
4867         return rc;
4868 }
4869
4870
4871 static int
4872 hexValidate(
4873         Syntax *syntax,
4874         struct berval *in )
4875 {
4876         ber_len_t       i;
4877
4878         assert( in != NULL );
4879         assert( !BER_BVISNULL( in ) );
4880
4881         for ( i = 0; i < in->bv_len; i++ ) {
4882                 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4883                         return LDAP_INVALID_SYNTAX;
4884                 }
4885         }
4886
4887         return LDAP_SUCCESS;
4888 }
4889
4890 /* Normalize a SID as used inside a CSN:
4891  * three-digit numeric string */
4892 static int
4893 hexNormalize(
4894         slap_mask_t usage,
4895         Syntax *syntax,
4896         MatchingRule *mr,
4897         struct berval *val,
4898         struct berval *normalized,
4899         void *ctx )
4900 {
4901         ber_len_t       i;
4902
4903         assert( val != NULL );
4904         assert( normalized != NULL );
4905
4906         ber_dupbv_x( normalized, val, ctx );
4907
4908         for ( i = 0; i < normalized->bv_len; i++ ) {
4909                 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
4910                         ber_memfree_x( normalized->bv_val, ctx );
4911                         BER_BVZERO( normalized );
4912                         return LDAP_INVALID_SYNTAX;
4913                 }
4914
4915                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
4916         }
4917
4918         return LDAP_SUCCESS;
4919 }
4920
4921 static int
4922 sidValidate (
4923         Syntax *syntax,
4924         struct berval *in )
4925 {
4926         assert( in != NULL );
4927         assert( !BER_BVISNULL( in ) );
4928
4929         if ( in->bv_len != 3 ) {
4930                 return LDAP_INVALID_SYNTAX;
4931         }
4932
4933         return hexValidate( NULL, in );
4934 }
4935
4936 /* Normalize a SID as used inside a CSN:
4937  * three-digit numeric string */
4938 static int
4939 sidNormalize(
4940         slap_mask_t usage,
4941         Syntax *syntax,
4942         MatchingRule *mr,
4943         struct berval *val,
4944         struct berval *normalized,
4945         void *ctx )
4946 {
4947         if ( val->bv_len != 3 ) {
4948                 return LDAP_INVALID_SYNTAX;
4949         }
4950
4951         return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
4952 }
4953
4954 static int
4955 sidPretty(
4956         Syntax *syntax,
4957         struct berval *val,
4958         struct berval *out,
4959         void *ctx )
4960 {
4961         return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
4962 }
4963
4964 /* Normalize a SID as used inside a CSN, either as-is
4965  * (assertion value) or extracted from the CSN
4966  * (attribute value) */
4967 static int
4968 csnSidNormalize(
4969         slap_mask_t usage,
4970         Syntax *syntax,
4971         MatchingRule *mr,
4972         struct berval *val,
4973         struct berval *normalized,
4974         void *ctx )
4975 {
4976         struct berval   bv;
4977         char            *ptr,
4978                         buf[ 4 ];
4979
4980
4981         if ( BER_BVISEMPTY( val ) ) {
4982                 return LDAP_INVALID_SYNTAX;
4983         }
4984
4985         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4986                 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
4987         }
4988
4989         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4990
4991         ptr = ber_bvchr( val, '#' );
4992         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4993                 return LDAP_INVALID_SYNTAX;
4994         }
4995
4996         bv.bv_val = ptr + 1;
4997         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
4998
4999         ptr = ber_bvchr( &bv, '#' );
5000         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5001                 return LDAP_INVALID_SYNTAX;
5002         }
5003
5004         bv.bv_val = ptr + 1;
5005         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5006                 
5007         ptr = ber_bvchr( &bv, '#' );
5008         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5009                 return LDAP_INVALID_SYNTAX;
5010         }
5011
5012         bv.bv_len = ptr - bv.bv_val;
5013
5014         if ( bv.bv_len == 2 ) {
5015                 /* OpenLDAP 2.3 SID */
5016                 buf[ 0 ] = '0';
5017                 buf[ 1 ] = bv.bv_val[ 0 ];
5018                 buf[ 2 ] = bv.bv_val[ 1 ];
5019                 buf[ 3 ] = '\0';
5020
5021                 bv.bv_val = buf;
5022                 bv.bv_len = 3;
5023         }
5024
5025         return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
5026 }
5027
5028 static int
5029 csnValidate(
5030         Syntax *syntax,
5031         struct berval *in )
5032 {
5033         struct berval   bv;
5034         char            *ptr;
5035         int             rc;
5036
5037         assert( in != NULL );
5038         assert( !BER_BVISNULL( in ) );
5039
5040         if ( BER_BVISEMPTY( in ) ) {
5041                 return LDAP_INVALID_SYNTAX;
5042         }
5043
5044         bv = *in;
5045
5046         ptr = ber_bvchr( &bv, '#' );
5047         if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
5048                 return LDAP_INVALID_SYNTAX;
5049         }
5050
5051         bv.bv_len = ptr - bv.bv_val;
5052         if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
5053                 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
5054         {
5055                 return LDAP_INVALID_SYNTAX;
5056         }
5057
5058         rc = generalizedTimeValidate( NULL, &bv );
5059         if ( rc != LDAP_SUCCESS ) {
5060                 return rc;
5061         }
5062
5063         bv.bv_val = ptr + 1;
5064         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5065
5066         ptr = ber_bvchr( &bv, '#' );
5067         if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5068                 return LDAP_INVALID_SYNTAX;
5069         }
5070
5071         bv.bv_len = ptr - bv.bv_val;
5072         if ( bv.bv_len != 6 ) {
5073                 return LDAP_INVALID_SYNTAX;
5074         }
5075
5076         rc = hexValidate( NULL, &bv );
5077         if ( rc != LDAP_SUCCESS ) {
5078                 return rc;
5079         }
5080
5081         bv.bv_val = ptr + 1;
5082         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5083
5084         ptr = ber_bvchr( &bv, '#' );
5085         if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5086                 return LDAP_INVALID_SYNTAX;
5087         }
5088
5089         bv.bv_len = ptr - bv.bv_val;
5090         if ( bv.bv_len == 2 ) {
5091                 /* tolerate old 2-digit replica-id */
5092                 rc = hexValidate( NULL, &bv );
5093
5094         } else {
5095                 rc = sidValidate( NULL, &bv );
5096         }
5097         if ( rc != LDAP_SUCCESS ) {
5098                 return rc;
5099         }
5100
5101         bv.bv_val = ptr + 1;
5102         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5103
5104         if ( bv.bv_len != 6 ) {
5105                 return LDAP_INVALID_SYNTAX;
5106         }
5107
5108         return hexValidate( NULL, &bv );
5109 }
5110
5111 /* Normalize a CSN in OpenLDAP 2.1 format */
5112 static int
5113 csnNormalize21(
5114         slap_mask_t usage,
5115         Syntax *syntax,
5116         MatchingRule *mr,
5117         struct berval *val,
5118         struct berval *normalized,
5119         void *ctx )
5120 {
5121         struct berval   gt, cnt, sid, mod;
5122         struct berval   bv;
5123         char            buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5124         char            *ptr;
5125         ber_len_t       i;
5126
5127         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5128         assert( !BER_BVISEMPTY( val ) );
5129
5130         gt = *val;
5131
5132         ptr = ber_bvchr( &gt, '#' );
5133         if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
5134                 return LDAP_INVALID_SYNTAX;
5135         }
5136
5137         gt.bv_len = ptr - gt.bv_val;
5138         if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5139                 return LDAP_INVALID_SYNTAX;
5140         }
5141
5142         if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5143                 return LDAP_INVALID_SYNTAX;
5144         }
5145
5146         cnt.bv_val = ptr + 1;
5147         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5148
5149         ptr = ber_bvchr( &cnt, '#' );
5150         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5151                 return LDAP_INVALID_SYNTAX;
5152         }
5153
5154         cnt.bv_len = ptr - cnt.bv_val;
5155         if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5156                 return LDAP_INVALID_SYNTAX;
5157         }
5158
5159         if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5160                 return LDAP_INVALID_SYNTAX;
5161         }
5162
5163         cnt.bv_val += STRLENOF( "0x" );
5164         cnt.bv_len -= STRLENOF( "0x" );
5165
5166         sid.bv_val = ptr + 1;
5167         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5168                 
5169         ptr = ber_bvchr( &sid, '#' );
5170         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5171                 return LDAP_INVALID_SYNTAX;
5172         }
5173
5174         sid.bv_len = ptr - sid.bv_val;
5175         if ( sid.bv_len != STRLENOF( "0" ) ) {
5176                 return LDAP_INVALID_SYNTAX;
5177         }
5178
5179         mod.bv_val = ptr + 1;
5180         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5181         if ( mod.bv_len != STRLENOF( "0000" ) ) {
5182                 return LDAP_INVALID_SYNTAX;
5183         }
5184
5185         bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5186         bv.bv_val = buf;
5187
5188         ptr = bv.bv_val;
5189         ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5190         ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5191                 STRLENOF( "MM" ) );
5192         ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5193                 STRLENOF( "SS" ) );
5194         ptr = lutil_strcopy( ptr, ".000000Z#00" );
5195         ptr = lutil_strbvcopy( ptr, &cnt );
5196         *ptr++ = '#';
5197         *ptr++ = '0';
5198         *ptr++ = '0';
5199         *ptr++ = sid.bv_val[ 0 ];
5200         *ptr++ = '#';
5201         *ptr++ = '0';
5202         *ptr++ = '0';
5203         for ( i = 0; i < mod.bv_len; i++ ) {
5204                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5205         }
5206         *ptr = '\0';
5207
5208         assert( ptr == &bv.bv_val[bv.bv_len] );
5209
5210         if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5211                 return LDAP_INVALID_SYNTAX;
5212         }
5213
5214         ber_dupbv_x( normalized, &bv, ctx );
5215
5216         return LDAP_SUCCESS;
5217 }
5218
5219 /* Normalize a CSN in OpenLDAP 2.3 format */
5220 static int
5221 csnNormalize23(
5222         slap_mask_t usage,
5223         Syntax *syntax,
5224         MatchingRule *mr,
5225         struct berval *val,
5226         struct berval *normalized,
5227         void *ctx )
5228 {
5229         struct berval   gt, cnt, sid, mod;
5230         struct berval   bv;
5231         char            buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5232         char            *ptr;
5233         ber_len_t       i;
5234
5235         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5236         assert( !BER_BVISEMPTY( val ) );
5237
5238         gt = *val;
5239
5240         ptr = ber_bvchr( &gt, '#' );
5241         if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
5242                 return LDAP_INVALID_SYNTAX;
5243         }
5244
5245         gt.bv_len = ptr - gt.bv_val;
5246         if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5247                 return LDAP_INVALID_SYNTAX;
5248         }
5249
5250         cnt.bv_val = ptr + 1;
5251         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5252
5253         ptr = ber_bvchr( &cnt, '#' );
5254         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5255                 return LDAP_INVALID_SYNTAX;
5256         }
5257
5258         cnt.bv_len = ptr - cnt.bv_val;
5259         if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5260                 return LDAP_INVALID_SYNTAX;
5261         }
5262
5263         sid.bv_val = ptr + 1;
5264         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5265                 
5266         ptr = ber_bvchr( &sid, '#' );
5267         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5268                 return LDAP_INVALID_SYNTAX;
5269         }
5270
5271         sid.bv_len = ptr - sid.bv_val;
5272         if ( sid.bv_len != STRLENOF( "00" ) ) {
5273                 return LDAP_INVALID_SYNTAX;
5274         }
5275
5276         mod.bv_val = ptr + 1;
5277         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5278         if ( mod.bv_len != STRLENOF( "000000" ) ) {
5279                 return LDAP_INVALID_SYNTAX;
5280         }
5281
5282         bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5283         bv.bv_val = buf;
5284
5285         ptr = bv.bv_val;
5286         ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5287         ptr = lutil_strcopy( ptr, ".000000Z#" );
5288         ptr = lutil_strbvcopy( ptr, &cnt );
5289         *ptr++ = '#';
5290         *ptr++ = '0';
5291         for ( i = 0; i < sid.bv_len; i++ ) {
5292                 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5293         }
5294         *ptr++ = '#';
5295         for ( i = 0; i < mod.bv_len; i++ ) {
5296                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5297         }
5298         *ptr = '\0';
5299
5300         assert( ptr == &bv.bv_val[bv.bv_len] );
5301         if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5302                 return LDAP_INVALID_SYNTAX;
5303         }
5304
5305         ber_dupbv_x( normalized, &bv, ctx );
5306
5307         return LDAP_SUCCESS;
5308 }
5309
5310 /* Normalize a CSN */
5311 static int
5312 csnNormalize(
5313         slap_mask_t usage,
5314         Syntax *syntax,
5315         MatchingRule *mr,
5316         struct berval *val,
5317         struct berval *normalized,
5318         void *ctx )
5319 {
5320         struct berval   cnt, sid, mod;
5321         char            *ptr;
5322         ber_len_t       i;
5323
5324         assert( val != NULL );
5325         assert( normalized != NULL );
5326
5327         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5328
5329         if ( BER_BVISEMPTY( val ) ) {
5330                 return LDAP_INVALID_SYNTAX;
5331         }
5332
5333         if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5334                 /* Openldap <= 2.3 */
5335
5336                 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5337         }
5338
5339         if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5340                 /* Openldap 2.1 */
5341
5342                 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5343         }
5344
5345         if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5346                 return LDAP_INVALID_SYNTAX;
5347         }
5348
5349         ptr = ber_bvchr( val, '#' );
5350         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5351                 return LDAP_INVALID_SYNTAX;
5352         }
5353
5354         if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5355                 return LDAP_INVALID_SYNTAX;
5356         }
5357
5358         cnt.bv_val = ptr + 1;
5359         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5360
5361         ptr = ber_bvchr( &cnt, '#' );
5362         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5363                 return LDAP_INVALID_SYNTAX;
5364         }
5365
5366         if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5367                 return LDAP_INVALID_SYNTAX;
5368         }
5369
5370         sid.bv_val = ptr + 1;
5371         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5372                 
5373         ptr = ber_bvchr( &sid, '#' );
5374         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5375                 return LDAP_INVALID_SYNTAX;
5376         }
5377
5378         sid.bv_len = ptr - sid.bv_val;
5379         if ( sid.bv_len != STRLENOF( "000" ) ) {
5380                 return LDAP_INVALID_SYNTAX;
5381         }
5382
5383         mod.bv_val = ptr + 1;
5384         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5385
5386         if ( mod.bv_len != STRLENOF( "000000" ) ) {
5387                 return LDAP_INVALID_SYNTAX;
5388         }
5389
5390         ber_dupbv_x( normalized, val, ctx );
5391
5392         for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5393                 i < normalized->bv_len; i++ )
5394         {
5395                 /* assume it's already validated that's all hex digits */
5396                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5397         }
5398
5399         return LDAP_SUCCESS;
5400 }
5401
5402 static int
5403 csnPretty(
5404         Syntax *syntax,
5405         struct berval *val,
5406         struct berval *out,
5407         void *ctx )
5408 {
5409         return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5410 }
5411
5412 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5413 /* slight optimization - does not need the start parameter */
5414 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5415 enum { start = 0 };
5416 #endif
5417
5418 static int
5419 check_time_syntax (struct berval *val,
5420         int start,
5421         int *parts,
5422         struct berval *fraction)
5423 {
5424         /*
5425          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5426          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
5427          * GeneralizedTime supports leap seconds, UTCTime does not.
5428          */
5429         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5430         static const int mdays[2][12] = {
5431                 /* non-leap years */
5432                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5433                 /* leap years */
5434                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5435         };
5436         char *p, *e;
5437         int part, c, c1, c2, tzoffset, leapyear = 0;
5438
5439         p = val->bv_val;
5440         e = p + val->bv_len;
5441
5442 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5443         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5444 #endif
5445         for (part = start; part < 7 && p < e; part++) {
5446                 c1 = *p;
5447                 if (!ASCII_DIGIT(c1)) {
5448                         break;
5449                 }
5450                 p++;
5451                 if (p == e) {
5452                         return LDAP_INVALID_SYNTAX;
5453                 }
5454                 c = *p++;
5455                 if (!ASCII_DIGIT(c)) {
5456                         return LDAP_INVALID_SYNTAX;
5457                 }
5458                 c += c1 * 10 - '0' * 11;
5459                 if ((part | 1) == 3) {
5460                         --c;
5461                         if (c < 0) {
5462                                 return LDAP_INVALID_SYNTAX;
5463                         }
5464                 }
5465                 if (c >= ceiling[part]) {
5466                         if (! (c == 60 && part == 6 && start == 0))
5467                                 return LDAP_INVALID_SYNTAX;
5468                 }
5469                 parts[part] = c;
5470         }
5471         if (part < 5 + start) {
5472                 return LDAP_INVALID_SYNTAX;
5473         }
5474         for (; part < 9; part++) {
5475                 parts[part] = 0;
5476         }
5477
5478         /* leapyear check for the Gregorian calendar (year>1581) */
5479         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5480                 leapyear = 1;
5481         }
5482
5483         if (parts[3] >= mdays[leapyear][parts[2]]) {
5484                 return LDAP_INVALID_SYNTAX;
5485         }
5486
5487         if (start == 0) {
5488                 fraction->bv_val = p;
5489                 fraction->bv_len = 0;
5490                 if (p < e && (*p == '.' || *p == ',')) {
5491                         char *end_num;
5492                         while (++p < e && ASCII_DIGIT(*p)) {
5493                                 /* EMTPY */;
5494                         }
5495                         if (p - fraction->bv_val == 1) {
5496                                 return LDAP_INVALID_SYNTAX;
5497                         }
5498                         for (end_num = p; end_num[-1] == '0'; --end_num) {
5499                                 /* EMPTY */;
5500                         }
5501                         c = end_num - fraction->bv_val;
5502                         if (c != 1) fraction->bv_len = c;
5503                 }
5504         }
5505
5506         if (p == e) {
5507                 /* no time zone */
5508                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5509         }
5510
5511         tzoffset = *p++;
5512         switch (tzoffset) {
5513         default:
5514                 return LDAP_INVALID_SYNTAX;
5515         case 'Z':
5516                 /* UTC */
5517                 break;
5518         case '+':
5519         case '-':
5520                 for (part = 7; part < 9 && p < e; part++) {
5521                         c1 = *p;
5522                         if (!ASCII_DIGIT(c1)) {
5523                                 break;
5524                         }
5525                         p++;
5526                         if (p == e) {
5527                                 return LDAP_INVALID_SYNTAX;
5528                         }
5529                         c2 = *p++;
5530                         if (!ASCII_DIGIT(c2)) {
5531                                 return LDAP_INVALID_SYNTAX;
5532                         }
5533                         parts[part] = c1 * 10 + c2 - '0' * 11;
5534                         if (parts[part] >= ceiling[part]) {
5535                                 return LDAP_INVALID_SYNTAX;
5536                         }
5537                 }
5538                 if (part < 8 + start) {
5539                         return LDAP_INVALID_SYNTAX;
5540                 }
5541
5542                 if (tzoffset == '-') {
5543                         /* negative offset to UTC, ie west of Greenwich */
5544                         parts[4] += parts[7];
5545                         parts[5] += parts[8];
5546                         /* offset is just hhmm, no seconds */
5547                         for (part = 6; --part >= 0; ) {
5548                                 if (part != 3) {
5549                                         c = ceiling[part];
5550                                 } else {
5551                                         c = mdays[leapyear][parts[2]];
5552                                 }
5553                                 if (parts[part] >= c) {
5554                                         if (part == 0) {
5555                                                 return LDAP_INVALID_SYNTAX;
5556                                         }
5557                                         parts[part] -= c;
5558                                         parts[part - 1]++;
5559                                         continue;
5560                                 } else if (part != 5) {
5561                                         break;
5562                                 }
5563                         }
5564                 } else {
5565                         /* positive offset to UTC, ie east of Greenwich */
5566                         parts[4] -= parts[7];
5567                         parts[5] -= parts[8];
5568                         for (part = 6; --part >= 0; ) {
5569                                 if (parts[part] < 0) {
5570                                         if (part == 0) {
5571                                                 return LDAP_INVALID_SYNTAX;
5572                                         }
5573                                         if (part != 3) {
5574                                                 c = ceiling[part];
5575                                         } else {
5576                                                 /* make first arg to % non-negative */
5577                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5578                                         }
5579                                         parts[part] += c;
5580                                         parts[part - 1]--;
5581                                         continue;
5582                                 } else if (part != 5) {
5583                                         break;
5584                                 }
5585                         }
5586                 }
5587         }
5588
5589         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5590 }
5591
5592 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5593
5594 #if 0
5595 static int
5596 xutcTimeNormalize(
5597         Syntax *syntax,
5598         struct berval *val,
5599         struct berval *normalized )
5600 {
5601         int parts[9], rc;
5602
5603         rc = check_time_syntax(val, 1, parts, NULL);
5604         if (rc != LDAP_SUCCESS) {
5605                 return rc;
5606         }
5607
5608         normalized->bv_val = ch_malloc( 14 );
5609         if ( normalized->bv_val == NULL ) {
5610                 return LBER_ERROR_MEMORY;
5611         }
5612
5613         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5614                 parts[1], parts[2] + 1, parts[3] + 1,
5615                 parts[4], parts[5], parts[6] );
5616         normalized->bv_len = 13;
5617
5618         return LDAP_SUCCESS;
5619 }
5620 #endif /* 0 */
5621
5622 static int
5623 utcTimeValidate(
5624         Syntax *syntax,
5625         struct berval *in )
5626 {
5627         int parts[9];
5628         return check_time_syntax(in, 1, parts, NULL);
5629 }
5630
5631 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5632
5633 static int
5634 generalizedTimeValidate(
5635         Syntax *syntax,
5636         struct berval *in )
5637 {
5638         int parts[9];
5639         struct berval fraction;
5640         return check_time_syntax(in, 0, parts, &fraction);
5641 }
5642
5643 static int
5644 generalizedTimeNormalize(
5645         slap_mask_t usage,
5646         Syntax *syntax,
5647         MatchingRule *mr,
5648         struct berval *val,
5649         struct berval *normalized,
5650         void *ctx )
5651 {
5652         int parts[9], rc;
5653         unsigned int len;
5654         struct berval fraction;
5655
5656         rc = check_time_syntax(val, 0, parts, &fraction);
5657         if (rc != LDAP_SUCCESS) {
5658                 return rc;
5659         }
5660
5661         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5662         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5663         if ( BER_BVISNULL( normalized ) ) {
5664                 return LBER_ERROR_MEMORY;
5665         }
5666
5667         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5668                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5669                 parts[4], parts[5], parts[6] );
5670         if ( !BER_BVISEMPTY( &fraction ) ) {
5671                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5672                         fraction.bv_val, fraction.bv_len );
5673                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5674         }
5675         strcpy( normalized->bv_val + len-1, "Z" );
5676         normalized->bv_len = len;
5677
5678         return LDAP_SUCCESS;
5679 }
5680
5681 static int
5682 generalizedTimeOrderingMatch(
5683         int *matchp,
5684         slap_mask_t flags,
5685         Syntax *syntax,
5686         MatchingRule *mr,
5687         struct berval *value,
5688         void *assertedValue )
5689 {
5690         struct berval *asserted = (struct berval *) assertedValue;
5691         ber_len_t v_len  = value->bv_len;
5692         ber_len_t av_len = asserted->bv_len;
5693
5694         /* ignore trailing 'Z' when comparing */
5695         int match = memcmp( value->bv_val, asserted->bv_val,
5696                 (v_len < av_len ? v_len : av_len) - 1 );
5697         if ( match == 0 ) match = v_len - av_len;
5698
5699         /* If used in extensible match filter, match if value < asserted */
5700         if ( flags & SLAP_MR_EXT )
5701                 match = (match >= 0);
5702
5703         *matchp = match;
5704         return LDAP_SUCCESS;
5705 }
5706
5707 /* Index generation function: Ordered index */
5708 int generalizedTimeIndexer(
5709         slap_mask_t use,
5710         slap_mask_t flags,
5711         Syntax *syntax,
5712         MatchingRule *mr,
5713         struct berval *prefix,
5714         BerVarray values,
5715         BerVarray *keysp,
5716         void *ctx )
5717 {
5718         int i, j;
5719         BerVarray keys;
5720         char tmp[5];
5721         BerValue bvtmp; /* 40 bit index */
5722         struct lutil_tm tm;
5723         struct lutil_timet tt;
5724
5725         bvtmp.bv_len = sizeof(tmp);
5726         bvtmp.bv_val = tmp;
5727         for( i=0; values[i].bv_val != NULL; i++ ) {
5728                 /* just count them */
5729         }
5730
5731         /* we should have at least one value at this point */
5732         assert( i > 0 );
5733
5734         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5735
5736         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5737         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5738                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5739                 /* Use 40 bits of time for key */
5740                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5741                         lutil_tm2time( &tm, &tt );
5742                         tmp[0] = tt.tt_gsec & 0xff;
5743                         tmp[4] = tt.tt_sec & 0xff;
5744                         tt.tt_sec >>= 8;
5745                         tmp[3] = tt.tt_sec & 0xff;
5746                         tt.tt_sec >>= 8;
5747                         tmp[2] = tt.tt_sec & 0xff;
5748                         tt.tt_sec >>= 8;
5749                         tmp[1] = tt.tt_sec & 0xff;
5750                         
5751                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5752                 }
5753         }
5754
5755         keys[j].bv_val = NULL;
5756         keys[j].bv_len = 0;
5757
5758         *keysp = keys;
5759
5760         return LDAP_SUCCESS;
5761 }
5762
5763 /* Index generation function: Ordered index */
5764 int generalizedTimeFilter(
5765         slap_mask_t use,
5766         slap_mask_t flags,
5767         Syntax *syntax,
5768         MatchingRule *mr,
5769         struct berval *prefix,
5770         void * assertedValue,
5771         BerVarray *keysp,
5772         void *ctx )
5773 {
5774         BerVarray keys;
5775         char tmp[5];
5776         BerValue bvtmp; /* 40 bit index */
5777         BerValue *value = (BerValue *) assertedValue;
5778         struct lutil_tm tm;
5779         struct lutil_timet tt;
5780         
5781         bvtmp.bv_len = sizeof(tmp);
5782         bvtmp.bv_val = tmp;
5783         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5784         /* Use 40 bits of time for key */
5785         if ( value->bv_val && value->bv_len >= 10 &&
5786                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5787
5788                 lutil_tm2time( &tm, &tt );
5789                 tmp[0] = tt.tt_gsec & 0xff;
5790                 tmp[4] = tt.tt_sec & 0xff;
5791                 tt.tt_sec >>= 8;
5792                 tmp[3] = tt.tt_sec & 0xff;
5793                 tt.tt_sec >>= 8;
5794                 tmp[2] = tt.tt_sec & 0xff;
5795                 tt.tt_sec >>= 8;
5796                 tmp[1] = tt.tt_sec & 0xff;
5797
5798                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5799                 ber_dupbv_x(keys, &bvtmp, ctx );
5800                 keys[1].bv_val = NULL;
5801                 keys[1].bv_len = 0;
5802         } else {
5803                 keys = NULL;
5804         }
5805
5806         *keysp = keys;
5807
5808         return LDAP_SUCCESS;
5809 }
5810
5811 static int
5812 deliveryMethodValidate(
5813         Syntax *syntax,
5814         struct berval *val )
5815 {
5816 #undef LENOF
5817 #define LENOF(s) (sizeof(s)-1)
5818         struct berval tmp = *val;
5819         /*
5820      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5821          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5822          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5823          */
5824 again:
5825         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5826
5827         switch( tmp.bv_val[0] ) {
5828         case 'a':
5829         case 'A':
5830                 if(( tmp.bv_len >= LENOF("any") ) &&
5831                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5832                 {
5833                         tmp.bv_len -= LENOF("any");
5834                         tmp.bv_val += LENOF("any");
5835                         break;
5836                 }
5837                 return LDAP_INVALID_SYNTAX;
5838
5839         case 'm':
5840         case 'M':
5841                 if(( tmp.bv_len >= LENOF("mhs") ) &&
5842                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5843                 {
5844                         tmp.bv_len -= LENOF("mhs");
5845                         tmp.bv_val += LENOF("mhs");
5846                         break;
5847                 }
5848                 return LDAP_INVALID_SYNTAX;
5849
5850         case 'p':
5851         case 'P':
5852                 if(( tmp.bv_len >= LENOF("physical") ) &&
5853                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5854                 {
5855                         tmp.bv_len -= LENOF("physical");
5856                         tmp.bv_val += LENOF("physical");
5857                         break;
5858                 }
5859                 return LDAP_INVALID_SYNTAX;
5860
5861         case 't':
5862         case 'T': /* telex or teletex or telephone */
5863                 if(( tmp.bv_len >= LENOF("telex") ) &&
5864                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5865                 {
5866                         tmp.bv_len -= LENOF("telex");
5867                         tmp.bv_val += LENOF("telex");
5868                         break;
5869                 }
5870                 if(( tmp.bv_len >= LENOF("teletex") ) &&
5871                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5872                 {
5873                         tmp.bv_len -= LENOF("teletex");
5874                         tmp.bv_val += LENOF("teletex");
5875                         break;
5876                 }
5877                 if(( tmp.bv_len >= LENOF("telephone") ) &&
5878                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5879                 {
5880                         tmp.bv_len -= LENOF("telephone");
5881                         tmp.bv_val += LENOF("telephone");
5882                         break;
5883                 }
5884                 return LDAP_INVALID_SYNTAX;
5885
5886         case 'g':
5887         case 'G': /* g3fax or g4fax */
5888                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5889                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5890                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5891                 {
5892                         tmp.bv_len -= LENOF("g3fax");
5893                         tmp.bv_val += LENOF("g3fax");
5894                         break;
5895                 }
5896                 return LDAP_INVALID_SYNTAX;
5897
5898         case 'i':
5899         case 'I':
5900                 if(( tmp.bv_len >= LENOF("ia5") ) &&
5901                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
5902                 {
5903                         tmp.bv_len -= LENOF("ia5");
5904                         tmp.bv_val += LENOF("ia5");
5905                         break;
5906                 }
5907                 return LDAP_INVALID_SYNTAX;
5908
5909         case 'v':
5910         case 'V':
5911                 if(( tmp.bv_len >= LENOF("videotex") ) &&
5912                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
5913                 {
5914                         tmp.bv_len -= LENOF("videotex");
5915                         tmp.bv_val += LENOF("videotex");
5916                         break;
5917                 }
5918                 return LDAP_INVALID_SYNTAX;
5919
5920         default:
5921                 return LDAP_INVALID_SYNTAX;
5922         }
5923
5924         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
5925
5926         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5927                 tmp.bv_len++;
5928                 tmp.bv_val--;
5929         }
5930         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
5931                 tmp.bv_len++;
5932                 tmp.bv_val--;
5933         } else {
5934                 return LDAP_INVALID_SYNTAX;
5935         }
5936         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5937                 tmp.bv_len++;
5938                 tmp.bv_val--;
5939         }
5940
5941         goto again;
5942 }
5943
5944 static int
5945 nisNetgroupTripleValidate(
5946         Syntax *syntax,
5947         struct berval *val )
5948 {
5949         char *p, *e;
5950         int commas = 0;
5951
5952         if ( BER_BVISEMPTY( val ) ) {
5953                 return LDAP_INVALID_SYNTAX;
5954         }
5955
5956         p = (char *)val->bv_val;
5957         e = p + val->bv_len;
5958
5959         if ( *p != '(' /*')'*/ ) {
5960                 return LDAP_INVALID_SYNTAX;
5961         }
5962
5963         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
5964                 if ( *p == ',' ) {
5965                         commas++;
5966                         if ( commas > 2 ) {
5967                                 return LDAP_INVALID_SYNTAX;
5968                         }
5969
5970                 } else if ( !AD_CHAR( *p ) ) {
5971                         return LDAP_INVALID_SYNTAX;
5972                 }
5973         }
5974
5975         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
5976                 return LDAP_INVALID_SYNTAX;
5977         }
5978
5979         p++;
5980
5981         if (p != e) {
5982                 return LDAP_INVALID_SYNTAX;
5983         }
5984
5985         return LDAP_SUCCESS;
5986 }
5987
5988 static int
5989 bootParameterValidate(
5990         Syntax *syntax,
5991         struct berval *val )
5992 {
5993         char *p, *e;
5994
5995         if ( BER_BVISEMPTY( val ) ) {
5996                 return LDAP_INVALID_SYNTAX;
5997         }
5998
5999         p = (char *)val->bv_val;
6000         e = p + val->bv_len;
6001
6002         /* key */
6003         for (; ( p < e ) && ( *p != '=' ); p++ ) {
6004                 if ( !AD_CHAR( *p ) ) {
6005                         return LDAP_INVALID_SYNTAX;
6006                 }
6007         }
6008
6009         if ( *p != '=' ) {
6010                 return LDAP_INVALID_SYNTAX;
6011         }
6012
6013         /* server */
6014         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
6015                 if ( !AD_CHAR( *p ) ) {
6016                         return LDAP_INVALID_SYNTAX;
6017                 }
6018         }
6019
6020         if ( *p != ':' ) {
6021                 return LDAP_INVALID_SYNTAX;
6022         }
6023
6024         /* path */
6025         for ( p++; p < e; p++ ) {
6026                 if ( !SLAP_PRINTABLE( *p ) ) {
6027                         return LDAP_INVALID_SYNTAX;
6028                 }
6029         }
6030
6031         return LDAP_SUCCESS;
6032 }
6033
6034 static int
6035 firstComponentNormalize(
6036         slap_mask_t usage,
6037         Syntax *syntax,
6038         MatchingRule *mr,
6039         struct berval *val,
6040         struct berval *normalized,
6041         void *ctx )
6042 {
6043         int rc;
6044         struct berval comp;
6045         ber_len_t len;
6046
6047         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
6048                 ber_dupbv_x( normalized, val, ctx );
6049                 return LDAP_SUCCESS;
6050         }
6051
6052         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
6053
6054         if( ! ( val->bv_val[0] == '(' /*')'*/
6055                         && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
6056                 && ! ( val->bv_val[0] == '{' /*'}'*/
6057                         && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
6058         {
6059                 return LDAP_INVALID_SYNTAX;
6060         }
6061
6062         /* trim leading white space */
6063         for( len=1;
6064                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
6065                 len++ )
6066         {
6067                 /* empty */
6068         }
6069
6070         /* grab next word */
6071         comp.bv_val = &val->bv_val[len];
6072         len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
6073         for( comp.bv_len = 0;
6074                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
6075                 comp.bv_len++ )
6076         {
6077                 /* empty */
6078         }
6079
6080         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
6081                 rc = numericoidValidate( NULL, &comp );
6082         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
6083                 rc = integerValidate( NULL, &comp );
6084         } else {
6085                 rc = LDAP_INVALID_SYNTAX;
6086         }
6087         
6088
6089         if( rc == LDAP_SUCCESS ) {
6090                 ber_dupbv_x( normalized, &comp, ctx );
6091         }
6092
6093         return rc;
6094 }
6095
6096 static char *country_gen_syn[] = {
6097         "1.3.6.1.4.1.1466.115.121.1.15",        /* Directory String */
6098         "1.3.6.1.4.1.1466.115.121.1.26",        /* IA5 String */
6099         "1.3.6.1.4.1.1466.115.121.1.44",        /* Printable String */
6100         NULL
6101 };
6102
6103 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
6104 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
6105
6106 static slap_syntax_defs_rec syntax_defs[] = {
6107         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
6108                 X_BINARY X_NOT_H_R ")",
6109                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
6110         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
6111                 0, NULL, NULL, NULL},
6112         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
6113                 0, NULL, NULL, NULL},
6114         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
6115                 X_NOT_H_R ")",
6116                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6117         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
6118                 X_NOT_H_R ")",
6119                 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6120         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6121                 0, NULL, bitStringValidate, NULL },
6122         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6123                 0, NULL, booleanValidate, NULL},
6124         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6125                 X_BINARY X_NOT_H_R ")",
6126                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6127                 NULL, certificateValidate, NULL},
6128         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6129                 X_BINARY X_NOT_H_R ")",
6130                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6131                 NULL, certificateListValidate, NULL},
6132         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6133                 X_BINARY X_NOT_H_R ")",
6134                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6135                 NULL, sequenceValidate, NULL},
6136         {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6137                 X_BINARY X_NOT_H_R ")",
6138                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6139                 NULL, attributeCertificateValidate, NULL},
6140 #if 0   /* need to go __after__ printableString */
6141         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6142                 0, "1.3.6.1.4.1.1466.115.121.1.44",
6143                 countryStringValidate, NULL},
6144 #endif
6145         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6146                 SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
6147         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6148                 0, NULL, rdnValidate, rdnPretty},
6149 #ifdef LDAP_COMP_MATCH
6150         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6151                 0, NULL, allComponentsValidate, NULL},
6152         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6153                 0, NULL, componentFilterValidate, NULL},
6154 #endif
6155         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6156                 0, NULL, NULL, NULL},
6157         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6158                 0, NULL, deliveryMethodValidate, NULL},
6159         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6160                 0, NULL, UTF8StringValidate, NULL},
6161         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6162                 0, NULL, NULL, NULL},
6163         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6164                 0, NULL, NULL, NULL},
6165         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6166                 0, NULL, NULL, NULL},
6167         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6168                 0, NULL, NULL, NULL},
6169         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6170                 0, NULL, NULL, NULL},
6171         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6172                 0, NULL, printablesStringValidate, NULL},
6173         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6174                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6175         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6176                 0, NULL, generalizedTimeValidate, NULL},
6177         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6178                 0, NULL, NULL, NULL},
6179         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6180                 0, NULL, IA5StringValidate, NULL},
6181         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6182                 0, NULL, integerValidate, NULL},
6183         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6184                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6185         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6186                 0, NULL, NULL, NULL},
6187         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6188                 0, NULL, NULL, NULL},
6189         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6190                 0, NULL, NULL, NULL},
6191         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6192                 0, NULL, NULL, NULL},
6193         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6194                 0, NULL, NULL, NULL},
6195         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6196                 SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
6197         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6198                 0, NULL, NULL, NULL},
6199         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6200                 0, NULL, numericStringValidate, NULL},
6201         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6202                 0, NULL, NULL, NULL},
6203         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6204                 0, NULL, numericoidValidate, NULL},
6205         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6206                 0, NULL, IA5StringValidate, NULL},
6207         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6208                 0, NULL, blobValidate, NULL},
6209         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6210                 0, NULL, postalAddressValidate, NULL},
6211         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6212                 0, NULL, NULL, NULL},
6213         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6214                 0, NULL, NULL, NULL},
6215         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6216                 0, NULL, printableStringValidate, NULL},
6217         /* moved here because now depends on Directory String, IA5 String 
6218          * and Printable String */
6219         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6220                 0, country_gen_syn, countryStringValidate, NULL},
6221         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6222 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6223                 0, NULL, subtreeSpecificationValidate, NULL},
6224         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6225                 X_BINARY X_NOT_H_R ")",
6226                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6227         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6228                 0, NULL, printableStringValidate, NULL},
6229         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6230                 0, NULL, NULL, NULL},
6231         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6232                 0, NULL, printablesStringValidate, NULL},
6233 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6234         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6235                 0, NULL, utcTimeValidate, NULL},
6236 #endif
6237         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6238                 0, NULL, NULL, NULL},
6239         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6240                 0, NULL, NULL, NULL},
6241         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6242                 0, NULL, NULL, NULL},
6243         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6244                 0, NULL, NULL, NULL},
6245         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6246                 0, NULL, NULL, NULL},
6247
6248         /* RFC 2307 NIS Syntaxes */
6249         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
6250                 0, NULL, nisNetgroupTripleValidate, NULL},
6251         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
6252                 0, NULL, bootParameterValidate, NULL},
6253
6254         /* draft-zeilenga-ldap-x509 */
6255         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6256                 SLAP_SYNTAX_HIDE, NULL,
6257                 serialNumberAndIssuerValidate,
6258                 serialNumberAndIssuerPretty},
6259         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6260                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6261         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6262                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6263         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6264                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6265         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6266                 SLAP_SYNTAX_HIDE, NULL,
6267                 issuerAndThisUpdateValidate,
6268                 issuerAndThisUpdatePretty},
6269         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6270                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6271         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6272                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6273         {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6274                 SLAP_SYNTAX_HIDE, NULL,
6275                 serialNumberAndIssuerSerialValidate,
6276                 serialNumberAndIssuerSerialPretty},
6277         {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6278                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6279
6280 #ifdef SLAPD_AUTHPASSWD
6281         /* needs updating */
6282         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6283                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6284 #endif
6285
6286         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6287                 0, NULL, UUIDValidate, UUIDPretty},
6288
6289         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6290                 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6291
6292         {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6293                 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6294
6295         /* OpenLDAP Void Syntax */
6296         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6297                 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6298
6299         /* FIXME: OID is unused, but not registered yet */
6300         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6301                 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6302
6303         {NULL, 0, NULL, NULL, NULL}
6304 };
6305
6306 char *csnSIDMatchSyntaxes[] = {
6307         "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6308         NULL
6309 };
6310 char *certificateExactMatchSyntaxes[] = {
6311         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6312         NULL
6313 };
6314 char *certificateListExactMatchSyntaxes[] = {
6315         "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6316         NULL
6317 };
6318 char *attributeCertificateExactMatchSyntaxes[] = {
6319         attributeCertificateSyntaxOID  /* attributeCertificate */,
6320         NULL
6321 };
6322
6323 #ifdef LDAP_COMP_MATCH
6324 char *componentFilterMatchSyntaxes[] = {
6325         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6326         "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6327         attributeCertificateSyntaxOID /* attributeCertificate */,
6328         NULL
6329 };
6330 #endif
6331
6332 char *directoryStringSyntaxes[] = {
6333         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6334         NULL
6335 };
6336 char *integerFirstComponentMatchSyntaxes[] = {
6337         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6338         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6339         NULL
6340 };
6341 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6342         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6343         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
6344         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6345         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6346         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6347         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6348         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6349         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6350         NULL
6351 };
6352
6353 /*
6354  * Other matching rules in X.520 that we do not use (yet):
6355  *
6356  * 2.5.13.25    uTCTimeMatch
6357  * 2.5.13.26    uTCTimeOrderingMatch
6358  * 2.5.13.31*   directoryStringFirstComponentMatch
6359  * 2.5.13.32*   wordMatch
6360  * 2.5.13.33*   keywordMatch
6361  * 2.5.13.36+   certificatePairExactMatch
6362  * 2.5.13.37+   certificatePairMatch
6363  * 2.5.13.40+   algorithmIdentifierMatch
6364  * 2.5.13.41*   storedPrefixMatch
6365  * 2.5.13.42    attributeCertificateMatch
6366  * 2.5.13.43    readerAndKeyIDMatch
6367  * 2.5.13.44    attributeIntegrityMatch
6368  *
6369  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6370  * (+) described in draft-zeilenga-ldap-x509
6371  */
6372 static slap_mrule_defs_rec mrule_defs[] = {
6373         /*
6374          * EQUALITY matching rules must be listed after associated APPROX
6375          * matching rules.  So, we list all APPROX matching rules first.
6376          */
6377         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6378                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6379                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6380                 NULL, NULL, directoryStringApproxMatch,
6381                 directoryStringApproxIndexer, directoryStringApproxFilter,
6382                 NULL},
6383
6384         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6385                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6386                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6387                 NULL, NULL, IA5StringApproxMatch,
6388                 IA5StringApproxIndexer, IA5StringApproxFilter,
6389                 NULL},
6390
6391         /*
6392          * Other matching rules
6393          */
6394         
6395         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6396                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6397                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6398                 NULL, NULL, octetStringMatch,
6399                 octetStringIndexer, octetStringFilter,
6400                 NULL },
6401
6402         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6403                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6404                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6405                 NULL, dnNormalize, dnMatch,
6406                 octetStringIndexer, octetStringFilter,
6407                 NULL },
6408
6409         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6410                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6411                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6412                 NULL, dnNormalize, dnRelativeMatch,
6413                 NULL, NULL,
6414                 NULL },
6415
6416         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6417                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6418                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6419                 NULL, dnNormalize, dnRelativeMatch,
6420                 NULL, NULL,
6421                 NULL },
6422
6423         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6424                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6425                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6426                 NULL, dnNormalize, dnRelativeMatch,
6427                 NULL, NULL,
6428                 NULL },
6429
6430         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6431                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6432                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6433                 NULL, dnNormalize, dnRelativeMatch,
6434                 NULL, NULL,
6435                 NULL },
6436
6437         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6438                 "SYNTAX 1.2.36.79672281.1.5.0 )",
6439                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6440                 NULL, rdnNormalize, rdnMatch,
6441                 octetStringIndexer, octetStringFilter,
6442                 NULL },
6443
6444 #ifdef LDAP_COMP_MATCH
6445         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6446                 "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
6447                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6448                 NULL, NULL , componentFilterMatch,
6449                 octetStringIndexer, octetStringFilter,
6450                 NULL },
6451
6452         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6453                 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6454                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6455                 NULL, NULL , allComponentsMatch,
6456                 octetStringIndexer, octetStringFilter,
6457                 NULL },
6458
6459         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6460                 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6461                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6462                 NULL, NULL , directoryComponentsMatch,
6463                 octetStringIndexer, octetStringFilter,
6464                 NULL },
6465 #endif
6466
6467         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6468                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6469                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6470                 NULL, UTF8StringNormalize, octetStringMatch,
6471                 octetStringIndexer, octetStringFilter,
6472                 directoryStringApproxMatchOID },
6473
6474         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6475                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6476                 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6477                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6478                 NULL, NULL,
6479                 "caseIgnoreMatch" },
6480
6481         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6482                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6483                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6484                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6485                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6486                 "caseIgnoreMatch" },
6487
6488         {"( 2.5.13.5 NAME 'caseExactMatch' "
6489                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6490                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6491                 NULL, UTF8StringNormalize, octetStringMatch,
6492                 octetStringIndexer, octetStringFilter,
6493                 directoryStringApproxMatchOID },
6494
6495         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6496                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6497                 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6498                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6499                 NULL, NULL,
6500                 "caseExactMatch" },
6501
6502         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6503                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6504                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6505                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6506                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6507                 "caseExactMatch" },
6508
6509         {"( 2.5.13.8 NAME 'numericStringMatch' "
6510                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6511                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6512                 NULL, numericStringNormalize, octetStringMatch,
6513                 octetStringIndexer, octetStringFilter,
6514                 NULL },
6515
6516         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6517                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6518                 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6519                 NULL, numericStringNormalize, octetStringOrderingMatch,
6520                 NULL, NULL,
6521                 "numericStringMatch" },
6522
6523         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6524                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6525                 SLAP_MR_SUBSTR, NULL,
6526                 NULL, numericStringNormalize, octetStringSubstringsMatch,
6527                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6528                 "numericStringMatch" },
6529
6530         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6531                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
6532                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6533                 NULL, postalAddressNormalize, octetStringMatch,
6534                 octetStringIndexer, octetStringFilter,
6535                 NULL },
6536
6537         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6538                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6539                 SLAP_MR_SUBSTR, NULL,
6540                 NULL, NULL, NULL, NULL, NULL,
6541                 "caseIgnoreListMatch" },
6542
6543         {"( 2.5.13.13 NAME 'booleanMatch' "
6544                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6545                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6546                 NULL, NULL, booleanMatch,
6547                 octetStringIndexer, octetStringFilter,
6548                 NULL },
6549
6550         {"( 2.5.13.14 NAME 'integerMatch' "
6551                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6552                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6553                 NULL, NULL, integerMatch,
6554                 integerIndexer, integerFilter,
6555                 NULL },
6556
6557         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6558                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6559                 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6560                 NULL, NULL, integerMatch,
6561                 NULL, NULL,
6562                 "integerMatch" },
6563
6564         {"( 2.5.13.16 NAME 'bitStringMatch' "
6565                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6566                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6567                 NULL, NULL, octetStringMatch,
6568                 octetStringIndexer, octetStringFilter,
6569                 NULL },
6570
6571         {"( 2.5.13.17 NAME 'octetStringMatch' "
6572                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6573                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6574                 NULL, NULL, octetStringMatch,
6575                 octetStringIndexer, octetStringFilter,
6576                 NULL },
6577
6578         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6579                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6580                 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6581                 NULL, NULL, octetStringOrderingMatch,
6582                 NULL, NULL,
6583                 "octetStringMatch" },
6584
6585         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6586                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6587                 SLAP_MR_SUBSTR, NULL,
6588                 NULL, NULL, octetStringSubstringsMatch,
6589                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6590                 "octetStringMatch" },
6591
6592         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6593                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6594                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6595                 NULL,
6596                 telephoneNumberNormalize, octetStringMatch,
6597                 octetStringIndexer, octetStringFilter,
6598                 NULL },
6599
6600         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6601                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6602                 SLAP_MR_SUBSTR, NULL,
6603                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6604                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6605                 "telephoneNumberMatch" },
6606
6607         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6608                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6609                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6610                 NULL, NULL, NULL, NULL, NULL, NULL },
6611
6612         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6613                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
6614                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6615                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6616                 uniqueMemberIndexer, uniqueMemberFilter,
6617                 NULL },
6618
6619         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6620                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6621                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6622                 NULL, NULL, NULL, NULL, NULL, NULL },
6623
6624         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6625                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6626                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6627                 NULL, generalizedTimeNormalize, octetStringMatch,
6628                 generalizedTimeIndexer, generalizedTimeFilter,
6629                 NULL },
6630
6631         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6632                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6633                 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6634                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6635                 NULL, NULL,
6636                 "generalizedTimeMatch" },
6637
6638         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6639                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6640                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6641                         integerFirstComponentMatchSyntaxes,
6642                 NULL, firstComponentNormalize, integerMatch,
6643                 octetStringIndexer, octetStringFilter,
6644                 NULL },
6645
6646         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6647                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
6648                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6649                         objectIdentifierFirstComponentMatchSyntaxes,
6650                 NULL, firstComponentNormalize, octetStringMatch,
6651                 octetStringIndexer, octetStringFilter,
6652                 NULL },
6653
6654         {"( 2.5.13.34 NAME 'certificateExactMatch' "
6655                 "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
6656                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6657                 NULL, certificateExactNormalize, octetStringMatch,
6658                 octetStringIndexer, octetStringFilter,
6659                 NULL },
6660
6661         {"( 2.5.13.35 NAME 'certificateMatch' "
6662                 "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
6663                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6664                 NULL, NULL, NULL, NULL, NULL,
6665                 NULL },
6666
6667         {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6668                 "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
6669                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6670                 NULL, certificateListExactNormalize, octetStringMatch,
6671                 octetStringIndexer, octetStringFilter,
6672                 NULL },
6673
6674         {"( 2.5.13.39 NAME 'certificateListMatch' "
6675                 "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
6676                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6677                 NULL, NULL, NULL, NULL, NULL,
6678                 NULL },
6679
6680         {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6681                 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6682                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6683                 NULL, attributeCertificateExactNormalize, octetStringMatch,
6684                 octetStringIndexer, octetStringFilter,
6685                 NULL },
6686
6687         {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6688                 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6689                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6690                 NULL, NULL, NULL, NULL, NULL,
6691                 NULL },
6692
6693         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6694                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6695                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6696                 NULL, IA5StringNormalize, octetStringMatch,
6697                 octetStringIndexer, octetStringFilter,
6698                 IA5StringApproxMatchOID },
6699
6700         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6701                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6702                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6703                 NULL, IA5StringNormalize, octetStringMatch,
6704                 octetStringIndexer, octetStringFilter,
6705                 IA5StringApproxMatchOID },
6706
6707         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6708                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6709                 SLAP_MR_SUBSTR, NULL,
6710                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6711                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6712                 "caseIgnoreIA5Match" },
6713
6714         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6715                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6716                 SLAP_MR_SUBSTR, NULL,
6717                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6718                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6719                 "caseExactIA5Match" },
6720
6721 #ifdef SLAPD_AUTHPASSWD
6722         /* needs updating */
6723         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6724                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
6725                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6726                 NULL, NULL, authPasswordMatch,
6727                 NULL, NULL,
6728                 NULL},
6729 #endif
6730
6731         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6732                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6733                 SLAP_MR_EXT, NULL,
6734                 NULL, NULL, integerBitAndMatch,
6735                 NULL, NULL,
6736                 "integerMatch" },
6737
6738         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6739                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6740                 SLAP_MR_EXT, NULL,
6741                 NULL, NULL, integerBitOrMatch,
6742                 NULL, NULL,
6743                 "integerMatch" },
6744
6745         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6746                 "SYNTAX 1.3.6.1.1.16.1 )",
6747                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6748                 NULL, UUIDNormalize, octetStringMatch,
6749                 octetStringIndexer, octetStringFilter,
6750                 NULL},
6751
6752         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6753                 "SYNTAX 1.3.6.1.1.16.1 )",
6754                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6755                 NULL, UUIDNormalize, octetStringOrderingMatch,
6756                 octetStringIndexer, octetStringFilter,
6757                 "UUIDMatch"},
6758
6759         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6760                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6761                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6762                 NULL, csnNormalize, csnMatch,
6763                 csnIndexer, csnFilter,
6764                 NULL},
6765
6766         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6767                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6768                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6769                 NULL, csnNormalize, csnOrderingMatch,
6770                 NULL, NULL,
6771                 "CSNMatch" },
6772
6773         {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6774                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6775                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6776                 NULL, csnSidNormalize, octetStringMatch,
6777                 octetStringIndexer, octetStringFilter,
6778                 NULL },
6779
6780         /* FIXME: OID is unused, but not registered yet */
6781         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6782                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
6783                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6784                 NULL, authzNormalize, authzMatch,
6785                 NULL, NULL,
6786                 NULL},
6787
6788         {NULL, SLAP_MR_NONE, NULL,
6789                 NULL, NULL, NULL, NULL, NULL,
6790                 NULL }
6791 };
6792
6793 int
6794 slap_schema_init( void )
6795 {
6796         int             res;
6797         int             i;
6798
6799         /* we should only be called once (from main) */
6800         assert( schema_init_done == 0 );
6801
6802         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6803                 res = register_syntax( &syntax_defs[i] );
6804
6805                 if ( res ) {
6806                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6807                                  syntax_defs[i].sd_desc );
6808                         return LDAP_OTHER;
6809                 }
6810         }
6811
6812         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6813                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6814                         mrule_defs[i].mrd_compat_syntaxes == NULL )
6815                 {
6816                         fprintf( stderr,
6817                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
6818                                  mrule_defs[i].mrd_desc );
6819                         continue;
6820                 }
6821
6822                 res = register_matching_rule( &mrule_defs[i] );
6823
6824                 if ( res ) {
6825                         fprintf( stderr,
6826                                 "slap_schema_init: Error registering matching rule %s\n",
6827                                  mrule_defs[i].mrd_desc );
6828                         return LDAP_OTHER;
6829                 }
6830         }
6831
6832         res = slap_schema_load();
6833         schema_init_done = 1;
6834         return res;
6835 }
6836
6837 void
6838 schema_destroy( void )
6839 {
6840         oidm_destroy();
6841         oc_destroy();
6842         at_destroy();
6843         mr_destroy();
6844         mru_destroy();
6845         syn_destroy();
6846
6847         if( schema_init_done ) {
6848                 ldap_pvt_thread_mutex_destroy( &ad_index_mutex );
6849                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6850                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
6851         }
6852 }