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