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