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