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