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