xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/schema_init.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/schema_init.c,v 1.386.2.22 2008/07/10 00:02:48 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2008 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 
17 #include "portable.h"
18 
19 #include <stdio.h>
20 #ifdef HAVE_LIMITS_H
21 #include <limits.h>
22 #endif
23 
24 #include <ac/ctype.h>
25 #include <ac/errno.h>
26 #include <ac/string.h>
27 #include <ac/socket.h>
28 
29 #include "slap.h"
30 #include "../../libraries/liblber/lber-int.h" /* get ber_ptrlen() */
31 
32 #include "ldap_utf8.h"
33 
34 #include "lutil.h"
35 #include "lutil_hash.h"
36 #define HASH_BYTES				LUTIL_HASH_BYTES
37 #define HASH_CONTEXT			lutil_HASH_CTX
38 #define HASH_Init(c)			lutil_HASHInit(c)
39 #define HASH_Update(c,buf,len)	lutil_HASHUpdate(c,buf,len)
40 #define HASH_Final(d,c)			lutil_HASHFinal(d,c)
41 
42 /* approx matching rules */
43 #define directoryStringApproxMatchOID	"1.3.6.1.4.1.4203.666.4.4"
44 #define directoryStringApproxMatch		approxMatch
45 #define directoryStringApproxIndexer	approxIndexer
46 #define directoryStringApproxFilter		approxFilter
47 #define IA5StringApproxMatchOID			"1.3.6.1.4.1.4203.666.4.5"
48 #define IA5StringApproxMatch			approxMatch
49 #define IA5StringApproxIndexer			approxIndexer
50 #define IA5StringApproxFilter			approxFilter
51 
52 /* Change Sequence Number (CSN) - much of this will change */
53 #define csnMatch				octetStringMatch
54 #define csnOrderingMatch		octetStringOrderingMatch
55 #define csnIndexer				generalizedTimeIndexer
56 #define csnFilter				generalizedTimeFilter
57 
58 #define authzMatch				octetStringMatch
59 
60 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
61 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
62 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
63 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
64 
65 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
66 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
67 	SLAP_INDEX_INTLEN_DEFAULT );
68 
69 ldap_pvt_thread_mutex_t	ad_undef_mutex;
70 ldap_pvt_thread_mutex_t	oc_undef_mutex;
71 
72 static int
73 generalizedTimeValidate(
74 	Syntax *syntax,
75 	struct berval *in );
76 
77 static int
78 inValidate(
79 	Syntax *syntax,
80 	struct berval *in )
81 {
82 	/* no value allowed */
83 	return LDAP_INVALID_SYNTAX;
84 }
85 
86 static int
87 blobValidate(
88 	Syntax *syntax,
89 	struct berval *in )
90 {
91 	/* any value allowed */
92 	return LDAP_SUCCESS;
93 }
94 
95 #define berValidate blobValidate
96 
97 static int
98 sequenceValidate(
99 	Syntax *syntax,
100 	struct berval *in )
101 {
102 	if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
103 	if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
104 
105 	return LDAP_SUCCESS;
106 }
107 
108 /* X.509 related stuff */
109 
110 enum {
111 	SLAP_X509_V1		= 0,
112 	SLAP_X509_V2		= 1,
113 	SLAP_X509_V3		= 2
114 };
115 
116 #define	SLAP_X509_OPTION	(LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
117 
118 enum {
119 	SLAP_X509_OPT_C_VERSION		= SLAP_X509_OPTION + 0,
120 	SLAP_X509_OPT_C_ISSUERUNIQUEID	= SLAP_X509_OPTION + 1,
121 	SLAP_X509_OPT_C_SUBJECTUNIQUEID	= SLAP_X509_OPTION + 2,
122 	SLAP_X509_OPT_C_EXTENSIONS	= SLAP_X509_OPTION + 3
123 };
124 
125 enum {
126 	SLAP_X509_OPT_CL_CRLEXTENSIONS	= SLAP_X509_OPTION + 0
127 };
128 
129 /* X.509 certificate validation */
130 static int certificateValidate( Syntax *syntax, struct berval *in )
131 {
132 	BerElementBuffer berbuf;
133 	BerElement *ber = (BerElement *)&berbuf;
134 	ber_tag_t tag;
135 	ber_len_t len;
136 	ber_int_t version = SLAP_X509_V1;
137 
138 	ber_init2( ber, in, LBER_USE_DER );
139 	tag = ber_skip_tag( ber, &len );	/* Signed wrapper */
140 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
141 	tag = ber_skip_tag( ber, &len );	/* Sequence */
142 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
143 	tag = ber_peek_tag( ber, &len );
144 	/* Optional version */
145 	if ( tag == SLAP_X509_OPT_C_VERSION ) {
146 		tag = ber_skip_tag( ber, &len );
147 		tag = ber_get_int( ber, &version );
148 		if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
149 	}
150 	/* NOTE: don't try to parse Serial, because it might be longer
151 	 * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
152 	tag = ber_skip_tag( ber, &len );	/* Serial */
153 	if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
154 	ber_skip_data( ber, len );
155 	tag = ber_skip_tag( ber, &len );	/* Signature Algorithm */
156 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
157 	ber_skip_data( ber, len );
158 	tag = ber_skip_tag( ber, &len );	/* Issuer DN */
159 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
160 	ber_skip_data( ber, len );
161 	tag = ber_skip_tag( ber, &len );	/* Validity */
162 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
163 	ber_skip_data( ber, len );
164 	tag = ber_skip_tag( ber, &len );	/* Subject DN */
165 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
166 	ber_skip_data( ber, len );
167 	tag = ber_skip_tag( ber, &len );	/* Subject PublicKeyInfo */
168 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
169 	ber_skip_data( ber, len );
170 	tag = ber_skip_tag( ber, &len );
171 	if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) {	/* issuerUniqueID */
172 		if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
173 		ber_skip_data( ber, len );
174 		tag = ber_skip_tag( ber, &len );
175 	}
176 	if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) {	/* subjectUniqueID */
177 		if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
178 		ber_skip_data( ber, len );
179 		tag = ber_skip_tag( ber, &len );
180 	}
181 	if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) {	/* Extensions */
182 		if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
183 		tag = ber_skip_tag( ber, &len );
184 		if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
185 		ber_skip_data( ber, len );
186 		tag = ber_skip_tag( ber, &len );
187 	}
188 	/* signatureAlgorithm */
189 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
190 	ber_skip_data( ber, len );
191 	tag = ber_skip_tag( ber, &len );
192 	/* Signature */
193 	if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
194 	ber_skip_data( ber, len );
195 	tag = ber_skip_tag( ber, &len );
196 	/* Must be at end now */
197 	if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
198 	return LDAP_SUCCESS;
199 }
200 
201 /* X.509 certificate list validation */
202 static int certificateListValidate( Syntax *syntax, struct berval *in )
203 {
204 	BerElementBuffer berbuf;
205 	BerElement *ber = (BerElement *)&berbuf;
206 	ber_tag_t tag;
207 	ber_len_t len;
208 	ber_int_t version = SLAP_X509_V1;
209 
210 	ber_init2( ber, in, LBER_USE_DER );
211 	tag = ber_skip_tag( ber, &len );	/* Signed wrapper */
212 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
213 	tag = ber_skip_tag( ber, &len );	/* Sequence */
214 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
215 	tag = ber_peek_tag( ber, &len );
216 	/* Optional version */
217 	if ( tag == LBER_INTEGER ) {
218 		tag = ber_get_int( ber, &version );
219 		assert( tag == LBER_INTEGER );
220 		if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
221 	}
222 	tag = ber_skip_tag( ber, &len );	/* Signature Algorithm */
223 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
224 	ber_skip_data( ber, len );
225 	tag = ber_skip_tag( ber, &len );	/* Issuer DN */
226 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
227 	ber_skip_data( ber, len );
228 	tag = ber_skip_tag( ber, &len );	/* thisUpdate */
229 	/* Time is a CHOICE { UTCTime, GeneralizedTime } */
230 	if ( tag != 0x17U && tag != 0x18U ) return LDAP_INVALID_SYNTAX;
231 	ber_skip_data( ber, len );
232 	/* Optional nextUpdate */
233 	tag = ber_skip_tag( ber, &len );
234 	if ( tag == 0x17U || tag == 0x18U ) {
235 		ber_skip_data( ber, len );
236 		tag = ber_skip_tag( ber, &len );
237 	}
238 	/* revokedCertificates - Sequence of Sequence, Optional */
239 	if ( tag == LBER_SEQUENCE ) {
240 		ber_len_t seqlen;
241 		if ( ber_peek_tag( ber, &seqlen ) == LBER_SEQUENCE ) {
242 			/* Should NOT be empty */
243 			ber_skip_data( ber, len );
244 			tag = ber_skip_tag( ber, &len );
245 		}
246 	}
247 	/* Optional Extensions */
248 	if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
249 		if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
250 		tag = ber_skip_tag( ber, &len );
251 		if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
252 		ber_skip_data( ber, len );
253 		tag = ber_skip_tag( ber, &len );
254 	}
255 	/* signatureAlgorithm */
256 	if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
257 	ber_skip_data( ber, len );
258 	tag = ber_skip_tag( ber, &len );
259 	/* Signature */
260 	if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
261 	ber_skip_data( ber, len );
262 	tag = ber_skip_tag( ber, &len );
263 	/* Must be at end now */
264 	if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
265 	return LDAP_SUCCESS;
266 }
267 
268 int
269 octetStringMatch(
270 	int *matchp,
271 	slap_mask_t flags,
272 	Syntax *syntax,
273 	MatchingRule *mr,
274 	struct berval *value,
275 	void *assertedValue )
276 {
277 	struct berval *asserted = (struct berval *) assertedValue;
278 	int match = value->bv_len - asserted->bv_len;
279 
280 	if( match == 0 ) {
281 		match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
282 	}
283 
284 	*matchp = match;
285 	return LDAP_SUCCESS;
286 }
287 
288 int
289 octetStringOrderingMatch(
290 	int *matchp,
291 	slap_mask_t flags,
292 	Syntax *syntax,
293 	MatchingRule *mr,
294 	struct berval *value,
295 	void *assertedValue )
296 {
297 	struct berval *asserted = (struct berval *) assertedValue;
298 	ber_len_t v_len  = value->bv_len;
299 	ber_len_t av_len = asserted->bv_len;
300 
301 	int match = memcmp( value->bv_val, asserted->bv_val,
302 		(v_len < av_len ? v_len : av_len) );
303 
304 	if( match == 0 ) match = v_len - av_len;
305 
306 	*matchp = match;
307 	return LDAP_SUCCESS;
308 }
309 
310 static void
311 hashPreset(
312 	HASH_CONTEXT *HASHcontext,
313 	struct berval *prefix,
314 	char pre,
315 	Syntax *syntax,
316 	MatchingRule *mr)
317 {
318 	HASH_Init(HASHcontext);
319 	if(prefix && prefix->bv_len > 0) {
320 		HASH_Update(HASHcontext,
321 			(unsigned char *)prefix->bv_val, prefix->bv_len);
322 	}
323 	if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
324 	HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
325 	HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
326 	return;
327 }
328 
329 static void
330 hashIter(
331 	HASH_CONTEXT *HASHcontext,
332 	unsigned char *HASHdigest,
333 	unsigned char *value,
334 	int len)
335 {
336 	HASH_CONTEXT ctx = *HASHcontext;
337 	HASH_Update( &ctx, value, len );
338 	HASH_Final( HASHdigest, &ctx );
339 }
340 
341 /* Index generation function */
342 int octetStringIndexer(
343 	slap_mask_t use,
344 	slap_mask_t flags,
345 	Syntax *syntax,
346 	MatchingRule *mr,
347 	struct berval *prefix,
348 	BerVarray values,
349 	BerVarray *keysp,
350 	void *ctx )
351 {
352 	int i;
353 	size_t slen, mlen;
354 	BerVarray keys;
355 	HASH_CONTEXT HASHcontext;
356 	unsigned char HASHdigest[HASH_BYTES];
357 	struct berval digest;
358 	digest.bv_val = (char *)HASHdigest;
359 	digest.bv_len = sizeof(HASHdigest);
360 
361 	for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
362 		/* just count them */
363 	}
364 
365 	/* we should have at least one value at this point */
366 	assert( i > 0 );
367 
368 	keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
369 
370 	slen = syntax->ssyn_oidlen;
371 	mlen = mr->smr_oidlen;
372 
373 	hashPreset( &HASHcontext, prefix, 0, syntax, mr);
374 	for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
375 		hashIter( &HASHcontext, HASHdigest,
376 			(unsigned char *)values[i].bv_val, values[i].bv_len );
377 		ber_dupbv_x( &keys[i], &digest, ctx );
378 	}
379 
380 	BER_BVZERO( &keys[i] );
381 
382 	*keysp = keys;
383 
384 	return LDAP_SUCCESS;
385 }
386 
387 /* Index generation function */
388 int octetStringFilter(
389 	slap_mask_t use,
390 	slap_mask_t flags,
391 	Syntax *syntax,
392 	MatchingRule *mr,
393 	struct berval *prefix,
394 	void * assertedValue,
395 	BerVarray *keysp,
396 	void *ctx )
397 {
398 	size_t slen, mlen;
399 	BerVarray keys;
400 	HASH_CONTEXT HASHcontext;
401 	unsigned char HASHdigest[HASH_BYTES];
402 	struct berval *value = (struct berval *) assertedValue;
403 	struct berval digest;
404 	digest.bv_val = (char *)HASHdigest;
405 	digest.bv_len = sizeof(HASHdigest);
406 
407 	slen = syntax->ssyn_oidlen;
408 	mlen = mr->smr_oidlen;
409 
410 	keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
411 
412 	hashPreset( &HASHcontext, prefix, 0, syntax, mr );
413 	hashIter( &HASHcontext, HASHdigest,
414 		(unsigned char *)value->bv_val, value->bv_len );
415 
416 	ber_dupbv_x( keys, &digest, ctx );
417 	BER_BVZERO( &keys[1] );
418 
419 	*keysp = keys;
420 
421 	return LDAP_SUCCESS;
422 }
423 
424 static int
425 octetStringSubstringsMatch(
426 	int *matchp,
427 	slap_mask_t flags,
428 	Syntax *syntax,
429 	MatchingRule *mr,
430 	struct berval *value,
431 	void *assertedValue )
432 {
433 	int match = 0;
434 	SubstringsAssertion *sub = assertedValue;
435 	struct berval left = *value;
436 	int i;
437 	ber_len_t inlen = 0;
438 
439 	/* Add up asserted input length */
440 	if ( !BER_BVISNULL( &sub->sa_initial ) ) {
441 		inlen += sub->sa_initial.bv_len;
442 	}
443 	if ( sub->sa_any ) {
444 		for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
445 			inlen += sub->sa_any[i].bv_len;
446 		}
447 	}
448 	if ( !BER_BVISNULL( &sub->sa_final ) ) {
449 		inlen += sub->sa_final.bv_len;
450 	}
451 
452 	if ( !BER_BVISNULL( &sub->sa_initial ) ) {
453 		if ( inlen > left.bv_len ) {
454 			match = 1;
455 			goto done;
456 		}
457 
458 		match = memcmp( sub->sa_initial.bv_val, left.bv_val,
459 			sub->sa_initial.bv_len );
460 
461 		if ( match != 0 ) {
462 			goto done;
463 		}
464 
465 		left.bv_val += sub->sa_initial.bv_len;
466 		left.bv_len -= sub->sa_initial.bv_len;
467 		inlen -= sub->sa_initial.bv_len;
468 	}
469 
470 	if ( !BER_BVISNULL( &sub->sa_final ) ) {
471 		if ( inlen > left.bv_len ) {
472 			match = 1;
473 			goto done;
474 		}
475 
476 		match = memcmp( sub->sa_final.bv_val,
477 			&left.bv_val[left.bv_len - sub->sa_final.bv_len],
478 			sub->sa_final.bv_len );
479 
480 		if ( match != 0 ) {
481 			goto done;
482 		}
483 
484 		left.bv_len -= sub->sa_final.bv_len;
485 		inlen -= sub->sa_final.bv_len;
486 	}
487 
488 	if ( sub->sa_any ) {
489 		for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
490 			ber_len_t idx;
491 			char *p;
492 
493 retry:
494 			if ( inlen > left.bv_len ) {
495 				/* not enough length */
496 				match = 1;
497 				goto done;
498 			}
499 
500 			if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
501 				continue;
502 			}
503 
504 			p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
505 
506 			if( p == NULL ) {
507 				match = 1;
508 				goto done;
509 			}
510 
511 			idx = p - left.bv_val;
512 
513 			if ( idx >= left.bv_len ) {
514 				/* this shouldn't happen */
515 				return LDAP_OTHER;
516 			}
517 
518 			left.bv_val = p;
519 			left.bv_len -= idx;
520 
521 			if ( sub->sa_any[i].bv_len > left.bv_len ) {
522 				/* not enough left */
523 				match = 1;
524 				goto done;
525 			}
526 
527 			match = memcmp( left.bv_val,
528 				sub->sa_any[i].bv_val,
529 				sub->sa_any[i].bv_len );
530 
531 			if ( match != 0 ) {
532 				left.bv_val++;
533 				left.bv_len--;
534 				goto retry;
535 			}
536 
537 			left.bv_val += sub->sa_any[i].bv_len;
538 			left.bv_len -= sub->sa_any[i].bv_len;
539 			inlen -= sub->sa_any[i].bv_len;
540 		}
541 	}
542 
543 done:
544 	*matchp = match;
545 	return LDAP_SUCCESS;
546 }
547 
548 /* Substrings Index generation function */
549 static int
550 octetStringSubstringsIndexer(
551 	slap_mask_t use,
552 	slap_mask_t flags,
553 	Syntax *syntax,
554 	MatchingRule *mr,
555 	struct berval *prefix,
556 	BerVarray values,
557 	BerVarray *keysp,
558 	void *ctx )
559 {
560 	ber_len_t i, nkeys;
561 	size_t slen, mlen;
562 	BerVarray keys;
563 
564 	HASH_CONTEXT HCany, HCini, HCfin;
565 	unsigned char HASHdigest[HASH_BYTES];
566 	struct berval digest;
567 	digest.bv_val = (char *)HASHdigest;
568 	digest.bv_len = sizeof(HASHdigest);
569 
570 	nkeys = 0;
571 
572 	for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
573 		/* count number of indices to generate */
574 		if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
575 			if( values[i].bv_len >= index_substr_if_maxlen ) {
576 				nkeys += index_substr_if_maxlen -
577 					(index_substr_if_minlen - 1);
578 			} else if( values[i].bv_len >= index_substr_if_minlen ) {
579 				nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
580 			}
581 		}
582 
583 		if( flags & SLAP_INDEX_SUBSTR_ANY ) {
584 			if( values[i].bv_len >= index_substr_any_len ) {
585 				nkeys += values[i].bv_len - (index_substr_any_len - 1);
586 			}
587 		}
588 
589 		if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
590 			if( values[i].bv_len >= index_substr_if_maxlen ) {
591 				nkeys += index_substr_if_maxlen -
592 					(index_substr_if_minlen - 1);
593 			} else if( values[i].bv_len >= index_substr_if_minlen ) {
594 				nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
595 			}
596 		}
597 	}
598 
599 	if( nkeys == 0 ) {
600 		/* no keys to generate */
601 		*keysp = NULL;
602 		return LDAP_SUCCESS;
603 	}
604 
605 	keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
606 
607 	slen = syntax->ssyn_oidlen;
608 	mlen = mr->smr_oidlen;
609 
610 	if ( flags & SLAP_INDEX_SUBSTR_ANY )
611 		hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
612 	if( flags & SLAP_INDEX_SUBSTR_INITIAL )
613 		hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
614 	if( flags & SLAP_INDEX_SUBSTR_FINAL )
615 		hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
616 
617 	nkeys = 0;
618 	for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
619 		ber_len_t j,max;
620 
621 		if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
622 			( values[i].bv_len >= index_substr_any_len ) )
623 		{
624 			max = values[i].bv_len - (index_substr_any_len - 1);
625 
626 			for( j=0; j<max; j++ ) {
627 				hashIter( &HCany, HASHdigest,
628 					(unsigned char *)&values[i].bv_val[j],
629 					index_substr_any_len );
630 				ber_dupbv_x( &keys[nkeys++], &digest, ctx );
631 			}
632 		}
633 
634 		/* skip if too short */
635 		if( values[i].bv_len < index_substr_if_minlen ) continue;
636 
637 		max = index_substr_if_maxlen < values[i].bv_len
638 			? index_substr_if_maxlen : values[i].bv_len;
639 
640 		for( j=index_substr_if_minlen; j<=max; j++ ) {
641 
642 			if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
643 				hashIter( &HCini, HASHdigest,
644 					(unsigned char *)values[i].bv_val, j );
645 				ber_dupbv_x( &keys[nkeys++], &digest, ctx );
646 			}
647 
648 			if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
649 				hashIter( &HCfin, HASHdigest,
650 					(unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
651 				ber_dupbv_x( &keys[nkeys++], &digest, ctx );
652 			}
653 
654 		}
655 	}
656 
657 	if( nkeys > 0 ) {
658 		BER_BVZERO( &keys[nkeys] );
659 		*keysp = keys;
660 	} else {
661 		ch_free( keys );
662 		*keysp = NULL;
663 	}
664 
665 	return LDAP_SUCCESS;
666 }
667 
668 static int
669 octetStringSubstringsFilter (
670 	slap_mask_t use,
671 	slap_mask_t flags,
672 	Syntax *syntax,
673 	MatchingRule *mr,
674 	struct berval *prefix,
675 	void * assertedValue,
676 	BerVarray *keysp,
677 	void *ctx)
678 {
679 	SubstringsAssertion *sa;
680 	char pre;
681 	ber_len_t nkeys = 0;
682 	size_t slen, mlen, klen;
683 	BerVarray keys;
684 	HASH_CONTEXT HASHcontext;
685 	unsigned char HASHdigest[HASH_BYTES];
686 	struct berval *value;
687 	struct berval digest;
688 
689 	sa = (SubstringsAssertion *) assertedValue;
690 
691 	if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
692 		!BER_BVISNULL( &sa->sa_initial ) &&
693 		sa->sa_initial.bv_len >= index_substr_if_minlen )
694 	{
695 		nkeys++;
696 		if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
697 			( flags & SLAP_INDEX_SUBSTR_ANY ))
698 		{
699 			nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
700 		}
701 	}
702 
703 	if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
704 		ber_len_t i;
705 		for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
706 			if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
707 				/* don't bother accounting with stepping */
708 				nkeys += sa->sa_any[i].bv_len -
709 					( index_substr_any_len - 1 );
710 			}
711 		}
712 	}
713 
714 	if( flags & SLAP_INDEX_SUBSTR_FINAL &&
715 		!BER_BVISNULL( &sa->sa_final ) &&
716 		sa->sa_final.bv_len >= index_substr_if_minlen )
717 	{
718 		nkeys++;
719 		if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
720 			( flags & SLAP_INDEX_SUBSTR_ANY ))
721 		{
722 			nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
723 		}
724 	}
725 
726 	if( nkeys == 0 ) {
727 		*keysp = NULL;
728 		return LDAP_SUCCESS;
729 	}
730 
731 	digest.bv_val = (char *)HASHdigest;
732 	digest.bv_len = sizeof(HASHdigest);
733 
734 	slen = syntax->ssyn_oidlen;
735 	mlen = mr->smr_oidlen;
736 
737 	keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
738 	nkeys = 0;
739 
740 	if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
741 		!BER_BVISNULL( &sa->sa_initial ) &&
742 		sa->sa_initial.bv_len >= index_substr_if_minlen )
743 	{
744 		pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
745 		value = &sa->sa_initial;
746 
747 		klen = index_substr_if_maxlen < value->bv_len
748 			? index_substr_if_maxlen : value->bv_len;
749 
750 		hashPreset( &HASHcontext, prefix, pre, syntax, mr );
751 		hashIter( &HASHcontext, HASHdigest,
752 			(unsigned char *)value->bv_val, klen );
753 		ber_dupbv_x( &keys[nkeys++], &digest, ctx );
754 
755 		/* If initial is too long and we have subany indexed, use it
756 		 * to match the excess...
757 		 */
758 		if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
759 		{
760 			ber_len_t j;
761 			pre = SLAP_INDEX_SUBSTR_PREFIX;
762 			hashPreset( &HASHcontext, prefix, pre, syntax, mr);
763 			for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
764 			{
765 				hashIter( &HASHcontext, HASHdigest,
766 					(unsigned char *)&value->bv_val[j], index_substr_any_len );
767 				ber_dupbv_x( &keys[nkeys++], &digest, ctx );
768 			}
769 		}
770 	}
771 
772 	if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
773 		ber_len_t i, j;
774 		pre = SLAP_INDEX_SUBSTR_PREFIX;
775 		klen = index_substr_any_len;
776 
777 		for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
778 			if( sa->sa_any[i].bv_len < index_substr_any_len ) {
779 				continue;
780 			}
781 
782 			value = &sa->sa_any[i];
783 
784 			hashPreset( &HASHcontext, prefix, pre, syntax, mr);
785 			for(j=0;
786 				j <= value->bv_len - index_substr_any_len;
787 				j += index_substr_any_step )
788 			{
789 				hashIter( &HASHcontext, HASHdigest,
790 					(unsigned char *)&value->bv_val[j], klen );
791 				ber_dupbv_x( &keys[nkeys++], &digest, ctx );
792 			}
793 		}
794 	}
795 
796 	if( flags & SLAP_INDEX_SUBSTR_FINAL &&
797 		!BER_BVISNULL( &sa->sa_final ) &&
798 		sa->sa_final.bv_len >= index_substr_if_minlen )
799 	{
800 		pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
801 		value = &sa->sa_final;
802 
803 		klen = index_substr_if_maxlen < value->bv_len
804 			? index_substr_if_maxlen : value->bv_len;
805 
806 		hashPreset( &HASHcontext, prefix, pre, syntax, mr );
807 		hashIter( &HASHcontext, HASHdigest,
808 			(unsigned char *)&value->bv_val[value->bv_len-klen], klen );
809 		ber_dupbv_x( &keys[nkeys++], &digest, ctx );
810 
811 		/* If final is too long and we have subany indexed, use it
812 		 * to match the excess...
813 		 */
814 		if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
815 		{
816 			ber_len_t j;
817 			pre = SLAP_INDEX_SUBSTR_PREFIX;
818 			hashPreset( &HASHcontext, prefix, pre, syntax, mr);
819 			for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
820 			{
821 				hashIter( &HASHcontext, HASHdigest,
822 					(unsigned char *)&value->bv_val[j], index_substr_any_len );
823 				ber_dupbv_x( &keys[nkeys++], &digest, ctx );
824 			}
825 		}
826 	}
827 
828 	if( nkeys > 0 ) {
829 		BER_BVZERO( &keys[nkeys] );
830 		*keysp = keys;
831 	} else {
832 		ch_free( keys );
833 		*keysp = NULL;
834 	}
835 
836 	return LDAP_SUCCESS;
837 }
838 
839 static int
840 bitStringValidate(
841 	Syntax *syntax,
842 	struct berval *in )
843 {
844 	ber_len_t i;
845 
846 	/* very unforgiving validation, requires no normalization
847 	 * before simplistic matching
848 	 */
849 	if( in->bv_len < 3 ) {
850 		return LDAP_INVALID_SYNTAX;
851 	}
852 
853 	/* RFC 4517 Section 3.3.2 Bit String:
854      *	BitString    = SQUOTE *binary-digit SQUOTE "B"
855      *	binary-digit = "0" / "1"
856 	 *
857 	 * where SQUOTE [RFC4512] is
858 	 *	SQUOTE  = %x27 ; single quote ("'")
859 	 *
860 	 * Example: '0101111101'B
861 	 */
862 
863 	if( in->bv_val[0] != '\'' ||
864 		in->bv_val[in->bv_len - 2] != '\'' ||
865 		in->bv_val[in->bv_len - 1] != 'B' )
866 	{
867 		return LDAP_INVALID_SYNTAX;
868 	}
869 
870 	for( i = in->bv_len - 3; i > 0; i-- ) {
871 		if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
872 			return LDAP_INVALID_SYNTAX;
873 		}
874 	}
875 
876 	return LDAP_SUCCESS;
877 }
878 
879 /*
880  * Syntaxes from RFC 4517
881  *
882 
883 3.3.2.  Bit String
884 
885    A value of the Bit String syntax is a sequence of binary digits.  The
886    LDAP-specific encoding of a value of this syntax is defined by the
887    following ABNF:
888 
889       BitString    = SQUOTE *binary-digit SQUOTE "B"
890 
891       binary-digit = "0" / "1"
892 
893    The <SQUOTE> rule is defined in [MODELS].
894 
895       Example:
896          '0101111101'B
897 
898    The LDAP definition for the Bit String syntax is:
899 
900       ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
901 
902    This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
903 
904    ...
905 
906 3.3.21.  Name and Optional UID
907 
908    A value of the Name and Optional UID syntax is the distinguished name
909    [MODELS] of an entity optionally accompanied by a unique identifier
910    that serves to differentiate the entity from others with an identical
911    distinguished name.
912 
913    The LDAP-specific encoding of a value of this syntax is defined by
914    the following ABNF:
915 
916        NameAndOptionalUID = distinguishedName [ SHARP BitString ]
917 
918    The <BitString> rule is defined in Section 3.3.2.  The
919    <distinguishedName> rule is defined in [LDAPDN].  The <SHARP> rule is
920    defined in [MODELS].
921 
922    Note that although the '#' character may occur in the string
923    representation of a distinguished name, no additional escaping of
924    this character is performed when a <distinguishedName> is encoded in
925    a <NameAndOptionalUID>.
926 
927       Example:
928          1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
929 
930    The LDAP definition for the Name and Optional UID syntax is:
931 
932       ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
933 
934    This syntax corresponds to the NameAndOptionalUID ASN.1 type from
935    [X.520].
936 
937  *
938  * RFC 4512 says:
939  *
940 
941 1.4. Common ABNF Productions
942 
943   ...
944       SHARP   = %x23 ; octothorpe (or sharp sign) ("#")
945   ...
946       SQUOTE  = %x27 ; single quote ("'")
947   ...
948 
949  *
950  * Note: normalization strips any leading "0"s, unless the
951  * bit string is exactly "'0'B", so the normalized example,
952  * in slapd, would result in
953  *
954  * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B
955  *
956  * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
957  * be escaped except when at the beginning of a value, the
958  * definition of Name and Optional UID appears to be flawed,
959  * because there is no clear means to determine whether the
960  * UID part is present or not.
961  *
962  * Example:
963  *
964  * 	cn=Someone,dc=example,dc=com#'1'B
965  *
966  * could be either a NameAndOptionalUID with trailing UID, i.e.
967  *
968  * 	DN = "cn=Someone,dc=example,dc=com"
969  * 	UID = "'1'B"
970  *
971  * or a NameAndOptionalUID with no trailing UID, and the AVA
972  * in the last RDN made of
973  *
974  * 	attributeType = dc
975  * 	attributeValue = com#'1'B
976  *
977  * in fact "com#'1'B" is a valid IA5 string.
978  *
979  * As a consequence, current slapd code assumes that the
980  * presence of portions of a BitString at the end of the string
981  * representation of a NameAndOptionalUID means a BitString
982  * is expected, and cause an error otherwise.  This is quite
983  * arbitrary, and might change in the future.
984  */
985 
986 
987 static int
988 nameUIDValidate(
989 	Syntax *syntax,
990 	struct berval *in )
991 {
992 	int rc;
993 	struct berval dn, uid;
994 
995 	if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
996 
997 	ber_dupbv( &dn, in );
998 	if( !dn.bv_val ) return LDAP_OTHER;
999 
1000 	/* if there's a "#", try bitStringValidate()... */
1001 	uid.bv_val = strrchr( dn.bv_val, '#' );
1002 	if ( !BER_BVISNULL( &uid ) ) {
1003 		uid.bv_val++;
1004 		uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1005 
1006 		rc = bitStringValidate( NULL, &uid );
1007 		if ( rc == LDAP_SUCCESS ) {
1008 			/* in case of success, trim the UID,
1009 			 * otherwise treat it as part of the DN */
1010 			dn.bv_len -= uid.bv_len + 1;
1011 			uid.bv_val[-1] = '\0';
1012 		}
1013 	}
1014 
1015 	rc = dnValidate( NULL, &dn );
1016 
1017 	ber_memfree( dn.bv_val );
1018 	return rc;
1019 }
1020 
1021 int
1022 nameUIDPretty(
1023 	Syntax *syntax,
1024 	struct berval *val,
1025 	struct berval *out,
1026 	void *ctx )
1027 {
1028 	assert( val != NULL );
1029 	assert( out != NULL );
1030 
1031 
1032 	Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1033 
1034 	if( BER_BVISEMPTY( val ) ) {
1035 		ber_dupbv_x( out, val, ctx );
1036 
1037 	} else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1038 		return LDAP_INVALID_SYNTAX;
1039 
1040 	} else {
1041 		int		rc;
1042 		struct berval	dnval = *val;
1043 		struct berval	uidval = BER_BVNULL;
1044 
1045 		uidval.bv_val = strrchr( val->bv_val, '#' );
1046 		if ( !BER_BVISNULL( &uidval ) ) {
1047 			uidval.bv_val++;
1048 			uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1049 
1050 			rc = bitStringValidate( NULL, &uidval );
1051 
1052 			if ( rc == LDAP_SUCCESS ) {
1053 				ber_dupbv_x( &dnval, val, ctx );
1054 				dnval.bv_len -= uidval.bv_len + 1;
1055 				dnval.bv_val[dnval.bv_len] = '\0';
1056 
1057 			} else {
1058 				BER_BVZERO( &uidval );
1059 			}
1060 		}
1061 
1062 		rc = dnPretty( syntax, &dnval, out, ctx );
1063 		if ( dnval.bv_val != val->bv_val ) {
1064 			slap_sl_free( dnval.bv_val, ctx );
1065 		}
1066 		if( rc != LDAP_SUCCESS ) {
1067 			return rc;
1068 		}
1069 
1070 		if( !BER_BVISNULL( &uidval ) ) {
1071 			int	i, c, got1;
1072 			char	*tmp;
1073 
1074 			tmp = slap_sl_realloc( out->bv_val, out->bv_len
1075 				+ STRLENOF( "#" ) + uidval.bv_len + 1,
1076 				ctx );
1077 			if( tmp == NULL ) {
1078 				ber_memfree_x( out->bv_val, ctx );
1079 				return LDAP_OTHER;
1080 			}
1081 			out->bv_val = tmp;
1082 			out->bv_val[out->bv_len++] = '#';
1083 			out->bv_val[out->bv_len++] = '\'';
1084 
1085 			got1 = uidval.bv_len < sizeof("'0'B");
1086 			for( i = 1; i < uidval.bv_len - 2; i++ ) {
1087 				c = uidval.bv_val[i];
1088 				switch(c) {
1089 					case '0':
1090 						if( got1 ) out->bv_val[out->bv_len++] = c;
1091 						break;
1092 					case '1':
1093 						got1 = 1;
1094 						out->bv_val[out->bv_len++] = c;
1095 						break;
1096 				}
1097 			}
1098 
1099 			out->bv_val[out->bv_len++] = '\'';
1100 			out->bv_val[out->bv_len++] = 'B';
1101 			out->bv_val[out->bv_len] = '\0';
1102 		}
1103 	}
1104 
1105 	Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1106 
1107 	return LDAP_SUCCESS;
1108 }
1109 
1110 static int
1111 uniqueMemberNormalize(
1112 	slap_mask_t usage,
1113 	Syntax *syntax,
1114 	MatchingRule *mr,
1115 	struct berval *val,
1116 	struct berval *normalized,
1117 	void *ctx )
1118 {
1119 	struct berval out;
1120 	int rc;
1121 
1122 	assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1123 
1124 	ber_dupbv_x( &out, val, ctx );
1125 	if ( BER_BVISEMPTY( &out ) ) {
1126 		*normalized = out;
1127 
1128 	} else {
1129 		struct berval uid = BER_BVNULL;
1130 
1131 		uid.bv_val = strrchr( out.bv_val, '#' );
1132 		if ( !BER_BVISNULL( &uid ) ) {
1133 			uid.bv_val++;
1134 			uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1135 
1136 			rc = bitStringValidate( NULL, &uid );
1137 			if ( rc == LDAP_SUCCESS ) {
1138 				uid.bv_val[-1] = '\0';
1139 				out.bv_len -= uid.bv_len + 1;
1140 			} else {
1141 				BER_BVZERO( &uid );
1142 			}
1143 		}
1144 
1145 		rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1146 
1147 		if( rc != LDAP_SUCCESS ) {
1148 			slap_sl_free( out.bv_val, ctx );
1149 			return LDAP_INVALID_SYNTAX;
1150 		}
1151 
1152 		if( !BER_BVISNULL( &uid ) ) {
1153 			char	*tmp;
1154 
1155 			tmp = ch_realloc( normalized->bv_val,
1156 				normalized->bv_len + uid.bv_len
1157 				+ STRLENOF("#") + 1 );
1158 			if ( tmp == NULL ) {
1159 				ber_memfree_x( normalized->bv_val, ctx );
1160 				return LDAP_OTHER;
1161 			}
1162 
1163 			normalized->bv_val = tmp;
1164 
1165 			/* insert the separator */
1166 			normalized->bv_val[normalized->bv_len++] = '#';
1167 
1168 			/* append the UID */
1169 			AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1170 				uid.bv_val, uid.bv_len );
1171 			normalized->bv_len += uid.bv_len;
1172 
1173 			/* terminate */
1174 			normalized->bv_val[normalized->bv_len] = '\0';
1175 		}
1176 
1177 		slap_sl_free( out.bv_val, ctx );
1178 	}
1179 
1180 	return LDAP_SUCCESS;
1181 }
1182 
1183 static int
1184 uniqueMemberMatch(
1185 	int *matchp,
1186 	slap_mask_t flags,
1187 	Syntax *syntax,
1188 	MatchingRule *mr,
1189 	struct berval *value,
1190 	void *assertedValue )
1191 {
1192 	int match;
1193 	struct berval *asserted = (struct berval *) assertedValue;
1194 	struct berval assertedDN = *asserted;
1195 	struct berval assertedUID = BER_BVNULL;
1196 	struct berval valueDN = *value;
1197 	struct berval valueUID = BER_BVNULL;
1198 	int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1199 
1200 	if ( !BER_BVISEMPTY( asserted ) ) {
1201 		assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1202 		if ( !BER_BVISNULL( &assertedUID ) ) {
1203 			assertedUID.bv_val++;
1204 			assertedUID.bv_len = assertedDN.bv_len
1205 				- ( assertedUID.bv_val - assertedDN.bv_val );
1206 
1207 			if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1208 				assertedDN.bv_len -= assertedUID.bv_len + 1;
1209 
1210 			} else {
1211 				BER_BVZERO( &assertedUID );
1212 			}
1213 		}
1214 	}
1215 
1216 	if ( !BER_BVISEMPTY( value ) ) {
1217 
1218 		valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1219 		if ( !BER_BVISNULL( &valueUID ) ) {
1220 			valueUID.bv_val++;
1221 			valueUID.bv_len = valueDN.bv_len
1222 				- ( valueUID.bv_val - valueDN.bv_val );
1223 
1224 			if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1225 				valueDN.bv_len -= valueUID.bv_len + 1;
1226 
1227 			} else {
1228 				BER_BVZERO( &valueUID );
1229 			}
1230 		}
1231 	}
1232 
1233 	if( valueUID.bv_len && assertedUID.bv_len ) {
1234 		match = valueUID.bv_len - assertedUID.bv_len;
1235 		if ( match ) {
1236 			*matchp = match;
1237 			return LDAP_SUCCESS;
1238 		}
1239 
1240 		match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1241 		if( match ) {
1242 			*matchp = match;
1243 			return LDAP_SUCCESS;
1244 		}
1245 
1246 	} else if ( !approx && valueUID.bv_len ) {
1247 		match = -1;
1248 		*matchp = match;
1249 		return LDAP_SUCCESS;
1250 
1251 	} else if ( !approx && assertedUID.bv_len ) {
1252 		match = 1;
1253 		*matchp = match;
1254 		return LDAP_SUCCESS;
1255 	}
1256 
1257 	return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1258 }
1259 
1260 static int
1261 uniqueMemberIndexer(
1262 	slap_mask_t use,
1263 	slap_mask_t flags,
1264 	Syntax *syntax,
1265 	MatchingRule *mr,
1266 	struct berval *prefix,
1267 	BerVarray values,
1268 	BerVarray *keysp,
1269 	void *ctx )
1270 {
1271 	BerVarray dnvalues;
1272 	int rc;
1273 	int i;
1274 	for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1275 		/* just count them */
1276 	}
1277 	assert( i > 0 );
1278 
1279 	dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1280 
1281 	for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1282 		struct berval assertedDN = values[i];
1283 		struct berval assertedUID = BER_BVNULL;
1284 
1285 		if ( !BER_BVISEMPTY( &assertedDN ) ) {
1286 			assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1287 			if ( !BER_BVISNULL( &assertedUID ) ) {
1288 				assertedUID.bv_val++;
1289 				assertedUID.bv_len = assertedDN.bv_len
1290 					- ( assertedUID.bv_val - assertedDN.bv_val );
1291 
1292 				if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1293 					assertedDN.bv_len -= assertedUID.bv_len + 1;
1294 
1295 				} else {
1296 					BER_BVZERO( &assertedUID );
1297 				}
1298 			}
1299 		}
1300 
1301 		dnvalues[i] = assertedDN;
1302 	}
1303 	BER_BVZERO( &dnvalues[i] );
1304 
1305 	rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1306 		dnvalues, keysp, ctx );
1307 
1308 	slap_sl_free( dnvalues, ctx );
1309 	return rc;
1310 }
1311 
1312 static int
1313 uniqueMemberFilter(
1314 	slap_mask_t use,
1315 	slap_mask_t flags,
1316 	Syntax *syntax,
1317 	MatchingRule *mr,
1318 	struct berval *prefix,
1319 	void * assertedValue,
1320 	BerVarray *keysp,
1321 	void *ctx )
1322 {
1323 	struct berval *asserted = (struct berval *) assertedValue;
1324 	struct berval assertedDN = *asserted;
1325 	struct berval assertedUID = BER_BVNULL;
1326 
1327 	if ( !BER_BVISEMPTY( asserted ) ) {
1328 		assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1329 		if ( !BER_BVISNULL( &assertedUID ) ) {
1330 			assertedUID.bv_val++;
1331 			assertedUID.bv_len = assertedDN.bv_len
1332 				- ( assertedUID.bv_val - assertedDN.bv_val );
1333 
1334 			if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1335 				assertedDN.bv_len -= assertedUID.bv_len + 1;
1336 
1337 			} else {
1338 				BER_BVZERO( &assertedUID );
1339 			}
1340 		}
1341 	}
1342 
1343 	return octetStringFilter( use, flags, syntax, mr, prefix,
1344 		&assertedDN, keysp, ctx );
1345 }
1346 
1347 
1348 /*
1349  * Handling boolean syntax and matching is quite rigid.
1350  * A more flexible approach would be to allow a variety
1351  * of strings to be normalized and prettied into TRUE
1352  * and FALSE.
1353  */
1354 static int
1355 booleanValidate(
1356 	Syntax *syntax,
1357 	struct berval *in )
1358 {
1359 	/* very unforgiving validation, requires no normalization
1360 	 * before simplistic matching
1361 	 */
1362 
1363 	if( in->bv_len == 4 ) {
1364 		if( bvmatch( in, &slap_true_bv ) ) {
1365 			return LDAP_SUCCESS;
1366 		}
1367 	} else if( in->bv_len == 5 ) {
1368 		if( bvmatch( in, &slap_false_bv ) ) {
1369 			return LDAP_SUCCESS;
1370 		}
1371 	}
1372 
1373 	return LDAP_INVALID_SYNTAX;
1374 }
1375 
1376 static int
1377 booleanMatch(
1378 	int *matchp,
1379 	slap_mask_t flags,
1380 	Syntax *syntax,
1381 	MatchingRule *mr,
1382 	struct berval *value,
1383 	void *assertedValue )
1384 {
1385 	/* simplistic matching allowed by rigid validation */
1386 	struct berval *asserted = (struct berval *) assertedValue;
1387 	*matchp = value->bv_len != asserted->bv_len;
1388 	return LDAP_SUCCESS;
1389 }
1390 
1391 /*-------------------------------------------------------------------
1392 LDAP/X.500 string syntax / matching rules have a few oddities.  This
1393 comment attempts to detail how slapd(8) treats them.
1394 
1395 Summary:
1396   StringSyntax		X.500	LDAP	Matching/Comments
1397   DirectoryString	CHOICE	UTF8	i/e + ignore insignificant spaces
1398   PrintableString	subset	subset	i/e + ignore insignificant spaces
1399   PrintableString	subset	subset	i/e + ignore insignificant spaces
1400   NumericString		subset	subset	ignore all spaces
1401   IA5String			ASCII	ASCII	i/e + ignore insignificant spaces
1402   TeletexString		T.61	T.61	i/e + ignore insignificant spaces
1403 
1404   TelephoneNumber	subset	subset	i + ignore all spaces and "-"
1405 
1406   See RFC 4518 for details.
1407 
1408 
1409 Directory String -
1410   In X.500(93), a directory string can be either a PrintableString,
1411   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1412   In later versions, more CHOICEs were added.  In all cases the string
1413   must be non-empty.
1414 
1415   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1416   A directory string cannot be zero length.
1417 
1418   For matching, there are both case ignore and exact rules.  Both
1419   also require that "insignificant" spaces be ignored.
1420 	spaces before the first non-space are ignored;
1421 	spaces after the last non-space are ignored;
1422 	spaces after a space are ignored.
1423   Note: by these rules (and as clarified in X.520), a string of only
1424   spaces is to be treated as if held one space, not empty (which
1425   would be a syntax error).
1426 
1427 NumericString
1428   In ASN.1, numeric string is just a string of digits and spaces
1429   and could be empty.  However, in X.500, all attribute values of
1430   numeric string carry a non-empty constraint.  For example:
1431 
1432 	internationalISDNNumber ATTRIBUTE ::= {
1433 		WITH SYNTAX InternationalISDNNumber
1434 		EQUALITY MATCHING RULE numericStringMatch
1435 		SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1436 		ID id-at-internationalISDNNumber }
1437 	InternationalISDNNumber ::=
1438 	    NumericString (SIZE(1..ub-international-isdn-number))
1439 
1440   Unforunately, some assertion values are don't carry the same
1441   constraint (but its unclear how such an assertion could ever
1442   be true). In LDAP, there is one syntax (numericString) not two
1443   (numericString with constraint, numericString without constraint).
1444   This should be treated as numericString with non-empty constraint.
1445   Note that while someone may have no ISDN number, there are no ISDN
1446   numbers which are zero length.
1447 
1448   In matching, spaces are ignored.
1449 
1450 PrintableString
1451   In ASN.1, Printable string is just a string of printable characters
1452   and can be empty.  In X.500, semantics much like NumericString (see
1453   serialNumber for a like example) excepting uses insignificant space
1454   handling instead of ignore all spaces.  They must be non-empty.
1455 
1456 IA5String
1457   Basically same as PrintableString.  There are no examples in X.500,
1458   but same logic applies.  Empty strings are allowed.
1459 
1460 -------------------------------------------------------------------*/
1461 
1462 static int
1463 UTF8StringValidate(
1464 	Syntax *syntax,
1465 	struct berval *in )
1466 {
1467 	ber_len_t count;
1468 	int len;
1469 	unsigned char *u = (unsigned char *)in->bv_val;
1470 
1471 	if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1472 		/* directory strings cannot be empty */
1473 		return LDAP_INVALID_SYNTAX;
1474 	}
1475 
1476 	for( count = in->bv_len; count > 0; count -= len, u += len ) {
1477 		/* get the length indicated by the first byte */
1478 		len = LDAP_UTF8_CHARLEN2( u, len );
1479 
1480 		/* very basic checks */
1481 		switch( len ) {
1482 			case 6:
1483 				if( (u[5] & 0xC0) != 0x80 ) {
1484 					return LDAP_INVALID_SYNTAX;
1485 				}
1486 			case 5:
1487 				if( (u[4] & 0xC0) != 0x80 ) {
1488 					return LDAP_INVALID_SYNTAX;
1489 				}
1490 			case 4:
1491 				if( (u[3] & 0xC0) != 0x80 ) {
1492 					return LDAP_INVALID_SYNTAX;
1493 				}
1494 			case 3:
1495 				if( (u[2] & 0xC0 )!= 0x80 ) {
1496 					return LDAP_INVALID_SYNTAX;
1497 				}
1498 			case 2:
1499 				if( (u[1] & 0xC0) != 0x80 ) {
1500 					return LDAP_INVALID_SYNTAX;
1501 				}
1502 			case 1:
1503 				/* CHARLEN already validated it */
1504 				break;
1505 			default:
1506 				return LDAP_INVALID_SYNTAX;
1507 		}
1508 
1509 		/* make sure len corresponds with the offset
1510 			to the next character */
1511 		if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1512 	}
1513 
1514 	if( count != 0 ) {
1515 		return LDAP_INVALID_SYNTAX;
1516 	}
1517 
1518 	return LDAP_SUCCESS;
1519 }
1520 
1521 static int
1522 UTF8StringNormalize(
1523 	slap_mask_t use,
1524 	Syntax *syntax,
1525 	MatchingRule *mr,
1526 	struct berval *val,
1527 	struct berval *normalized,
1528 	void *ctx )
1529 {
1530 	struct berval tmp, nvalue;
1531 	int flags;
1532 	int i, wasspace;
1533 
1534 	assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1535 
1536 	if( BER_BVISNULL( val ) ) {
1537 		/* assume we're dealing with a syntax (e.g., UTF8String)
1538 		 * which allows empty strings
1539 		 */
1540 		BER_BVZERO( normalized );
1541 		return LDAP_SUCCESS;
1542 	}
1543 
1544 	flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1545 		? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1546 	flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1547 		? LDAP_UTF8_APPROX : 0;
1548 
1549 	val = UTF8bvnormalize( val, &tmp, flags, ctx );
1550 	if( val == NULL ) {
1551 		return LDAP_OTHER;
1552 	}
1553 
1554 	/* collapse spaces (in place) */
1555 	nvalue.bv_len = 0;
1556 	nvalue.bv_val = tmp.bv_val;
1557 
1558 	/* trim leading spaces? */
1559 	wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1560 		(( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1561 
1562 	for( i = 0; i < tmp.bv_len; i++) {
1563 		if ( ASCII_SPACE( tmp.bv_val[i] )) {
1564 			if( wasspace++ == 0 ) {
1565 				/* trim repeated spaces */
1566 				nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1567 			}
1568 		} else {
1569 			wasspace = 0;
1570 			nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1571 		}
1572 	}
1573 
1574 	if( !BER_BVISEMPTY( &nvalue ) ) {
1575 		/* trim trailing space? */
1576 		if( wasspace && (
1577 			(( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1578 			( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1579 		{
1580 			--nvalue.bv_len;
1581 		}
1582 		nvalue.bv_val[nvalue.bv_len] = '\0';
1583 
1584 	} else {
1585 		/* string of all spaces is treated as one space */
1586 		nvalue.bv_val[0] = ' ';
1587 		nvalue.bv_val[1] = '\0';
1588 		nvalue.bv_len = 1;
1589 	}
1590 
1591 	*normalized = nvalue;
1592 	return LDAP_SUCCESS;
1593 }
1594 
1595 static int
1596 directoryStringSubstringsMatch(
1597 	int *matchp,
1598 	slap_mask_t flags,
1599 	Syntax *syntax,
1600 	MatchingRule *mr,
1601 	struct berval *value,
1602 	void *assertedValue )
1603 {
1604 	int match = 0;
1605 	SubstringsAssertion *sub = assertedValue;
1606 	struct berval left = *value;
1607 	int i;
1608 	int priorspace=0;
1609 
1610 	if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1611 		if ( sub->sa_initial.bv_len > left.bv_len ) {
1612 			/* not enough left */
1613 			match = 1;
1614 			goto done;
1615 		}
1616 
1617 		match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1618 			sub->sa_initial.bv_len );
1619 
1620 		if ( match != 0 ) {
1621 			goto done;
1622 		}
1623 
1624 		left.bv_val += sub->sa_initial.bv_len;
1625 		left.bv_len -= sub->sa_initial.bv_len;
1626 
1627 		priorspace = ASCII_SPACE(
1628 			sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1629 	}
1630 
1631 	if ( sub->sa_any ) {
1632 		for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1633 			ber_len_t idx;
1634 			char *p;
1635 
1636 			if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] )
1637 				&& ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1638 			{
1639 				/* allow next space to match */
1640 				left.bv_val--;
1641 				left.bv_len++;
1642 			}
1643 			priorspace=0;
1644 
1645 retry:
1646 			if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1647 				continue;
1648 			}
1649 
1650 			if ( sub->sa_any[i].bv_len > left.bv_len ) {
1651 				/* not enough left */
1652 				match = 1;
1653 				goto done;
1654 			}
1655 
1656 			p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1657 
1658 			if( p == NULL ) {
1659 				match = 1;
1660 				goto done;
1661 			}
1662 
1663 			idx = p - left.bv_val;
1664 
1665 			if ( idx >= left.bv_len ) {
1666 				/* this shouldn't happen */
1667 				return LDAP_OTHER;
1668 			}
1669 
1670 			left.bv_val = p;
1671 			left.bv_len -= idx;
1672 
1673 			if ( sub->sa_any[i].bv_len > left.bv_len ) {
1674 				/* not enough left */
1675 				match = 1;
1676 				goto done;
1677 			}
1678 
1679 			match = memcmp( left.bv_val,
1680 				sub->sa_any[i].bv_val,
1681 				sub->sa_any[i].bv_len );
1682 
1683 			if ( match != 0 ) {
1684 				left.bv_val++;
1685 				left.bv_len--;
1686 				goto retry;
1687 			}
1688 
1689 			left.bv_val += sub->sa_any[i].bv_len;
1690 			left.bv_len -= sub->sa_any[i].bv_len;
1691 
1692 			priorspace = ASCII_SPACE(
1693 				sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1694 		}
1695 	}
1696 
1697 	if ( !BER_BVISNULL( &sub->sa_final ) ) {
1698 		if( priorspace && !BER_BVISEMPTY( &sub->sa_final )
1699 			&& ASCII_SPACE( sub->sa_final.bv_val[0] ))
1700 		{
1701 			/* allow next space to match */
1702 			left.bv_val--;
1703 			left.bv_len++;
1704 		}
1705 
1706 		if ( sub->sa_final.bv_len > left.bv_len ) {
1707 			/* not enough left */
1708 			match = 1;
1709 			goto done;
1710 		}
1711 
1712 		match = memcmp( sub->sa_final.bv_val,
1713 			&left.bv_val[left.bv_len - sub->sa_final.bv_len],
1714 			sub->sa_final.bv_len );
1715 
1716 		if ( match != 0 ) {
1717 			goto done;
1718 		}
1719 	}
1720 
1721 done:
1722 	*matchp = match;
1723 	return LDAP_SUCCESS;
1724 }
1725 
1726 #if defined(SLAPD_APPROX_INITIALS)
1727 #	define SLAPD_APPROX_DELIMITER "._ "
1728 #	define SLAPD_APPROX_WORDLEN 2
1729 #else
1730 #	define SLAPD_APPROX_DELIMITER " "
1731 #	define SLAPD_APPROX_WORDLEN 1
1732 #endif
1733 
1734 static int
1735 approxMatch(
1736 	int *matchp,
1737 	slap_mask_t flags,
1738 	Syntax *syntax,
1739 	MatchingRule *mr,
1740 	struct berval *value,
1741 	void *assertedValue )
1742 {
1743 	struct berval *nval, *assertv;
1744 	char *val, **values, **words, *c;
1745 	int i, count, len, nextchunk=0, nextavail=0;
1746 
1747 	/* Yes, this is necessary */
1748 	nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1749 	if( nval == NULL ) {
1750 		*matchp = 1;
1751 		return LDAP_SUCCESS;
1752 	}
1753 
1754 	/* Yes, this is necessary */
1755 	assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1756 		NULL, LDAP_UTF8_APPROX, NULL );
1757 	if( assertv == NULL ) {
1758 		ber_bvfree( nval );
1759 		*matchp = 1;
1760 		return LDAP_SUCCESS;
1761 	}
1762 
1763 	/* Isolate how many words there are */
1764 	for ( c = nval->bv_val, count = 1; *c; c++ ) {
1765 		c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1766 		if ( c == NULL ) break;
1767 		*c = '\0';
1768 		count++;
1769 	}
1770 
1771 	/* Get a phonetic copy of each word */
1772 	words = (char **)ch_malloc( count * sizeof(char *) );
1773 	values = (char **)ch_malloc( count * sizeof(char *) );
1774 	for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1775 		words[i] = c;
1776 		values[i] = phonetic(c);
1777 	}
1778 
1779 	/* Work through the asserted value's words, to see if at least some
1780 	   of the words are there, in the same order. */
1781 	len = 0;
1782 	while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1783 		len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1784 		if( len == 0 ) {
1785 			nextchunk++;
1786 			continue;
1787 		}
1788 #if defined(SLAPD_APPROX_INITIALS)
1789 		else if( len == 1 ) {
1790 			/* Single letter words need to at least match one word's initial */
1791 			for( i=nextavail; i<count; i++ )
1792 				if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1793 					nextavail=i+1;
1794 					break;
1795 				}
1796 		}
1797 #endif
1798 		else {
1799 			/* Isolate the next word in the asserted value and phonetic it */
1800 			assertv->bv_val[nextchunk+len] = '\0';
1801 			val = phonetic( assertv->bv_val + nextchunk );
1802 
1803 			/* See if this phonetic chunk is in the remaining words of *value */
1804 			for( i=nextavail; i<count; i++ ){
1805 				if( !strcmp( val, values[i] ) ){
1806 					nextavail = i+1;
1807 					break;
1808 				}
1809 			}
1810 			ch_free( val );
1811 		}
1812 
1813 		/* This chunk in the asserted value was NOT within the *value. */
1814 		if( i >= count ) {
1815 			nextavail=-1;
1816 			break;
1817 		}
1818 
1819 		/* Go on to the next word in the asserted value */
1820 		nextchunk += len+1;
1821 	}
1822 
1823 	/* If some of the words were seen, call it a match */
1824 	if( nextavail > 0 ) {
1825 		*matchp = 0;
1826 	}
1827 	else {
1828 		*matchp = 1;
1829 	}
1830 
1831 	/* Cleanup allocs */
1832 	ber_bvfree( assertv );
1833 	for( i=0; i<count; i++ ) {
1834 		ch_free( values[i] );
1835 	}
1836 	ch_free( values );
1837 	ch_free( words );
1838 	ber_bvfree( nval );
1839 
1840 	return LDAP_SUCCESS;
1841 }
1842 
1843 static int
1844 approxIndexer(
1845 	slap_mask_t use,
1846 	slap_mask_t flags,
1847 	Syntax *syntax,
1848 	MatchingRule *mr,
1849 	struct berval *prefix,
1850 	BerVarray values,
1851 	BerVarray *keysp,
1852 	void *ctx )
1853 {
1854 	char *c;
1855 	int i,j, len, wordcount, keycount=0;
1856 	struct berval *newkeys;
1857 	BerVarray keys=NULL;
1858 
1859 	for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1860 		struct berval val = BER_BVNULL;
1861 		/* Yes, this is necessary */
1862 		UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1863 		assert( !BER_BVISNULL( &val ) );
1864 
1865 		/* Isolate how many words there are. There will be a key for each */
1866 		for( wordcount = 0, c = val.bv_val; *c; c++) {
1867 			len = strcspn(c, SLAPD_APPROX_DELIMITER);
1868 			if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1869 			c+= len;
1870 			if (*c == '\0') break;
1871 			*c = '\0';
1872 		}
1873 
1874 		/* Allocate/increase storage to account for new keys */
1875 		newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1)
1876 			* sizeof(struct berval) );
1877 		AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1878 		if( keys ) ch_free( keys );
1879 		keys = newkeys;
1880 
1881 		/* Get a phonetic copy of each word */
1882 		for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1883 			len = strlen( c );
1884 			if( len < SLAPD_APPROX_WORDLEN ) continue;
1885 			ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1886 			keycount++;
1887 			i++;
1888 		}
1889 
1890 		ber_memfree( val.bv_val );
1891 	}
1892 	BER_BVZERO( &keys[keycount] );
1893 	*keysp = keys;
1894 
1895 	return LDAP_SUCCESS;
1896 }
1897 
1898 static int
1899 approxFilter(
1900 	slap_mask_t use,
1901 	slap_mask_t flags,
1902 	Syntax *syntax,
1903 	MatchingRule *mr,
1904 	struct berval *prefix,
1905 	void * assertedValue,
1906 	BerVarray *keysp,
1907 	void *ctx )
1908 {
1909 	char *c;
1910 	int i, count, len;
1911 	struct berval *val;
1912 	BerVarray keys;
1913 
1914 	/* Yes, this is necessary */
1915 	val = UTF8bvnormalize( ((struct berval *)assertedValue),
1916 		NULL, LDAP_UTF8_APPROX, NULL );
1917 	if( val == NULL || BER_BVISNULL( val ) ) {
1918 		keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1919 		BER_BVZERO( &keys[0] );
1920 		*keysp = keys;
1921 		ber_bvfree( val );
1922 		return LDAP_SUCCESS;
1923 	}
1924 
1925 	/* Isolate how many words there are. There will be a key for each */
1926 	for( count = 0,c = val->bv_val; *c; c++) {
1927 		len = strcspn(c, SLAPD_APPROX_DELIMITER);
1928 		if( len >= SLAPD_APPROX_WORDLEN ) count++;
1929 		c+= len;
1930 		if (*c == '\0') break;
1931 		*c = '\0';
1932 	}
1933 
1934 	/* Allocate storage for new keys */
1935 	keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1936 
1937 	/* Get a phonetic copy of each word */
1938 	for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1939 		len = strlen(c);
1940 		if( len < SLAPD_APPROX_WORDLEN ) continue;
1941 		ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1942 		i++;
1943 	}
1944 
1945 	ber_bvfree( val );
1946 
1947 	BER_BVZERO( &keys[count] );
1948 	*keysp = keys;
1949 
1950 	return LDAP_SUCCESS;
1951 }
1952 
1953 /* Remove all spaces and '-' characters */
1954 static int
1955 telephoneNumberNormalize(
1956 	slap_mask_t usage,
1957 	Syntax *syntax,
1958 	MatchingRule *mr,
1959 	struct berval *val,
1960 	struct berval *normalized,
1961 	void *ctx )
1962 {
1963 	char *p, *q;
1964 
1965 	assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1966 
1967 	/* validator should have refused an empty string */
1968 	assert( !BER_BVISEMPTY( val ) );
1969 
1970 	q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1971 
1972 	for( p = val->bv_val; *p; p++ ) {
1973 		if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1974 			*q++ = *p;
1975 		}
1976 	}
1977 	*q = '\0';
1978 
1979 	normalized->bv_len = q - normalized->bv_val;
1980 
1981 	if( BER_BVISEMPTY( normalized ) ) {
1982 		slap_sl_free( normalized->bv_val, ctx );
1983 		BER_BVZERO( normalized );
1984 		return LDAP_INVALID_SYNTAX;
1985 	}
1986 
1987 	return LDAP_SUCCESS;
1988 }
1989 
1990 int
1991 numericoidValidate(
1992 	Syntax *syntax,
1993 	struct berval *in )
1994 {
1995 	struct berval val = *in;
1996 
1997 	if( BER_BVISEMPTY( &val ) ) {
1998 		/* disallow empty strings */
1999 		return LDAP_INVALID_SYNTAX;
2000 	}
2001 
2002 	while( OID_LEADCHAR( val.bv_val[0] ) ) {
2003 		if ( val.bv_len == 1 ) {
2004 			return LDAP_SUCCESS;
2005 		}
2006 
2007 		if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2008 			break;
2009 		}
2010 
2011 		val.bv_val++;
2012 		val.bv_len--;
2013 
2014 		while ( OID_LEADCHAR( val.bv_val[0] )) {
2015 			val.bv_val++;
2016 			val.bv_len--;
2017 
2018 			if ( val.bv_len == 0 ) {
2019 				return LDAP_SUCCESS;
2020 			}
2021 		}
2022 
2023 		if( !OID_SEPARATOR( val.bv_val[0] )) {
2024 			break;
2025 		}
2026 
2027 		val.bv_val++;
2028 		val.bv_len--;
2029 	}
2030 
2031 	return LDAP_INVALID_SYNTAX;
2032 }
2033 
2034 static int
2035 integerValidate(
2036 	Syntax *syntax,
2037 	struct berval *in )
2038 {
2039 	ber_len_t i;
2040 	struct berval val = *in;
2041 
2042 	if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2043 
2044 	if ( val.bv_val[0] == '-' ) {
2045 		val.bv_len--;
2046 		val.bv_val++;
2047 
2048 		if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2049 			return LDAP_INVALID_SYNTAX;
2050 		}
2051 
2052 		if( val.bv_val[0] == '0' ) { /* "-0" */
2053 			return LDAP_INVALID_SYNTAX;
2054 		}
2055 
2056 	} else if ( val.bv_val[0] == '0' ) {
2057 		if( val.bv_len > 1 ) { /* "0<more>" */
2058 			return LDAP_INVALID_SYNTAX;
2059 		}
2060 
2061 		return LDAP_SUCCESS;
2062 	}
2063 
2064 	for( i=0; i < val.bv_len; i++ ) {
2065 		if( !ASCII_DIGIT(val.bv_val[i]) ) {
2066 			return LDAP_INVALID_SYNTAX;
2067 		}
2068 	}
2069 
2070 	return LDAP_SUCCESS;
2071 }
2072 
2073 static int
2074 integerMatch(
2075 	int *matchp,
2076 	slap_mask_t flags,
2077 	Syntax *syntax,
2078 	MatchingRule *mr,
2079 	struct berval *value,
2080 	void *assertedValue )
2081 {
2082 	struct berval *asserted = (struct berval *) assertedValue;
2083 	int vsign = 1, asign = 1;	/* default sign = '+' */
2084 	struct berval v, a;
2085 	int match;
2086 
2087 	v = *value;
2088 	if( v.bv_val[0] == '-' ) {
2089 		vsign = -1;
2090 		v.bv_val++;
2091 		v.bv_len--;
2092 	}
2093 
2094 	if( BER_BVISEMPTY( &v ) ) vsign = 0;
2095 
2096 	a = *asserted;
2097 	if( a.bv_val[0] == '-' ) {
2098 		asign = -1;
2099 		a.bv_val++;
2100 		a.bv_len--;
2101 	}
2102 
2103 	if( BER_BVISEMPTY( &a ) ) vsign = 0;
2104 
2105 	match = vsign - asign;
2106 	if( match == 0 ) {
2107 		match = ( v.bv_len != a.bv_len
2108 			? ( v.bv_len < a.bv_len ? -1 : 1 )
2109 			: memcmp( v.bv_val, a.bv_val, v.bv_len ));
2110 		if( vsign < 0 ) match = -match;
2111 	}
2112 
2113 	*matchp = match;
2114 	return LDAP_SUCCESS;
2115 }
2116 
2117 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2118 #define INDEX_INTLEN_CHOP 7
2119 #define INDEX_INTLEN_CHOPBYTES 3
2120 
2121 static int
2122 integerVal2Key(
2123 	struct berval *in,
2124 	struct berval *key,
2125 	struct berval *tmp,
2126 	void *ctx )
2127 {
2128 	/* index format:
2129 	 * only if too large: one's complement <sign*exponent (chopped bytes)>,
2130 	 * two's complement value (sign-extended or chopped as needed),
2131 	 * however the top <number of exponent-bytes + 1> bits of first byte
2132 	 * above is the inverse sign.   The next bit is the sign as delimiter.
2133 	 */
2134 	ber_slen_t k = index_intlen_strlen;
2135 	ber_len_t chop = 0;
2136 	unsigned signmask = ~0x7fU;
2137 	unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2138 	struct berval val = *in, itmp = *tmp;
2139 
2140 	if ( val.bv_val[0] != '-' ) {
2141 		neg = 0;
2142 		--k;
2143 	}
2144 
2145 	/* Chop least significant digits, increase length instead */
2146 	if ( val.bv_len > (ber_len_t) k ) {
2147 		chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2148 		val.bv_len -= chop * INDEX_INTLEN_CHOP;	/* #digits chopped */
2149 		chop *= INDEX_INTLEN_CHOPBYTES;		/* #bytes added */
2150 	}
2151 
2152 	if ( lutil_str2bin( &val, &itmp, ctx )) {
2153 		return LDAP_INVALID_SYNTAX;
2154 	}
2155 
2156 	/* Omit leading sign byte */
2157 	if ( itmp.bv_val[0] == neg ) {
2158 		itmp.bv_val++;
2159 		itmp.bv_len--;
2160 	}
2161 
2162 	k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2163 	if ( k > 0 ) {
2164 		assert( chop == 0 );
2165 		memset( key->bv_val, neg, k );	/* sign-extend */
2166 	} else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2167 		lenp = lenbuf + sizeof(lenbuf);
2168 		chop = - (ber_len_t) k;
2169 		do {
2170 			*--lenp = ((unsigned char) chop & 0xff) ^ neg;
2171 			signmask >>= 1;
2172 		} while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2173 		/* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2174 		 * are 1, and the top n+2 bits of lenp[] are the sign bit. */
2175 		k = (lenbuf + sizeof(lenbuf)) - lenp;
2176 		if ( k > (ber_slen_t) index_intlen )
2177 			k = index_intlen;
2178 		memcpy( key->bv_val, lenp, k );
2179 		itmp.bv_len = index_intlen - k;
2180 	}
2181 	memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2182 	key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2183 	return 0;
2184 }
2185 
2186 /* Index generation function */
2187 static int
2188 integerIndexer(
2189 	slap_mask_t use,
2190 	slap_mask_t flags,
2191 	Syntax *syntax,
2192 	MatchingRule *mr,
2193 	struct berval *prefix,
2194 	BerVarray values,
2195 	BerVarray *keysp,
2196 	void *ctx )
2197 {
2198 	char ibuf[64];
2199 	struct berval itmp;
2200 	BerVarray keys;
2201 	ber_len_t vlen;
2202 	int i, rc;
2203 	unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2204 
2205 	/* count the values and find max needed length */
2206 	vlen = 0;
2207 	for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2208 		if ( vlen < values[i].bv_len )
2209 			vlen = values[i].bv_len;
2210 	}
2211 	if ( vlen > maxstrlen )
2212 		vlen = maxstrlen;
2213 
2214 	/* we should have at least one value at this point */
2215 	assert( i > 0 );
2216 
2217 	keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2218 	for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2219 		keys[i].bv_len = index_intlen;
2220 		keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2221 	}
2222 	keys[i].bv_len = 0;
2223 	keys[i].bv_val = NULL;
2224 
2225 	if ( vlen > sizeof(ibuf) ) {
2226 		itmp.bv_val = slap_sl_malloc( vlen, ctx );
2227 	} else {
2228 		itmp.bv_val = ibuf;
2229 	}
2230 	itmp.bv_len = sizeof(ibuf);
2231 
2232 	for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2233 		if ( itmp.bv_val != ibuf ) {
2234 			itmp.bv_len = values[i].bv_len;
2235 			if ( itmp.bv_len <= sizeof(ibuf) )
2236 				itmp.bv_len = sizeof(ibuf);
2237 			else if ( itmp.bv_len > maxstrlen )
2238 				itmp.bv_len = maxstrlen;
2239 		}
2240 		rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2241 		if ( rc )
2242 			goto func_leave;
2243 	}
2244 	*keysp = keys;
2245 func_leave:
2246 	if ( itmp.bv_val != ibuf ) {
2247 		slap_sl_free( itmp.bv_val, ctx );
2248 	}
2249 	return rc;
2250 }
2251 
2252 /* Index generation function */
2253 static int
2254 integerFilter(
2255 	slap_mask_t use,
2256 	slap_mask_t flags,
2257 	Syntax *syntax,
2258 	MatchingRule *mr,
2259 	struct berval *prefix,
2260 	void * assertedValue,
2261 	BerVarray *keysp,
2262 	void *ctx )
2263 {
2264 	char ibuf[64];
2265 	struct berval iv;
2266 	BerVarray keys;
2267 	struct berval *value;
2268 	int rc;
2269 
2270 	value = (struct berval *) assertedValue;
2271 
2272 	keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2273 
2274 	keys[0].bv_len = index_intlen;
2275 	keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2276 	keys[1].bv_len = 0;
2277 	keys[1].bv_val = NULL;
2278 
2279 	iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2280 		? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2281 	if ( iv.bv_len > (int) sizeof(ibuf) ) {
2282 		iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2283 	} else {
2284 		iv.bv_val = ibuf;
2285 		iv.bv_len = sizeof(ibuf);
2286 	}
2287 
2288 	rc = integerVal2Key( value, keys, &iv, ctx );
2289 	if ( rc == 0 )
2290 		*keysp = keys;
2291 
2292 	if ( iv.bv_val != ibuf ) {
2293 		slap_sl_free( iv.bv_val, ctx );
2294 	}
2295 	return rc;
2296 }
2297 
2298 static int
2299 countryStringValidate(
2300 	Syntax *syntax,
2301 	struct berval *val )
2302 {
2303 	if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2304 
2305 	if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2306 		return LDAP_INVALID_SYNTAX;
2307 	}
2308 	if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2309 		return LDAP_INVALID_SYNTAX;
2310 	}
2311 
2312 	return LDAP_SUCCESS;
2313 }
2314 
2315 static int
2316 printableStringValidate(
2317 	Syntax *syntax,
2318 	struct berval *val )
2319 {
2320 	ber_len_t i;
2321 
2322 	if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2323 
2324 	for(i=0; i < val->bv_len; i++) {
2325 		if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2326 			return LDAP_INVALID_SYNTAX;
2327 		}
2328 	}
2329 
2330 	return LDAP_SUCCESS;
2331 }
2332 
2333 static int
2334 printablesStringValidate(
2335 	Syntax *syntax,
2336 	struct berval *val )
2337 {
2338 	ber_len_t i, len;
2339 
2340 	if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2341 
2342 	for(i=0,len=0; i < val->bv_len; i++) {
2343 		int c = val->bv_val[i];
2344 
2345 		if( c == '$' ) {
2346 			if( len == 0 ) {
2347 				return LDAP_INVALID_SYNTAX;
2348 			}
2349 			len = 0;
2350 
2351 		} else if ( SLAP_PRINTABLE(c) ) {
2352 			len++;
2353 		} else {
2354 			return LDAP_INVALID_SYNTAX;
2355 		}
2356 	}
2357 
2358 	if( len == 0 ) {
2359 		return LDAP_INVALID_SYNTAX;
2360 	}
2361 
2362 	return LDAP_SUCCESS;
2363 }
2364 
2365 static int
2366 IA5StringValidate(
2367 	Syntax *syntax,
2368 	struct berval *val )
2369 {
2370 	ber_len_t i;
2371 
2372 	for(i=0; i < val->bv_len; i++) {
2373 		if( !LDAP_ASCII(val->bv_val[i]) ) {
2374 			return LDAP_INVALID_SYNTAX;
2375 		}
2376 	}
2377 
2378 	return LDAP_SUCCESS;
2379 }
2380 
2381 static int
2382 IA5StringNormalize(
2383 	slap_mask_t use,
2384 	Syntax *syntax,
2385 	MatchingRule *mr,
2386 	struct berval *val,
2387 	struct berval *normalized,
2388 	void *ctx )
2389 {
2390 	char *p, *q;
2391 	int casefold = !SLAP_MR_ASSOCIATED( mr,
2392 		slap_schema.si_mr_caseExactIA5Match );
2393 
2394 	assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2395 
2396 	p = val->bv_val;
2397 
2398 	/* Ignore initial whitespace */
2399 	while ( ASCII_SPACE( *p ) ) p++;
2400 
2401 	normalized->bv_len = val->bv_len - ( p - val->bv_val );
2402 	normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2403 	AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2404 	normalized->bv_val[normalized->bv_len] = '\0';
2405 
2406 	p = q = normalized->bv_val;
2407 
2408 	while ( *p ) {
2409 		if ( ASCII_SPACE( *p ) ) {
2410 			*q++ = *p++;
2411 
2412 			/* Ignore the extra whitespace */
2413 			while ( ASCII_SPACE( *p ) ) {
2414 				p++;
2415 			}
2416 
2417 		} else if ( casefold ) {
2418 			/* Most IA5 rules require casefolding */
2419 			*q++ = TOLOWER(*p); p++;
2420 
2421 		} else {
2422 			*q++ = *p++;
2423 		}
2424 	}
2425 
2426 	assert( normalized->bv_val <= p );
2427 	assert( q <= p );
2428 
2429 	/*
2430 	 * If the string ended in space, backup the pointer one
2431 	 * position.  One is enough because the above loop collapsed
2432 	 * all whitespace to a single space.
2433 	 */
2434 	if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2435 
2436 	/* null terminate */
2437 	*q = '\0';
2438 
2439 	normalized->bv_len = q - normalized->bv_val;
2440 
2441 	return LDAP_SUCCESS;
2442 }
2443 
2444 static int
2445 UUIDValidate(
2446 	Syntax *syntax,
2447 	struct berval *in )
2448 {
2449 	int i;
2450 	if( in->bv_len != 36 ) {
2451 		return LDAP_INVALID_SYNTAX;
2452 	}
2453 
2454 	for( i=0; i<36; i++ ) {
2455 		switch(i) {
2456 			case 8:
2457 			case 13:
2458 			case 18:
2459 			case 23:
2460 				if( in->bv_val[i] != '-' ) {
2461 					return LDAP_INVALID_SYNTAX;
2462 				}
2463 				break;
2464 			default:
2465 				if( !ASCII_HEX( in->bv_val[i]) ) {
2466 					return LDAP_INVALID_SYNTAX;
2467 				}
2468 		}
2469 	}
2470 
2471 	return LDAP_SUCCESS;
2472 }
2473 
2474 static int
2475 UUIDPretty(
2476 	Syntax *syntax,
2477 	struct berval *in,
2478 	struct berval *out,
2479 	void *ctx )
2480 {
2481 	int i;
2482 	int rc=LDAP_INVALID_SYNTAX;
2483 
2484 	assert( in != NULL );
2485 	assert( out != NULL );
2486 
2487 	if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2488 
2489 	out->bv_len = 36;
2490 	out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2491 
2492 	for( i=0; i<36; i++ ) {
2493 		switch(i) {
2494 			case 8:
2495 			case 13:
2496 			case 18:
2497 			case 23:
2498 				if( in->bv_val[i] != '-' ) {
2499 					goto handle_error;
2500 				}
2501 				out->bv_val[i] = '-';
2502 				break;
2503 
2504 			default:
2505 				if( !ASCII_HEX( in->bv_val[i]) ) {
2506 					goto handle_error;
2507 				}
2508 				out->bv_val[i] = TOLOWER( in->bv_val[i] );
2509 		}
2510 	}
2511 
2512 	rc = LDAP_SUCCESS;
2513 	out->bv_val[ out->bv_len ] = '\0';
2514 
2515 	if( 0 ) {
2516 handle_error:
2517 		slap_sl_free( out->bv_val, ctx );
2518 		out->bv_val = NULL;
2519 	}
2520 
2521 	return rc;
2522 }
2523 
2524 int
2525 UUIDNormalize(
2526 	slap_mask_t usage,
2527 	Syntax *syntax,
2528 	MatchingRule *mr,
2529 	struct berval *val,
2530 	struct berval *normalized,
2531 	void *ctx )
2532 {
2533 	unsigned char octet = '\0';
2534 	int i;
2535 	int j;
2536 
2537 	if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2538 		/* NOTE: must be a normalized UUID */
2539 		assert( val->bv_len == 16 );
2540 
2541 		normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2542 		normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2543 			val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2544 		assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2545 
2546 		return LDAP_SUCCESS;
2547 	}
2548 
2549 	normalized->bv_len = 16;
2550 	normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2551 
2552 	for( i=0, j=0; i<36; i++ ) {
2553 		unsigned char nibble;
2554 		if( val->bv_val[i] == '-' ) {
2555 			continue;
2556 
2557 		} else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2558 			nibble = val->bv_val[i] - '0';
2559 
2560 		} else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2561 			nibble = val->bv_val[i] - ('a'-10);
2562 
2563 		} else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2564 			nibble = val->bv_val[i] - ('A'-10);
2565 
2566 		} else {
2567 			slap_sl_free( normalized->bv_val, ctx );
2568 			return LDAP_INVALID_SYNTAX;
2569 		}
2570 
2571 		if( j & 1 ) {
2572 			octet |= nibble;
2573 			normalized->bv_val[j>>1] = octet;
2574 		} else {
2575 			octet = nibble << 4;
2576 		}
2577 		j++;
2578 	}
2579 
2580 	normalized->bv_val[normalized->bv_len] = 0;
2581 	return LDAP_SUCCESS;
2582 }
2583 
2584 
2585 
2586 int
2587 numericStringValidate(
2588 	Syntax *syntax,
2589 	struct berval *in )
2590 {
2591 	ber_len_t i;
2592 
2593 	if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2594 
2595 	for(i=0; i < in->bv_len; i++) {
2596 		if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2597 			return LDAP_INVALID_SYNTAX;
2598 		}
2599 	}
2600 
2601 	return LDAP_SUCCESS;
2602 }
2603 
2604 static int
2605 numericStringNormalize(
2606 	slap_mask_t usage,
2607 	Syntax *syntax,
2608 	MatchingRule *mr,
2609 	struct berval *val,
2610 	struct berval *normalized,
2611 	void *ctx )
2612 {
2613 	/* removal all spaces */
2614 	char *p, *q;
2615 
2616 	assert( !BER_BVISEMPTY( val ) );
2617 
2618 	normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2619 
2620 	p = val->bv_val;
2621 	q = normalized->bv_val;
2622 
2623 	while ( *p ) {
2624 		if ( ASCII_SPACE( *p ) ) {
2625 			/* Ignore whitespace */
2626 			p++;
2627 		} else {
2628 			*q++ = *p++;
2629 		}
2630 	}
2631 
2632 	/* we should have copied no more than is in val */
2633 	assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2634 
2635 	/* null terminate */
2636 	*q = '\0';
2637 
2638 	normalized->bv_len = q - normalized->bv_val;
2639 
2640 	if( BER_BVISEMPTY( normalized ) ) {
2641 		normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2642 		normalized->bv_val[0] = ' ';
2643 		normalized->bv_val[1] = '\0';
2644 		normalized->bv_len = 1;
2645 	}
2646 
2647 	return LDAP_SUCCESS;
2648 }
2649 
2650 /*
2651  * Integer conversion macros that will use the largest available
2652  * type.
2653  */
2654 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2655 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b)
2656 # define SLAP_LONG           long long
2657 #else
2658 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2659 # define SLAP_LONG           long
2660 #endif /* HAVE_STRTOLL ... */
2661 
2662 static int
2663 integerBitAndMatch(
2664 	int *matchp,
2665 	slap_mask_t flags,
2666 	Syntax *syntax,
2667 	MatchingRule *mr,
2668 	struct berval *value,
2669 	void *assertedValue )
2670 {
2671 	SLAP_LONG lValue, lAssertedValue;
2672 
2673 	errno = 0;
2674 	/* safe to assume integers are NUL terminated? */
2675 	lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2676 	if( errno == ERANGE )
2677 	{
2678 		return LDAP_CONSTRAINT_VIOLATION;
2679 	}
2680 
2681 	lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2682 		NULL, 10);
2683 	if( errno == ERANGE )
2684 	{
2685 		return LDAP_CONSTRAINT_VIOLATION;
2686 	}
2687 
2688 	*matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2689 	return LDAP_SUCCESS;
2690 }
2691 
2692 static int
2693 integerBitOrMatch(
2694 	int *matchp,
2695 	slap_mask_t flags,
2696 	Syntax *syntax,
2697 	MatchingRule *mr,
2698 	struct berval *value,
2699 	void *assertedValue )
2700 {
2701 	SLAP_LONG lValue, lAssertedValue;
2702 
2703 	errno = 0;
2704 	/* safe to assume integers are NUL terminated? */
2705 	lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2706 	if( errno == ERANGE )
2707 	{
2708 		return LDAP_CONSTRAINT_VIOLATION;
2709 	}
2710 
2711 	lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2712 		NULL, 10);
2713 	if( errno == ERANGE )
2714 	{
2715 		return LDAP_CONSTRAINT_VIOLATION;
2716 	}
2717 
2718 	*matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2719 	return LDAP_SUCCESS;
2720 }
2721 
2722 static int
2723 serialNumberAndIssuerCheck(
2724 	struct berval *in,
2725 	struct berval *sn,
2726 	struct berval *is,
2727 	void *ctx
2728 )
2729 {
2730 	int is_hex = 0, n;
2731 
2732 	if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2733 
2734 	if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2735 		/* Parse old format */
2736 		is->bv_val = ber_bvchr( in, '$' );
2737 		if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
2738 
2739 		sn->bv_val = in->bv_val;
2740 		sn->bv_len = is->bv_val - in->bv_val;
2741 
2742 		is->bv_val++;
2743 		is->bv_len = in->bv_len - (sn->bv_len + 1);
2744 
2745 		/* eat leading zeros */
2746 		for( n=0; n < (sn->bv_len-1); n++ ) {
2747 			if( sn->bv_val[n] != '0' ) break;
2748 		}
2749 		sn->bv_val += n;
2750 		sn->bv_len -= n;
2751 
2752 		for( n=0; n < sn->bv_len; n++ ) {
2753 			if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2754 		}
2755 
2756 	} else {
2757 		/* Parse GSER format */
2758 		int havesn = 0, haveissuer = 0, numdquotes = 0;
2759 		struct berval x = *in;
2760 		struct berval ni;
2761 		x.bv_val++;
2762 		x.bv_len-=2;
2763 
2764 		/* eat leading spaces */
2765 		for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2766 			/* empty */;
2767 		}
2768 
2769 		if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2770 			return LDAP_INVALID_SYNTAX;
2771 		}
2772 
2773 		/* should be at issuer or serialNumber NamedValue */
2774 		if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2775 			/* parse issuer */
2776 			x.bv_val += STRLENOF("issuer");
2777 			x.bv_len -= STRLENOF("issuer");
2778 
2779 			if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2780 			x.bv_val++; x.bv_len--;
2781 
2782 			/* eat leading spaces */
2783 			for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2784 				/* empty */;
2785 			}
2786 
2787 			/* For backward compatibility, this part is optional */
2788 			if( !strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:"))) {
2789 				x.bv_val += STRLENOF("rdnSequence:");
2790 				x.bv_len -= STRLENOF("rdnSequence:");
2791 			}
2792 
2793 			if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2794 			x.bv_val++; x.bv_len--;
2795 
2796 			is->bv_val = x.bv_val;
2797 			is->bv_len = 0;
2798 
2799 			for( ; is->bv_len < x.bv_len; ) {
2800 				if ( is->bv_val[is->bv_len] != '"' ) {
2801 					is->bv_len++;
2802 					continue;
2803 				}
2804 				if ( is->bv_val[is->bv_len+1] == '"' ) {
2805 					/* double dquote */
2806 					is->bv_len+=2;
2807 					continue;
2808 				}
2809 				break;
2810 			}
2811 			x.bv_val += is->bv_len+1;
2812 			x.bv_len -= is->bv_len+1;
2813 
2814 			if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2815 				return LDAP_INVALID_SYNTAX;
2816 			}
2817 
2818 			haveissuer++;
2819 
2820 		} else if( strncasecmp( x.bv_val, "serialNumber",
2821 			STRLENOF("serialNumber")) == 0 )
2822 		{
2823 			/* parse serialNumber */
2824 			int neg = 0;
2825 			char first = '\0';
2826 			int extra = 0;
2827 
2828 			x.bv_val += STRLENOF("serialNumber");
2829 			x.bv_len -= STRLENOF("serialNumber");
2830 
2831 			if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2832 			x.bv_val++; x.bv_len--;
2833 
2834 			/* eat leading spaces */
2835 			for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2836 				/* empty */;
2837 			}
2838 
2839 			sn->bv_val = x.bv_val;
2840 			sn->bv_len = 0;
2841 
2842 			if( sn->bv_val[0] == '-' ) {
2843 				neg++;
2844 				sn->bv_len++;
2845 			}
2846 
2847 			if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2848 				sn->bv_val[1] == 'X' ))
2849 			{
2850 				is_hex = 1;
2851 				first = sn->bv_val[2];
2852 				extra = 2;
2853 
2854 				sn->bv_len += STRLENOF("0x");
2855 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2856 					if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2857 				}
2858 
2859 			} else if ( sn->bv_val[0] == '\'' ) {
2860 				first = sn->bv_val[1];
2861 				extra = 3;
2862 
2863 				sn->bv_len += STRLENOF("'");
2864 
2865 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2866 					if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2867 				}
2868 				if ( sn->bv_val[sn->bv_len] == '\'' &&
2869 					sn->bv_val[sn->bv_len + 1] == 'H' )
2870 				{
2871 					sn->bv_len += STRLENOF("'H");
2872 					is_hex = 1;
2873 
2874 				} else {
2875 					return LDAP_INVALID_SYNTAX;
2876 				}
2877 
2878 			} else {
2879 				first = sn->bv_val[0];
2880 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2881 					if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2882 				}
2883 			}
2884 
2885 			if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2886 			if (( sn->bv_len > extra+1+neg ) && ( first == '0' )) {
2887 				return LDAP_INVALID_SYNTAX;
2888 			}
2889 
2890 			x.bv_val += sn->bv_len; x.bv_len -= sn->bv_len;
2891 
2892 			if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2893 				return LDAP_INVALID_SYNTAX;
2894 			}
2895 
2896 			havesn++;
2897 
2898 		} else return LDAP_INVALID_SYNTAX;
2899 
2900 		if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2901 		x.bv_val++; x.bv_len--;
2902 
2903 		/* eat spaces */
2904 		for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2905 			/* empty */;
2906 		}
2907 
2908 		/* should be at remaining NamedValue */
2909 		if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2910 			STRLENOF("issuer" )) == 0 ))
2911 		{
2912 			/* parse issuer */
2913 			x.bv_val += STRLENOF("issuer");
2914 			x.bv_len -= STRLENOF("issuer");
2915 
2916 			if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2917 			x.bv_val++; x.bv_len--;
2918 
2919 			/* eat leading spaces */
2920 			for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2921 				 /* empty */;
2922 			}
2923 
2924 			/* For backward compatibility, this part is optional */
2925 			if( !strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:"))) {
2926 				x.bv_val += STRLENOF("rdnSequence:");
2927 				x.bv_len -= STRLENOF("rdnSequence:");
2928 			}
2929 
2930 			if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2931 			x.bv_val++; x.bv_len--;
2932 
2933 			is->bv_val = x.bv_val;
2934 			is->bv_len = 0;
2935 
2936 			for( ; is->bv_len < x.bv_len; ) {
2937 				if ( is->bv_val[is->bv_len] != '"' ) {
2938 					is->bv_len++;
2939 					continue;
2940 				}
2941 				if ( is->bv_val[is->bv_len+1] == '"' ) {
2942 					/* double dquote */
2943 					numdquotes++;
2944 					is->bv_len+=2;
2945 					continue;
2946 				}
2947 				break;
2948 			}
2949 			x.bv_val += is->bv_len+1;
2950 			x.bv_len -= is->bv_len+1;
2951 
2952 		} else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2953 			STRLENOF("serialNumber")) == 0 ))
2954 		{
2955 			/* parse serialNumber */
2956 			int neg=0;
2957 			x.bv_val += STRLENOF("serialNumber");
2958 			x.bv_len -= STRLENOF("serialNumber");
2959 
2960 			if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2961 			x.bv_val++; x.bv_len--;
2962 
2963 			/* eat leading spaces */
2964 			for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2965 				/* empty */;
2966 			}
2967 
2968 			sn->bv_val = x.bv_val;
2969 			sn->bv_len = 0;
2970 
2971 			if( sn->bv_val[0] == '-' ) {
2972 				neg++;
2973 				sn->bv_len++;
2974 			}
2975 
2976 			if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2977 				sn->bv_val[1] == 'X' )) {
2978 				is_hex = 1;
2979 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2980 					if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2981 				}
2982 			} else if ( sn->bv_val[0] == '\'' ) {
2983 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2984 					if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2985 				}
2986 				if ( sn->bv_val[sn->bv_len] == '\'' &&
2987 					sn->bv_val[sn->bv_len+1] == 'H' )
2988 					is_hex = 1;
2989 				else
2990 					return LDAP_INVALID_SYNTAX;
2991 				sn->bv_len += 2;
2992 			} else {
2993 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2994 					if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2995 				}
2996 			}
2997 
2998 			if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2999 			if (( sn->bv_len > 1+neg ) && ( sn->bv_val[neg] == '0' )) {
3000 				return LDAP_INVALID_SYNTAX;
3001 			}
3002 
3003 			x.bv_val += sn->bv_len;
3004 			x.bv_len -= sn->bv_len;
3005 
3006 		} else return LDAP_INVALID_SYNTAX;
3007 
3008 		/* eat trailing spaces */
3009 		for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3010 			/* empty */;
3011 		}
3012 
3013 		/* should have no characters left... */
3014 		if( x.bv_len ) return LDAP_INVALID_SYNTAX;
3015 
3016 		if ( numdquotes == 0 ) {
3017 			ber_dupbv_x( &ni, is, ctx );
3018 		} else {
3019 			ber_int_t src, dst;
3020 
3021 			ni.bv_len = is->bv_len - numdquotes;
3022 			ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3023 			for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3024 				if ( is->bv_val[src] == '"' ) {
3025 					src++;
3026 				}
3027 				ni.bv_val[dst] = is->bv_val[src];
3028 			}
3029 			ni.bv_val[dst] = '\0';
3030 		}
3031 
3032 		*is = ni;
3033 	}
3034 
3035 	return 0;
3036 }
3037 
3038 static int
3039 serialNumberAndIssuerValidate(
3040 	Syntax *syntax,
3041 	struct berval *in )
3042 {
3043 	int rc;
3044 	struct berval sn, i;
3045 
3046 	Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3047 		in->bv_val, 0, 0 );
3048 
3049 	rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3050 	if ( rc )
3051 		return rc;
3052 
3053 	/* validate DN -- doesn't handle double dquote */
3054 	rc = dnValidate( NULL, &i );
3055 	if( rc )
3056 		rc = LDAP_INVALID_SYNTAX;
3057 
3058 	if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3059 		slap_sl_free( i.bv_val, NULL );
3060 	}
3061 
3062 	Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: OKAY\n",
3063 		0, 0, 0 );
3064 	return rc;
3065 }
3066 
3067 int
3068 serialNumberAndIssuerPretty(
3069 	Syntax *syntax,
3070 	struct berval *in,
3071 	struct berval *out,
3072 	void *ctx )
3073 {
3074 	int n, rc;
3075 	struct berval sn, i, ni;
3076 
3077 	assert( in != NULL );
3078 	assert( out != NULL );
3079 
3080 	Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3081 		in->bv_val, 0, 0 );
3082 
3083 	rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3084 	if ( rc )
3085 		return rc;
3086 
3087 	rc = dnPretty( syntax, &i, &ni, ctx );
3088 
3089 	if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3090 		slap_sl_free( i.bv_val, ctx );
3091 	}
3092 
3093 	if( rc ) return LDAP_INVALID_SYNTAX;
3094 
3095 	/* make room from sn + "$" */
3096 	out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3097 		+ sn.bv_len + ni.bv_len;
3098 	out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3099 
3100 	if( out->bv_val == NULL ) {
3101 		out->bv_len = 0;
3102 		slap_sl_free( ni.bv_val, ctx );
3103 		return LDAP_OTHER;
3104 	}
3105 
3106 	n = 0;
3107 	AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3108 		STRLENOF("{ serialNumber "));
3109 	n = STRLENOF("{ serialNumber ");
3110 
3111 	AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3112 	n += sn.bv_len;
3113 
3114 	AC_MEMCPY( &out->bv_val[n], ", issuer rdnSequence:\"", STRLENOF(", issuer rdnSequence:\""));
3115 	n += STRLENOF(", issuer rdnSequence:\"");
3116 
3117 	AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3118 	n += ni.bv_len;
3119 
3120 	AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
3121 	n += STRLENOF("\" }");
3122 
3123 	out->bv_val[n] = '\0';
3124 
3125 	assert( n == out->bv_len );
3126 
3127 	Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
3128 		out->bv_val, 0, 0 );
3129 
3130 	slap_sl_free( ni.bv_val, ctx );
3131 
3132 	return LDAP_SUCCESS;
3133 }
3134 
3135 /*
3136  * This routine is called by certificateExactNormalize when
3137  * certificateExactNormalize receives a search string instead of
3138  * a certificate. This routine checks if the search value is valid
3139  * and then returns the normalized value
3140  */
3141 static int
3142 serialNumberAndIssuerNormalize(
3143 	slap_mask_t usage,
3144 	Syntax *syntax,
3145 	MatchingRule *mr,
3146 	struct berval *in,
3147 	struct berval *out,
3148 	void *ctx )
3149 {
3150 	struct berval sn, sn2, i, ni;
3151 	char sbuf[64], *stmp = sbuf;
3152 	int rc;
3153 	ber_len_t n;
3154 
3155 	assert( in != NULL );
3156 	assert( out != NULL );
3157 
3158 	Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3159 		in->bv_val, 0, 0 );
3160 
3161 	rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3162 	if ( rc )
3163 		return rc;
3164 
3165 	rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3166 
3167 	if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3168 		slap_sl_free( i.bv_val, ctx );
3169 	}
3170 
3171 	if( rc ) return LDAP_INVALID_SYNTAX;
3172 
3173 	/* Convert sn to canonical hex */
3174 	if ( sn.bv_len > sizeof( sbuf )) {
3175 		stmp = slap_sl_malloc( sn.bv_len, ctx );
3176 	}
3177 	sn2.bv_val = stmp;
3178 	sn2.bv_len = sn.bv_len;
3179 	if ( lutil_str2bin( &sn, &sn2, ctx )) {
3180 		rc = LDAP_INVALID_SYNTAX;
3181 		goto func_leave;
3182 	}
3183 
3184 	/* make room for sn + "$" */
3185 	out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3186 		+ ( sn2.bv_len * 2 + 3 ) + ni.bv_len;
3187 	out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3188 
3189 	if( out->bv_val == NULL ) {
3190 		out->bv_len = 0;
3191 		slap_sl_free( ni.bv_val, ctx );
3192 		rc = LDAP_OTHER;
3193 		goto func_leave;
3194 	}
3195 
3196 	n = 0;
3197 	AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3198 		STRLENOF( "{ serialNumber " ));
3199 	n = STRLENOF( "{ serialNumber " );
3200 
3201 	AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3202 	{
3203 		int j;
3204 		unsigned char *v = (unsigned char *)sn2.bv_val;
3205 		out->bv_val[n++] = '\'';
3206 		for ( j = 0; j < sn2.bv_len; j++ ) {
3207 			snprintf( &out->bv_val[n], out->bv_len - n + 1,
3208 				"%02X", v[j] );
3209 			n += 2;
3210 		}
3211 		out->bv_val[n++] = '\'';
3212 		out->bv_val[n++] = 'H';
3213 	}
3214 
3215 	AC_MEMCPY( &out->bv_val[n], ", issuer rdnSequence:\"", STRLENOF( ", issuer rdnSequence:\"" ));
3216 	n += STRLENOF( ", issuer rdnSequence:\"" );
3217 
3218 	AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3219 	n += ni.bv_len;
3220 
3221 	AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
3222 	n += STRLENOF( "\" }" );
3223 
3224 	out->bv_val[n] = '\0';
3225 
3226 	assert( n == out->bv_len );
3227 
3228 	Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
3229 		out->bv_val, 0, 0 );
3230 
3231 func_leave:
3232 	if ( stmp != sbuf )
3233 		slap_sl_free( stmp, ctx );
3234 	slap_sl_free( ni.bv_val, ctx );
3235 
3236 	return rc;
3237 }
3238 
3239 static int
3240 certificateExactNormalize(
3241 	slap_mask_t usage,
3242 	Syntax *syntax,
3243 	MatchingRule *mr,
3244 	struct berval *val,
3245 	struct berval *normalized,
3246 	void *ctx )
3247 {
3248 	BerElementBuffer berbuf;
3249 	BerElement *ber = (BerElement *)&berbuf;
3250 	ber_tag_t tag;
3251 	ber_len_t len;
3252 	ber_int_t i;
3253 	char serialbuf[64], *serial = serialbuf;
3254 	ber_len_t seriallen;
3255 	struct berval issuer_dn = BER_BVNULL, bvdn;
3256 	unsigned char *p;
3257 	int rc = LDAP_INVALID_SYNTAX;
3258 
3259 	if( BER_BVISEMPTY( val ) ) goto done;
3260 
3261 	if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3262 		return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
3263 	}
3264 
3265 	assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3266 
3267 	ber_init2( ber, val, LBER_USE_DER );
3268 	tag = ber_skip_tag( ber, &len );	/* Signed Sequence */
3269 	tag = ber_skip_tag( ber, &len );	/* Sequence */
3270 	tag = ber_peek_tag( ber, &len );	/* Optional version? */
3271 	if ( tag == SLAP_X509_OPT_C_VERSION ) {
3272 		tag = ber_skip_tag( ber, &len );
3273 		tag = ber_get_int( ber, &i );	/* version */
3274 	}
3275 
3276 	/* NOTE: move the test here from certificateValidate,
3277 	 * so that we can validate certs with serial longer
3278 	 * than sizeof(ber_int_t) */
3279 	tag = ber_peek_tag( ber, &len );	/* serial */
3280 
3281 	/* Use hex format. '123456789abcdef'H
3282 	 */
3283 	{
3284 		unsigned char *ptr;
3285 		char *sptr;
3286 
3287 		tag = ber_skip_tag( ber, &len );
3288 		ptr = (unsigned char *)ber->ber_ptr;
3289 		ber_skip_data( ber, len );
3290 
3291 		/* Check for minimal encodings */
3292 		if ( len > 1 ) {
3293 			if ( ptr[0] & 0x80 ) {
3294 				if (( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ))
3295 					return LDAP_INVALID_SYNTAX;
3296 			} else if ( ptr[0] == 0 ) {
3297 				if (!( ptr[1] & 0x80 ))
3298 					return LDAP_INVALID_SYNTAX;
3299 			}
3300 		}
3301 
3302 		seriallen = len * 2 + 4;	/* quotes, H, NUL */
3303 		if ( seriallen > sizeof( serialbuf ))
3304 			serial = slap_sl_malloc( seriallen, ctx );
3305 		sptr = serial;
3306 		*sptr++ = '\'';
3307 		for ( i = 0; i<len; i++ ) {
3308 			sprintf( sptr, "%02X", ptr[i] );
3309 			sptr += 2;
3310 		}
3311 		*sptr++ = '\'';
3312 		*sptr++ = 'H';
3313 		seriallen--;
3314 	}
3315 	tag = ber_skip_tag( ber, &len );	/* SignatureAlg */
3316 	ber_skip_data( ber, len );
3317 	tag = ber_peek_tag( ber, &len );	/* IssuerDN */
3318 	len = ber_ptrlen( ber );
3319 	bvdn.bv_val = val->bv_val + len;
3320 	bvdn.bv_len = val->bv_len - len;
3321 
3322 	rc = dnX509normalize( &bvdn, &issuer_dn );
3323 	if( rc != LDAP_SUCCESS ) goto done;
3324 
3325 	normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3326 		+ seriallen + issuer_dn.bv_len;
3327 	normalized->bv_val = ch_malloc(normalized->bv_len+1);
3328 
3329 	p = (unsigned char *)normalized->bv_val;
3330 
3331 	AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3332 	p += STRLENOF( "{ serialNumber " );
3333 
3334 	AC_MEMCPY(p, serial, seriallen);
3335 	p += seriallen;
3336 
3337 	AC_MEMCPY(p, ", issuer rdnSequence:\"", STRLENOF( ", issuer rdnSequence:\"" ));
3338 	p += STRLENOF( ", issuer rdnSequence:\"" );
3339 
3340 	AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3341 	p += issuer_dn.bv_len;
3342 
3343 	AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3344 	p += STRLENOF( "\" }" );
3345 
3346 	*p = '\0';
3347 
3348 	Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3349 		normalized->bv_val, NULL, NULL );
3350 
3351 	rc = LDAP_SUCCESS;
3352 
3353 done:
3354 	if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3355 	if ( serial != serialbuf ) ber_memfree_x( serial, ctx );
3356 
3357 	return rc;
3358 }
3359 
3360 static int
3361 hexValidate(
3362 	Syntax *syntax,
3363 	struct berval *in )
3364 {
3365 	int	i;
3366 
3367 	assert( in != NULL );
3368 	assert( !BER_BVISNULL( in ) );
3369 
3370 	for ( i = 0; i < in->bv_len; i++ ) {
3371 		if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
3372 			return LDAP_INVALID_SYNTAX;
3373 		}
3374 	}
3375 
3376 	return LDAP_SUCCESS;
3377 }
3378 
3379 /* Normalize a SID as used inside a CSN:
3380  * three-digit numeric string */
3381 static int
3382 hexNormalize(
3383 	slap_mask_t usage,
3384 	Syntax *syntax,
3385 	MatchingRule *mr,
3386 	struct berval *val,
3387 	struct berval *normalized,
3388 	void *ctx )
3389 {
3390 	int	i;
3391 
3392 	assert( val != NULL );
3393 	assert( normalized != NULL );
3394 
3395 	ber_dupbv_x( normalized, val, ctx );
3396 
3397 	for ( i = 0; i < normalized->bv_len; i++ ) {
3398 		if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
3399 			ber_memfree_x( normalized->bv_val, ctx );
3400 			BER_BVZERO( normalized );
3401 			return LDAP_INVALID_SYNTAX;
3402 		}
3403 
3404 		normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3405 	}
3406 
3407 	return LDAP_SUCCESS;
3408 }
3409 
3410 static int
3411 sidValidate (
3412 	Syntax *syntax,
3413 	struct berval *in )
3414 {
3415 	assert( in != NULL );
3416 	assert( !BER_BVISNULL( in ) );
3417 
3418 	if ( in->bv_len != 3 ) {
3419 		return LDAP_INVALID_SYNTAX;
3420 	}
3421 
3422 	return hexValidate( NULL, in );
3423 }
3424 
3425 /* Normalize a SID as used inside a CSN:
3426  * three-digit numeric string */
3427 static int
3428 sidNormalize(
3429 	slap_mask_t usage,
3430 	Syntax *syntax,
3431 	MatchingRule *mr,
3432 	struct berval *val,
3433 	struct berval *normalized,
3434 	void *ctx )
3435 {
3436 	if ( val->bv_len != 3 ) {
3437 		return LDAP_INVALID_SYNTAX;
3438 	}
3439 
3440 	return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
3441 }
3442 
3443 static int
3444 sidPretty(
3445 	Syntax *syntax,
3446 	struct berval *val,
3447 	struct berval *out,
3448 	void *ctx )
3449 {
3450 	return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3451 }
3452 
3453 /* Normalize a SID as used inside a CSN, either as-is
3454  * (assertion value) or extracted from the CSN
3455  * (attribute value) */
3456 static int
3457 csnSidNormalize(
3458 	slap_mask_t usage,
3459 	Syntax *syntax,
3460 	MatchingRule *mr,
3461 	struct berval *val,
3462 	struct berval *normalized,
3463 	void *ctx )
3464 {
3465 	struct berval	bv;
3466 	char		*ptr,
3467 			buf[ 4 ];
3468 
3469 
3470 	if ( BER_BVISEMPTY( val ) ) {
3471 		return LDAP_INVALID_SYNTAX;
3472 	}
3473 
3474 	if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3475 		return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
3476 	}
3477 
3478 	assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3479 
3480 	ptr = ber_bvchr( val, '#' );
3481 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3482 		return LDAP_INVALID_SYNTAX;
3483 	}
3484 
3485 	bv.bv_val = ptr + 1;
3486 	bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3487 
3488 	ptr = ber_bvchr( &bv, '#' );
3489 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3490 		return LDAP_INVALID_SYNTAX;
3491 	}
3492 
3493 	bv.bv_val = ptr + 1;
3494 	bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3495 
3496 	ptr = ber_bvchr( &bv, '#' );
3497 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3498 		return LDAP_INVALID_SYNTAX;
3499 	}
3500 
3501 	bv.bv_len = ptr - bv.bv_val;
3502 
3503 	if ( bv.bv_len == 2 ) {
3504 		/* OpenLDAP 2.3 SID */
3505 		buf[ 0 ] = '0';
3506 		buf[ 1 ] = bv.bv_val[ 0 ];
3507 		buf[ 2 ] = bv.bv_val[ 1 ];
3508 		buf[ 3 ] = '\0';
3509 
3510 		bv.bv_val = buf;
3511 		bv.bv_len = 3;
3512 	}
3513 
3514 	return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
3515 }
3516 
3517 static int
3518 csnValidate(
3519 	Syntax *syntax,
3520 	struct berval *in )
3521 {
3522 	struct berval	bv;
3523 	char		*ptr;
3524 	int		rc;
3525 
3526 	assert( in != NULL );
3527 	assert( !BER_BVISNULL( in ) );
3528 
3529 	if ( BER_BVISEMPTY( in ) ) {
3530 		return LDAP_INVALID_SYNTAX;
3531 	}
3532 
3533 	bv = *in;
3534 
3535 	ptr = ber_bvchr( &bv, '#' );
3536 	if ( ptr == NULL || ptr - bv.bv_val == bv.bv_len ) {
3537 		return LDAP_INVALID_SYNTAX;
3538 	}
3539 
3540 	bv.bv_len = ptr - bv.bv_val;
3541 	if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
3542 		bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
3543 	{
3544 		return LDAP_INVALID_SYNTAX;
3545 	}
3546 
3547 	rc = generalizedTimeValidate( NULL, &bv );
3548 	if ( rc != LDAP_SUCCESS ) {
3549 		return rc;
3550 	}
3551 
3552 	bv.bv_val = ptr + 1;
3553 	bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3554 
3555 	ptr = ber_bvchr( &bv, '#' );
3556 	if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3557 		return LDAP_INVALID_SYNTAX;
3558 	}
3559 
3560 	bv.bv_len = ptr - bv.bv_val;
3561 	if ( bv.bv_len != 6 ) {
3562 		return LDAP_INVALID_SYNTAX;
3563 	}
3564 
3565 	rc = hexValidate( NULL, &bv );
3566 	if ( rc != LDAP_SUCCESS ) {
3567 		return rc;
3568 	}
3569 
3570 	bv.bv_val = ptr + 1;
3571 	bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3572 
3573 	ptr = ber_bvchr( &bv, '#' );
3574 	if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3575 		return LDAP_INVALID_SYNTAX;
3576 	}
3577 
3578 	bv.bv_len = ptr - bv.bv_val;
3579 	if ( bv.bv_len == 2 ) {
3580 		/* tolerate old 2-digit replica-id */
3581 		rc = hexValidate( NULL, &bv );
3582 
3583 	} else {
3584 		rc = sidValidate( NULL, &bv );
3585 	}
3586 	if ( rc != LDAP_SUCCESS ) {
3587 		return rc;
3588 	}
3589 
3590 	bv.bv_val = ptr + 1;
3591 	bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3592 
3593 	if ( bv.bv_len != 6 ) {
3594 		return LDAP_INVALID_SYNTAX;
3595 	}
3596 
3597 	return hexValidate( NULL, &bv );
3598 }
3599 
3600 /* Normalize a CSN in OpenLDAP 2.1 format */
3601 static int
3602 csnNormalize21(
3603 	slap_mask_t usage,
3604 	Syntax *syntax,
3605 	MatchingRule *mr,
3606 	struct berval *val,
3607 	struct berval *normalized,
3608 	void *ctx )
3609 {
3610 	struct berval	gt, cnt, sid, mod;
3611 	struct berval	bv;
3612 	char		buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
3613 	char		*ptr;
3614 	int		i;
3615 
3616 	assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3617 	assert( !BER_BVISEMPTY( val ) );
3618 
3619 	gt = *val;
3620 
3621 	ptr = ber_bvchr( &gt, '#' );
3622 	if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3623 		return LDAP_INVALID_SYNTAX;
3624 	}
3625 
3626 	gt.bv_len = ptr - gt.bv_val;
3627 	if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
3628 		return LDAP_INVALID_SYNTAX;
3629 	}
3630 
3631 	if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
3632 		return LDAP_INVALID_SYNTAX;
3633 	}
3634 
3635 	cnt.bv_val = ptr + 1;
3636 	cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3637 
3638 	ptr = ber_bvchr( &cnt, '#' );
3639 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3640 		return LDAP_INVALID_SYNTAX;
3641 	}
3642 
3643 	cnt.bv_len = ptr - cnt.bv_val;
3644 	if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
3645 		return LDAP_INVALID_SYNTAX;
3646 	}
3647 
3648 	if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
3649 		return LDAP_INVALID_SYNTAX;
3650 	}
3651 
3652 	cnt.bv_val += STRLENOF( "0x" );
3653 	cnt.bv_len -= STRLENOF( "0x" );
3654 
3655 	sid.bv_val = ptr + 1;
3656 	sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3657 
3658 	ptr = ber_bvchr( &sid, '#' );
3659 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3660 		return LDAP_INVALID_SYNTAX;
3661 	}
3662 
3663 	sid.bv_len = ptr - sid.bv_val;
3664 	if ( sid.bv_len != STRLENOF( "0" ) ) {
3665 		return LDAP_INVALID_SYNTAX;
3666 	}
3667 
3668 	mod.bv_val = ptr + 1;
3669 	mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3670 	if ( mod.bv_len != STRLENOF( "0000" ) ) {
3671 		return LDAP_INVALID_SYNTAX;
3672 	}
3673 
3674 	bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3675 	bv.bv_val = buf;
3676 
3677 	ptr = bv.bv_val;
3678 	ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
3679 	ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
3680 		STRLENOF( "MM" ) );
3681 	ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
3682 		STRLENOF( "SS" ) );
3683 	ptr = lutil_strcopy( ptr, ".000000Z#00" );
3684 	ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3685 	*ptr++ = '#';
3686 	*ptr++ = '0';
3687 	*ptr++ = '0';
3688 	*ptr++ = sid.bv_val[ 0 ];
3689 	*ptr++ = '#';
3690 	*ptr++ = '0';
3691 	*ptr++ = '0';
3692 	for ( i = 0; i < mod.bv_len; i++ ) {
3693 		*ptr++ = TOLOWER( mod.bv_val[ i ] );
3694 	}
3695 	*ptr = '\0';
3696 
3697 	assert( ptr - bv.bv_val == bv.bv_len );
3698 
3699 	if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
3700 		return LDAP_INVALID_SYNTAX;
3701 	}
3702 
3703 	ber_dupbv_x( normalized, &bv, ctx );
3704 
3705 	return LDAP_SUCCESS;
3706 }
3707 
3708 /* Normalize a CSN in OpenLDAP 2.3 format */
3709 static int
3710 csnNormalize23(
3711 	slap_mask_t usage,
3712 	Syntax *syntax,
3713 	MatchingRule *mr,
3714 	struct berval *val,
3715 	struct berval *normalized,
3716 	void *ctx )
3717 {
3718 	struct berval	gt, cnt, sid, mod;
3719 	struct berval	bv;
3720 	char		buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
3721 	char		*ptr;
3722 	int		i;
3723 
3724 	assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3725 	assert( !BER_BVISEMPTY( val ) );
3726 
3727 	gt = *val;
3728 
3729 	ptr = ber_bvchr( &gt, '#' );
3730 	if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3731 		return LDAP_INVALID_SYNTAX;
3732 	}
3733 
3734 	gt.bv_len = ptr - gt.bv_val;
3735 	if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3736 		return LDAP_INVALID_SYNTAX;
3737 	}
3738 
3739 	cnt.bv_val = ptr + 1;
3740 	cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3741 
3742 	ptr = ber_bvchr( &cnt, '#' );
3743 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3744 		return LDAP_INVALID_SYNTAX;
3745 	}
3746 
3747 	cnt.bv_len = ptr - cnt.bv_val;
3748 	if ( cnt.bv_len != STRLENOF( "000000" ) ) {
3749 		return LDAP_INVALID_SYNTAX;
3750 	}
3751 
3752 	sid.bv_val = ptr + 1;
3753 	sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3754 
3755 	ptr = ber_bvchr( &sid, '#' );
3756 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3757 		return LDAP_INVALID_SYNTAX;
3758 	}
3759 
3760 	sid.bv_len = ptr - sid.bv_val;
3761 	if ( sid.bv_len != STRLENOF( "00" ) ) {
3762 		return LDAP_INVALID_SYNTAX;
3763 	}
3764 
3765 	mod.bv_val = ptr + 1;
3766 	mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3767 	if ( mod.bv_len != STRLENOF( "000000" ) ) {
3768 		return LDAP_INVALID_SYNTAX;
3769 	}
3770 
3771 	bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3772 	bv.bv_val = buf;
3773 
3774 	ptr = bv.bv_val;
3775 	ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
3776 	ptr = lutil_strcopy( ptr, ".000000Z#" );
3777 	ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3778 	*ptr++ = '#';
3779 	*ptr++ = '0';
3780 	for ( i = 0; i < sid.bv_len; i++ ) {
3781 		*ptr++ = TOLOWER( sid.bv_val[ i ] );
3782 	}
3783 	*ptr++ = '#';
3784 	for ( i = 0; i < mod.bv_len; i++ ) {
3785 		*ptr++ = TOLOWER( mod.bv_val[ i ] );
3786 	}
3787 	*ptr = '\0';
3788 
3789 	assert( ptr - bv.bv_val == bv.bv_len );
3790 	if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
3791 		return LDAP_INVALID_SYNTAX;
3792 	}
3793 
3794 	ber_dupbv_x( normalized, &bv, ctx );
3795 
3796 	return LDAP_SUCCESS;
3797 }
3798 
3799 /* Normalize a CSN */
3800 static int
3801 csnNormalize(
3802 	slap_mask_t usage,
3803 	Syntax *syntax,
3804 	MatchingRule *mr,
3805 	struct berval *val,
3806 	struct berval *normalized,
3807 	void *ctx )
3808 {
3809 	struct berval	cnt, sid, mod;
3810 	char		*ptr;
3811 	int		i;
3812 
3813 	assert( val != NULL );
3814 	assert( normalized != NULL );
3815 
3816 	assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3817 
3818 	if ( BER_BVISEMPTY( val ) ) {
3819 		return LDAP_INVALID_SYNTAX;
3820 	}
3821 
3822 	if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
3823 		/* Openldap <= 2.3 */
3824 
3825 		return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
3826 	}
3827 
3828 	if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
3829 		/* Openldap 2.1 */
3830 
3831 		return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
3832 	}
3833 
3834 	if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
3835 		return LDAP_INVALID_SYNTAX;
3836 	}
3837 
3838 	ptr = ber_bvchr( val, '#' );
3839 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3840 		return LDAP_INVALID_SYNTAX;
3841 	}
3842 
3843 	if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
3844 		return LDAP_INVALID_SYNTAX;
3845 	}
3846 
3847 	cnt.bv_val = ptr + 1;
3848 	cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3849 
3850 	ptr = ber_bvchr( &cnt, '#' );
3851 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3852 		return LDAP_INVALID_SYNTAX;
3853 	}
3854 
3855 	if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
3856 		return LDAP_INVALID_SYNTAX;
3857 	}
3858 
3859 	sid.bv_val = ptr + 1;
3860 	sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3861 
3862 	ptr = ber_bvchr( &sid, '#' );
3863 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3864 		return LDAP_INVALID_SYNTAX;
3865 	}
3866 
3867 	sid.bv_len = ptr - sid.bv_val;
3868 	if ( sid.bv_len != STRLENOF( "000" ) ) {
3869 		return LDAP_INVALID_SYNTAX;
3870 	}
3871 
3872 	mod.bv_val = ptr + 1;
3873 	mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3874 
3875 	if ( mod.bv_len != STRLENOF( "000000" ) ) {
3876 		return LDAP_INVALID_SYNTAX;
3877 	}
3878 
3879 	ber_dupbv_x( normalized, val, ctx );
3880 
3881 	for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
3882 		i < normalized->bv_len; i++ )
3883 	{
3884 		/* assume it's already validated that's all hex digits */
3885 		normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3886 	}
3887 
3888 	return LDAP_SUCCESS;
3889 }
3890 
3891 static int
3892 csnPretty(
3893 	Syntax *syntax,
3894 	struct berval *val,
3895 	struct berval *out,
3896 	void *ctx )
3897 {
3898 	return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3899 }
3900 
3901 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3902 /* slight optimization - does not need the start parameter */
3903 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3904 enum { start = 0 };
3905 #endif
3906 
3907 static int
3908 check_time_syntax (struct berval *val,
3909 	int start,
3910 	int *parts,
3911 	struct berval *fraction)
3912 {
3913 	/*
3914 	 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3915 	 * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
3916 	 * GeneralizedTime supports leap seconds, UTCTime does not.
3917 	 */
3918 	static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3919 	static const int mdays[2][12] = {
3920 		/* non-leap years */
3921 		{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3922 		/* leap years */
3923 		{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3924 	};
3925 	char *p, *e;
3926 	int part, c, c1, c2, tzoffset, leapyear = 0;
3927 
3928 	p = val->bv_val;
3929 	e = p + val->bv_len;
3930 
3931 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3932 	parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3933 #endif
3934 	for (part = start; part < 7 && p < e; part++) {
3935 		c1 = *p;
3936 		if (!ASCII_DIGIT(c1)) {
3937 			break;
3938 		}
3939 		p++;
3940 		if (p == e) {
3941 			return LDAP_INVALID_SYNTAX;
3942 		}
3943 		c = *p++;
3944 		if (!ASCII_DIGIT(c)) {
3945 			return LDAP_INVALID_SYNTAX;
3946 		}
3947 		c += c1 * 10 - '0' * 11;
3948 		if ((part | 1) == 3) {
3949 			--c;
3950 			if (c < 0) {
3951 				return LDAP_INVALID_SYNTAX;
3952 			}
3953 		}
3954 		if (c >= ceiling[part]) {
3955 			if (! (c == 60 && part == 6 && start == 0))
3956 				return LDAP_INVALID_SYNTAX;
3957 		}
3958 		parts[part] = c;
3959 	}
3960 	if (part < 5 + start) {
3961 		return LDAP_INVALID_SYNTAX;
3962 	}
3963 	for (; part < 9; part++) {
3964 		parts[part] = 0;
3965 	}
3966 
3967 	/* leapyear check for the Gregorian calendar (year>1581) */
3968 	if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3969 		leapyear = 1;
3970 	}
3971 
3972 	if (parts[3] >= mdays[leapyear][parts[2]]) {
3973 		return LDAP_INVALID_SYNTAX;
3974 	}
3975 
3976 	if (start == 0) {
3977 		fraction->bv_val = p;
3978 		fraction->bv_len = 0;
3979 		if (p < e && (*p == '.' || *p == ',')) {
3980 			char *end_num;
3981 			while (++p < e && ASCII_DIGIT(*p)) {
3982 				/* EMTPY */;
3983 			}
3984 			if (p - fraction->bv_val == 1) {
3985 				return LDAP_INVALID_SYNTAX;
3986 			}
3987 			for (end_num = p; end_num[-1] == '0'; --end_num) {
3988 				/* EMPTY */;
3989 			}
3990 			c = end_num - fraction->bv_val;
3991 			if (c != 1) fraction->bv_len = c;
3992 		}
3993 	}
3994 
3995 	if (p == e) {
3996 		/* no time zone */
3997 		return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3998 	}
3999 
4000 	tzoffset = *p++;
4001 	switch (tzoffset) {
4002 	default:
4003 		return LDAP_INVALID_SYNTAX;
4004 	case 'Z':
4005 		/* UTC */
4006 		break;
4007 	case '+':
4008 	case '-':
4009 		for (part = 7; part < 9 && p < e; part++) {
4010 			c1 = *p;
4011 			if (!ASCII_DIGIT(c1)) {
4012 				break;
4013 			}
4014 			p++;
4015 			if (p == e) {
4016 				return LDAP_INVALID_SYNTAX;
4017 			}
4018 			c2 = *p++;
4019 			if (!ASCII_DIGIT(c2)) {
4020 				return LDAP_INVALID_SYNTAX;
4021 			}
4022 			parts[part] = c1 * 10 + c2 - '0' * 11;
4023 			if (parts[part] >= ceiling[part]) {
4024 				return LDAP_INVALID_SYNTAX;
4025 			}
4026 		}
4027 		if (part < 8 + start) {
4028 			return LDAP_INVALID_SYNTAX;
4029 		}
4030 
4031 		if (tzoffset == '-') {
4032 			/* negative offset to UTC, ie west of Greenwich */
4033 			parts[4] += parts[7];
4034 			parts[5] += parts[8];
4035 			/* offset is just hhmm, no seconds */
4036 			for (part = 6; --part >= 0; ) {
4037 				if (part != 3) {
4038 					c = ceiling[part];
4039 				} else {
4040 					c = mdays[leapyear][parts[2]];
4041 				}
4042 				if (parts[part] >= c) {
4043 					if (part == 0) {
4044 						return LDAP_INVALID_SYNTAX;
4045 					}
4046 					parts[part] -= c;
4047 					parts[part - 1]++;
4048 					continue;
4049 				} else if (part != 5) {
4050 					break;
4051 				}
4052 			}
4053 		} else {
4054 			/* positive offset to UTC, ie east of Greenwich */
4055 			parts[4] -= parts[7];
4056 			parts[5] -= parts[8];
4057 			for (part = 6; --part >= 0; ) {
4058 				if (parts[part] < 0) {
4059 					if (part == 0) {
4060 						return LDAP_INVALID_SYNTAX;
4061 					}
4062 					if (part != 3) {
4063 						c = ceiling[part];
4064 					} else {
4065 						/* make first arg to % non-negative */
4066 						c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
4067 					}
4068 					parts[part] += c;
4069 					parts[part - 1]--;
4070 					continue;
4071 				} else if (part != 5) {
4072 					break;
4073 				}
4074 			}
4075 		}
4076 	}
4077 
4078 	return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
4079 }
4080 
4081 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4082 
4083 #if 0
4084 static int
4085 xutcTimeNormalize(
4086 	Syntax *syntax,
4087 	struct berval *val,
4088 	struct berval *normalized )
4089 {
4090 	int parts[9], rc;
4091 
4092 	rc = check_time_syntax(val, 1, parts, NULL);
4093 	if (rc != LDAP_SUCCESS) {
4094 		return rc;
4095 	}
4096 
4097 	normalized->bv_val = ch_malloc( 14 );
4098 	if ( normalized->bv_val == NULL ) {
4099 		return LBER_ERROR_MEMORY;
4100 	}
4101 
4102 	sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
4103 		parts[1], parts[2] + 1, parts[3] + 1,
4104 		parts[4], parts[5], parts[6] );
4105 	normalized->bv_len = 13;
4106 
4107 	return LDAP_SUCCESS;
4108 }
4109 #endif /* 0 */
4110 
4111 static int
4112 utcTimeValidate(
4113 	Syntax *syntax,
4114 	struct berval *in )
4115 {
4116 	int parts[9];
4117 	return check_time_syntax(in, 1, parts, NULL);
4118 }
4119 
4120 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
4121 
4122 static int
4123 generalizedTimeValidate(
4124 	Syntax *syntax,
4125 	struct berval *in )
4126 {
4127 	int parts[9];
4128 	struct berval fraction;
4129 	return check_time_syntax(in, 0, parts, &fraction);
4130 }
4131 
4132 static int
4133 generalizedTimeNormalize(
4134 	slap_mask_t usage,
4135 	Syntax *syntax,
4136 	MatchingRule *mr,
4137 	struct berval *val,
4138 	struct berval *normalized,
4139 	void *ctx )
4140 {
4141 	int parts[9], rc;
4142 	unsigned int len;
4143 	struct berval fraction;
4144 
4145 	rc = check_time_syntax(val, 0, parts, &fraction);
4146 	if (rc != LDAP_SUCCESS) {
4147 		return rc;
4148 	}
4149 
4150 	len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
4151 	normalized->bv_val = slap_sl_malloc( len + 1, ctx );
4152 	if ( BER_BVISNULL( normalized ) ) {
4153 		return LBER_ERROR_MEMORY;
4154 	}
4155 
4156 	sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
4157 		parts[0], parts[1], parts[2] + 1, parts[3] + 1,
4158 		parts[4], parts[5], parts[6] );
4159 	if ( !BER_BVISEMPTY( &fraction ) ) {
4160 		memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
4161 			fraction.bv_val, fraction.bv_len );
4162 		normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
4163 	}
4164 	strcpy( normalized->bv_val + len-1, "Z" );
4165 	normalized->bv_len = len;
4166 
4167 	return LDAP_SUCCESS;
4168 }
4169 
4170 static int
4171 generalizedTimeOrderingMatch(
4172 	int *matchp,
4173 	slap_mask_t flags,
4174 	Syntax *syntax,
4175 	MatchingRule *mr,
4176 	struct berval *value,
4177 	void *assertedValue )
4178 {
4179 	struct berval *asserted = (struct berval *) assertedValue;
4180 	ber_len_t v_len  = value->bv_len;
4181 	ber_len_t av_len = asserted->bv_len;
4182 
4183 	/* ignore trailing 'Z' when comparing */
4184 	int match = memcmp( value->bv_val, asserted->bv_val,
4185 		(v_len < av_len ? v_len : av_len) - 1 );
4186 	if ( match == 0 ) match = v_len - av_len;
4187 
4188 	*matchp = match;
4189 	return LDAP_SUCCESS;
4190 }
4191 
4192 /* Index generation function */
4193 int generalizedTimeIndexer(
4194 	slap_mask_t use,
4195 	slap_mask_t flags,
4196 	Syntax *syntax,
4197 	MatchingRule *mr,
4198 	struct berval *prefix,
4199 	BerVarray values,
4200 	BerVarray *keysp,
4201 	void *ctx )
4202 {
4203 	int i, j;
4204 	BerVarray keys;
4205 	char tmp[5];
4206 	BerValue bvtmp; /* 40 bit index */
4207 	struct lutil_tm tm;
4208 	struct lutil_timet tt;
4209 
4210 	bvtmp.bv_len = sizeof(tmp);
4211 	bvtmp.bv_val = tmp;
4212 	for( i=0; values[i].bv_val != NULL; i++ ) {
4213 		/* just count them */
4214 	}
4215 
4216 	/* we should have at least one value at this point */
4217 	assert( i > 0 );
4218 
4219 	keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
4220 
4221 	/* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4222 	for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
4223 		assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
4224 		/* Use 40 bits of time for key */
4225 		if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
4226 			lutil_tm2time( &tm, &tt );
4227 			tmp[0] = tt.tt_gsec & 0xff;
4228 			tmp[4] = tt.tt_sec & 0xff;
4229 			tt.tt_sec >>= 8;
4230 			tmp[3] = tt.tt_sec & 0xff;
4231 			tt.tt_sec >>= 8;
4232 			tmp[2] = tt.tt_sec & 0xff;
4233 			tt.tt_sec >>= 8;
4234 			tmp[1] = tt.tt_sec & 0xff;
4235 
4236 			ber_dupbv_x(&keys[j++], &bvtmp, ctx );
4237 		}
4238 	}
4239 
4240 	keys[j].bv_val = NULL;
4241 	keys[j].bv_len = 0;
4242 
4243 	*keysp = keys;
4244 
4245 	return LDAP_SUCCESS;
4246 }
4247 
4248 /* Index generation function */
4249 int generalizedTimeFilter(
4250 	slap_mask_t use,
4251 	slap_mask_t flags,
4252 	Syntax *syntax,
4253 	MatchingRule *mr,
4254 	struct berval *prefix,
4255 	void * assertedValue,
4256 	BerVarray *keysp,
4257 	void *ctx )
4258 {
4259 	BerVarray keys;
4260 	char tmp[5];
4261 	BerValue bvtmp; /* 40 bit index */
4262 	BerValue *value = (BerValue *) assertedValue;
4263 	struct lutil_tm tm;
4264 	struct lutil_timet tt;
4265 
4266 	bvtmp.bv_len = sizeof(tmp);
4267 	bvtmp.bv_val = tmp;
4268 	/* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4269 	/* Use 40 bits of time for key */
4270 	if ( value->bv_val && value->bv_len >= 10 &&
4271 		lutil_parsetime( value->bv_val, &tm ) == 0 ) {
4272 
4273 		lutil_tm2time( &tm, &tt );
4274 		tmp[0] = tt.tt_gsec & 0xff;
4275 		tmp[4] = tt.tt_sec & 0xff;
4276 		tt.tt_sec >>= 8;
4277 		tmp[3] = tt.tt_sec & 0xff;
4278 		tt.tt_sec >>= 8;
4279 		tmp[2] = tt.tt_sec & 0xff;
4280 		tt.tt_sec >>= 8;
4281 		tmp[1] = tt.tt_sec & 0xff;
4282 
4283 		keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
4284 		ber_dupbv_x(keys, &bvtmp, ctx );
4285 		keys[1].bv_val = NULL;
4286 		keys[1].bv_len = 0;
4287 	} else {
4288 		keys = NULL;
4289 	}
4290 
4291 	*keysp = keys;
4292 
4293 	return LDAP_SUCCESS;
4294 }
4295 
4296 static int
4297 deliveryMethodValidate(
4298 	Syntax *syntax,
4299 	struct berval *val )
4300 {
4301 #undef LENOF
4302 #define LENOF(s) (sizeof(s)-1)
4303 	struct berval tmp = *val;
4304 	/*
4305      *	DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
4306 	 *	pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
4307 	 *		"g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
4308 	 */
4309 again:
4310 	if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4311 
4312 	switch( tmp.bv_val[0] ) {
4313 	case 'a':
4314 	case 'A':
4315 		if(( tmp.bv_len >= LENOF("any") ) &&
4316 			( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
4317 		{
4318 			tmp.bv_len -= LENOF("any");
4319 			tmp.bv_val += LENOF("any");
4320 			break;
4321 		}
4322 		return LDAP_INVALID_SYNTAX;
4323 
4324 	case 'm':
4325 	case 'M':
4326 		if(( tmp.bv_len >= LENOF("mhs") ) &&
4327 			( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
4328 		{
4329 			tmp.bv_len -= LENOF("mhs");
4330 			tmp.bv_val += LENOF("mhs");
4331 			break;
4332 		}
4333 		return LDAP_INVALID_SYNTAX;
4334 
4335 	case 'p':
4336 	case 'P':
4337 		if(( tmp.bv_len >= LENOF("physical") ) &&
4338 			( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
4339 		{
4340 			tmp.bv_len -= LENOF("physical");
4341 			tmp.bv_val += LENOF("physical");
4342 			break;
4343 		}
4344 		return LDAP_INVALID_SYNTAX;
4345 
4346 	case 't':
4347 	case 'T': /* telex or teletex or telephone */
4348 		if(( tmp.bv_len >= LENOF("telex") ) &&
4349 			( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
4350 		{
4351 			tmp.bv_len -= LENOF("telex");
4352 			tmp.bv_val += LENOF("telex");
4353 			break;
4354 		}
4355 		if(( tmp.bv_len >= LENOF("teletex") ) &&
4356 			( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
4357 		{
4358 			tmp.bv_len -= LENOF("teletex");
4359 			tmp.bv_val += LENOF("teletex");
4360 			break;
4361 		}
4362 		if(( tmp.bv_len >= LENOF("telephone") ) &&
4363 			( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
4364 		{
4365 			tmp.bv_len -= LENOF("telephone");
4366 			tmp.bv_val += LENOF("telephone");
4367 			break;
4368 		}
4369 		return LDAP_INVALID_SYNTAX;
4370 
4371 	case 'g':
4372 	case 'G': /* g3fax or g4fax */
4373 		if(( tmp.bv_len >= LENOF("g3fax") ) && (
4374 			( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
4375 			( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
4376 		{
4377 			tmp.bv_len -= LENOF("g3fax");
4378 			tmp.bv_val += LENOF("g3fax");
4379 			break;
4380 		}
4381 		return LDAP_INVALID_SYNTAX;
4382 
4383 	case 'i':
4384 	case 'I':
4385 		if(( tmp.bv_len >= LENOF("ia5") ) &&
4386 			( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
4387 		{
4388 			tmp.bv_len -= LENOF("ia5");
4389 			tmp.bv_val += LENOF("ia5");
4390 			break;
4391 		}
4392 		return LDAP_INVALID_SYNTAX;
4393 
4394 	case 'v':
4395 	case 'V':
4396 		if(( tmp.bv_len >= LENOF("videotex") ) &&
4397 			( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
4398 		{
4399 			tmp.bv_len -= LENOF("videotex");
4400 			tmp.bv_val += LENOF("videotex");
4401 			break;
4402 		}
4403 		return LDAP_INVALID_SYNTAX;
4404 
4405 	default:
4406 		return LDAP_INVALID_SYNTAX;
4407 	}
4408 
4409 	if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
4410 
4411 	while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4412 		tmp.bv_len++;
4413 		tmp.bv_val--;
4414 	}
4415 	if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
4416 		tmp.bv_len++;
4417 		tmp.bv_val--;
4418 	} else {
4419 		return LDAP_INVALID_SYNTAX;
4420 	}
4421 	while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4422 		tmp.bv_len++;
4423 		tmp.bv_val--;
4424 	}
4425 
4426 	goto again;
4427 }
4428 
4429 static int
4430 nisNetgroupTripleValidate(
4431 	Syntax *syntax,
4432 	struct berval *val )
4433 {
4434 	char *p, *e;
4435 	int commas = 0;
4436 
4437 	if ( BER_BVISEMPTY( val ) ) {
4438 		return LDAP_INVALID_SYNTAX;
4439 	}
4440 
4441 	p = (char *)val->bv_val;
4442 	e = p + val->bv_len;
4443 
4444 	if ( *p != '(' /*')'*/ ) {
4445 		return LDAP_INVALID_SYNTAX;
4446 	}
4447 
4448 	for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
4449 		if ( *p == ',' ) {
4450 			commas++;
4451 			if ( commas > 2 ) {
4452 				return LDAP_INVALID_SYNTAX;
4453 			}
4454 
4455 		} else if ( !AD_CHAR( *p ) ) {
4456 			return LDAP_INVALID_SYNTAX;
4457 		}
4458 	}
4459 
4460 	if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4461 		return LDAP_INVALID_SYNTAX;
4462 	}
4463 
4464 	p++;
4465 
4466 	if (p != e) {
4467 		return LDAP_INVALID_SYNTAX;
4468 	}
4469 
4470 	return LDAP_SUCCESS;
4471 }
4472 
4473 static int
4474 bootParameterValidate(
4475 	Syntax *syntax,
4476 	struct berval *val )
4477 {
4478 	char *p, *e;
4479 
4480 	if ( BER_BVISEMPTY( val ) ) {
4481 		return LDAP_INVALID_SYNTAX;
4482 	}
4483 
4484 	p = (char *)val->bv_val;
4485 	e = p + val->bv_len;
4486 
4487 	/* key */
4488 	for (; ( p < e ) && ( *p != '=' ); p++ ) {
4489 		if ( !AD_CHAR( *p ) ) {
4490 			return LDAP_INVALID_SYNTAX;
4491 		}
4492 	}
4493 
4494 	if ( *p != '=' ) {
4495 		return LDAP_INVALID_SYNTAX;
4496 	}
4497 
4498 	/* server */
4499 	for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4500 		if ( !AD_CHAR( *p ) ) {
4501 			return LDAP_INVALID_SYNTAX;
4502 		}
4503 	}
4504 
4505 	if ( *p != ':' ) {
4506 		return LDAP_INVALID_SYNTAX;
4507 	}
4508 
4509 	/* path */
4510 	for ( p++; p < e; p++ ) {
4511 		if ( !SLAP_PRINTABLE( *p ) ) {
4512 			return LDAP_INVALID_SYNTAX;
4513 		}
4514 	}
4515 
4516 	return LDAP_SUCCESS;
4517 }
4518 
4519 static int
4520 firstComponentNormalize(
4521 	slap_mask_t usage,
4522 	Syntax *syntax,
4523 	MatchingRule *mr,
4524 	struct berval *val,
4525 	struct berval *normalized,
4526 	void *ctx )
4527 {
4528 	int rc;
4529 	struct berval comp;
4530 	ber_len_t len;
4531 
4532 	if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
4533 		ber_dupbv_x( normalized, val, ctx );
4534 		return LDAP_SUCCESS;
4535 	}
4536 
4537 	if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4538 
4539 	if( val->bv_val[0] != '(' /*')'*/ &&
4540 		val->bv_val[0] != '{' /*'}'*/ )
4541 	{
4542 		return LDAP_INVALID_SYNTAX;
4543 	}
4544 
4545 	/* trim leading white space */
4546 	for( len=1;
4547 		len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
4548 		len++ )
4549 	{
4550 		/* empty */
4551 	}
4552 
4553 	/* grab next word */
4554 	comp.bv_val = &val->bv_val[len];
4555 	len = val->bv_len - len;
4556 	for( comp.bv_len = 0;
4557 		!ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
4558 		comp.bv_len++ )
4559 	{
4560 		/* empty */
4561 	}
4562 
4563 	if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
4564 		rc = numericoidValidate( NULL, &comp );
4565 	} else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
4566 		rc = integerValidate( NULL, &comp );
4567 	} else {
4568 		rc = LDAP_INVALID_SYNTAX;
4569 	}
4570 
4571 
4572 	if( rc == LDAP_SUCCESS ) {
4573 		ber_dupbv_x( normalized, &comp, ctx );
4574 	}
4575 
4576 	return rc;
4577 }
4578 
4579 static char *country_gen_syn[] = {
4580 	"1.3.6.1.4.1.1466.115.121.1.15",
4581 	"1.3.6.1.4.1.1466.115.121.1.26",
4582 	"1.3.6.1.4.1.1466.115.121.1.44",
4583 	NULL
4584 };
4585 
4586 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4587 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4588 
4589 static slap_syntax_defs_rec syntax_defs[] = {
4590 	{"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4591 		X_BINARY X_NOT_H_R ")",
4592 		SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4593 	{"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4594 		0, NULL, NULL, NULL},
4595 	{"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4596 		0, NULL, NULL, NULL},
4597 	{"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4598 		X_NOT_H_R ")",
4599 		SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4600 	{"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4601 		X_NOT_H_R ")",
4602 		SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4603 	{"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4604 		0, NULL, bitStringValidate, NULL },
4605 	{"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4606 		0, NULL, booleanValidate, NULL},
4607 	{"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4608 		X_BINARY X_NOT_H_R ")",
4609 		SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4610 		NULL, certificateValidate, NULL},
4611 	{"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4612 		X_BINARY X_NOT_H_R ")",
4613 		SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4614 		NULL, certificateListValidate, NULL},
4615 	{"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4616 		X_BINARY X_NOT_H_R ")",
4617 		SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4618 		NULL, sequenceValidate, NULL},
4619 #if 0	/* need to go __after__ printableString */
4620 	{"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4621 		0, "1.3.6.1.4.1.1466.115.121.1.44",
4622 		countryStringValidate, NULL},
4623 #endif
4624 	{"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4625 		0, NULL, dnValidate, dnPretty},
4626 	{"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4627 		0, NULL, rdnValidate, rdnPretty},
4628 #ifdef LDAP_COMP_MATCH
4629 	{"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4630 		0, NULL, allComponentsValidate, NULL},
4631  	{"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4632 		0, NULL, componentFilterValidate, NULL},
4633 #endif
4634 	{"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4635 		0, NULL, NULL, NULL},
4636 	{"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4637 		0, NULL, deliveryMethodValidate, NULL},
4638 	{"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4639 		0, NULL, UTF8StringValidate, NULL},
4640 	{"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4641 		0, NULL, NULL, NULL},
4642 	{"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4643 		0, NULL, NULL, NULL},
4644 	{"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4645 		0, NULL, NULL, NULL},
4646 	{"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4647 		0, NULL, NULL, NULL},
4648 	{"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4649 		0, NULL, NULL, NULL},
4650 	{"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4651 		0, NULL, printablesStringValidate, NULL},
4652 	{"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4653 		SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4654 	{"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4655 		0, NULL, generalizedTimeValidate, NULL},
4656 	{"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4657 		0, NULL, NULL, NULL},
4658 	{"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4659 		0, NULL, IA5StringValidate, NULL},
4660 	{"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4661 		0, NULL, integerValidate, NULL},
4662 	{"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4663 		SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4664 	{"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4665 		0, NULL, NULL, NULL},
4666 	{"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4667 		0, NULL, NULL, NULL},
4668 	{"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4669 		0, NULL, NULL, NULL},
4670 	{"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4671 		0, NULL, NULL, NULL},
4672 	{"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4673 		0, NULL, NULL, NULL},
4674 	{"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4675 		0, NULL, nameUIDValidate, nameUIDPretty },
4676 	{"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4677 		0, NULL, NULL, NULL},
4678 	{"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4679 		0, NULL, numericStringValidate, NULL},
4680 	{"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4681 		0, NULL, NULL, NULL},
4682 	{"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4683 		0, NULL, numericoidValidate, NULL},
4684 	{"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4685 		0, NULL, IA5StringValidate, NULL},
4686 	{"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4687 		0, NULL, blobValidate, NULL},
4688 	{"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4689 		0, NULL, UTF8StringValidate, NULL},
4690 	{"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4691 		0, NULL, NULL, NULL},
4692 	{"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4693 		0, NULL, NULL, NULL},
4694 	{"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4695 		0, NULL, printableStringValidate, NULL},
4696 	/* moved here because now depends on Directory String, IA5 String
4697 	 * and Printable String */
4698 	{"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4699 		0, country_gen_syn, countryStringValidate, NULL},
4700 	{"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4701 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4702 		0, NULL, subtreeSpecificationValidate, NULL},
4703 	{"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4704 		X_BINARY X_NOT_H_R ")",
4705 		SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4706 	{"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4707 		0, NULL, printableStringValidate, NULL},
4708 	{"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4709 		0, NULL, NULL, NULL},
4710 	{"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4711 		0, NULL, printablesStringValidate, NULL},
4712 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4713 	{"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4714 		0, NULL, utcTimeValidate, NULL},
4715 #endif
4716 	{"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4717 		0, NULL, NULL, NULL},
4718 	{"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4719 		0, NULL, NULL, NULL},
4720 	{"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4721 		0, NULL, NULL, NULL},
4722 	{"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4723 		0, NULL, NULL, NULL},
4724 	{"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4725 		0, NULL, NULL, NULL},
4726 
4727 	/* RFC 2307 NIS Syntaxes */
4728 	{"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4729 		0, NULL, nisNetgroupTripleValidate, NULL},
4730 	{"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4731 		0, NULL, bootParameterValidate, NULL},
4732 
4733 	/* draft-zeilenga-ldap-x509 */
4734 	{"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4735 		SLAP_SYNTAX_HIDE, NULL,
4736 		serialNumberAndIssuerValidate,
4737 		serialNumberAndIssuerPretty},
4738 	{"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4739 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4740 	{"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4741 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4742 	{"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4743 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4744 	{"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4745 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4746 	{"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4747 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4748 	{"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4749 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4750 
4751 #ifdef SLAPD_AUTHPASSWD
4752 	/* needs updating */
4753 	{"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4754 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4755 #endif
4756 
4757 	{"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4758 		0, NULL, UUIDValidate, UUIDPretty},
4759 
4760 	{"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4761 		SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
4762 
4763 	{"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
4764 		SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
4765 
4766 	/* OpenLDAP Void Syntax */
4767 	{"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4768 		SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
4769 
4770 	/* FIXME: OID is unused, but not registered yet */
4771 	{"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4772 		SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
4773 
4774 	{NULL, 0, NULL, NULL, NULL}
4775 };
4776 
4777 char *csnSIDMatchSyntaxes[] = {
4778 	"1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
4779 	NULL
4780 };
4781 char *certificateExactMatchSyntaxes[] = {
4782 	"1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4783 	NULL
4784 };
4785 #ifdef LDAP_COMP_MATCH
4786 char *componentFilterMatchSyntaxes[] = {
4787 	"1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4788 	NULL
4789 };
4790 #endif
4791 char *directoryStringSyntaxes[] = {
4792 	"1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4793 	NULL
4794 };
4795 char *integerFirstComponentMatchSyntaxes[] = {
4796 	"1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4797 	"1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4798 	NULL
4799 };
4800 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4801 	"1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4802 	"1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
4803 	"1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4804 	"1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4805 	"1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4806 	"1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4807 	"1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4808 	"1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4809 	NULL
4810 };
4811 
4812 /*
4813  * Other matching rules in X.520 that we do not use (yet):
4814  *
4815  * 2.5.13.25	uTCTimeMatch
4816  * 2.5.13.26	uTCTimeOrderingMatch
4817  * 2.5.13.31*	directoryStringFirstComponentMatch
4818  * 2.5.13.32*	wordMatch
4819  * 2.5.13.33*	keywordMatch
4820  * 2.5.13.36+	certificatePairExactMatch
4821  * 2.5.13.37+	certificatePairMatch
4822  * 2.5.13.38+	certificateListExactMatch
4823  * 2.5.13.39+	certificateListMatch
4824  * 2.5.13.40+	algorithmIdentifierMatch
4825  * 2.5.13.41*	storedPrefixMatch
4826  * 2.5.13.42	attributeCertificateMatch
4827  * 2.5.13.43	readerAndKeyIDMatch
4828  * 2.5.13.44	attributeIntegrityMatch
4829  *
4830  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4831  * (+) described in draft-zeilenga-ldap-x509
4832  */
4833 static slap_mrule_defs_rec mrule_defs[] = {
4834 	/*
4835 	 * EQUALITY matching rules must be listed after associated APPROX
4836 	 * matching rules.  So, we list all APPROX matching rules first.
4837 	 */
4838 	{"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4839 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4840 		SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4841 		NULL, NULL, directoryStringApproxMatch,
4842 		directoryStringApproxIndexer, directoryStringApproxFilter,
4843 		NULL},
4844 
4845 	{"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4846 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4847 		SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4848 		NULL, NULL, IA5StringApproxMatch,
4849 		IA5StringApproxIndexer, IA5StringApproxFilter,
4850 		NULL},
4851 
4852 	/*
4853 	 * Other matching rules
4854 	 */
4855 
4856 	{"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4857 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4858 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4859 		NULL, NULL, octetStringMatch,
4860 		octetStringIndexer, octetStringFilter,
4861 		NULL },
4862 
4863 	{"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4864 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4865 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4866 		NULL, dnNormalize, dnMatch,
4867 		octetStringIndexer, octetStringFilter,
4868 		NULL },
4869 
4870 	{"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4871 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4872 		SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4873 		NULL, dnNormalize, dnRelativeMatch,
4874 		NULL, NULL,
4875 		NULL },
4876 
4877 	{"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4878 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4879 		SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4880 		NULL, dnNormalize, dnRelativeMatch,
4881 		NULL, NULL,
4882 		NULL },
4883 
4884 	{"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4885 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4886 		SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4887 		NULL, dnNormalize, dnRelativeMatch,
4888 		NULL, NULL,
4889 		NULL },
4890 
4891 	{"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4892 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4893 		SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4894 		NULL, dnNormalize, dnRelativeMatch,
4895 		NULL, NULL,
4896 		NULL },
4897 
4898 	{"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4899 		"SYNTAX 1.2.36.79672281.1.5.0 )",
4900 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4901 		NULL, rdnNormalize, rdnMatch,
4902 		octetStringIndexer, octetStringFilter,
4903 		NULL },
4904 
4905 #ifdef LDAP_COMP_MATCH
4906 	{"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4907 		"SYNTAX 1.2.36.79672281.1.5.2 )",
4908 		SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4909 		NULL, NULL , componentFilterMatch,
4910 		octetStringIndexer, octetStringFilter,
4911 		NULL },
4912 
4913         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4914                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4915                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4916                 NULL, NULL , allComponentsMatch,
4917                 octetStringIndexer, octetStringFilter,
4918                 NULL },
4919 
4920         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4921                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4922                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4923                 NULL, NULL , directoryComponentsMatch,
4924                 octetStringIndexer, octetStringFilter,
4925                 NULL },
4926 #endif
4927 
4928 	{"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4929 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4930 		SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4931 		NULL, UTF8StringNormalize, octetStringMatch,
4932 		octetStringIndexer, octetStringFilter,
4933 		directoryStringApproxMatchOID },
4934 
4935 	{"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4936 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4937 		SLAP_MR_ORDERING, directoryStringSyntaxes,
4938 		NULL, UTF8StringNormalize, octetStringOrderingMatch,
4939 		NULL, NULL,
4940 		"caseIgnoreMatch" },
4941 
4942 	{"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4943 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4944 		SLAP_MR_SUBSTR, directoryStringSyntaxes,
4945 		NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4946 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
4947 		"caseIgnoreMatch" },
4948 
4949 	{"( 2.5.13.5 NAME 'caseExactMatch' "
4950 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4951 		SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4952 		NULL, UTF8StringNormalize, octetStringMatch,
4953 		octetStringIndexer, octetStringFilter,
4954 		directoryStringApproxMatchOID },
4955 
4956 	{"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4957 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4958 		SLAP_MR_ORDERING, directoryStringSyntaxes,
4959 		NULL, UTF8StringNormalize, octetStringOrderingMatch,
4960 		NULL, NULL,
4961 		"caseExactMatch" },
4962 
4963 	{"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4964 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4965 		SLAP_MR_SUBSTR, directoryStringSyntaxes,
4966 		NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4967 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
4968 		"caseExactMatch" },
4969 
4970 	{"( 2.5.13.8 NAME 'numericStringMatch' "
4971 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4972 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4973 		NULL, numericStringNormalize, octetStringMatch,
4974 		octetStringIndexer, octetStringFilter,
4975 		NULL },
4976 
4977 	{"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4978 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4979 		SLAP_MR_ORDERING, NULL,
4980 		NULL, numericStringNormalize, octetStringOrderingMatch,
4981 		NULL, NULL,
4982 		"numericStringMatch" },
4983 
4984 	{"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4985 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4986 		SLAP_MR_SUBSTR, NULL,
4987 		NULL, numericStringNormalize, octetStringSubstringsMatch,
4988 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
4989 		"numericStringMatch" },
4990 
4991 	{"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4992 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4993 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4994 		NULL, NULL, NULL, NULL, NULL, NULL },
4995 
4996 	{"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4997 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4998 		SLAP_MR_SUBSTR, NULL,
4999 		NULL, NULL, NULL, NULL, NULL,
5000 		"caseIgnoreListMatch" },
5001 
5002 	{"( 2.5.13.13 NAME 'booleanMatch' "
5003 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
5004 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5005 		NULL, NULL, booleanMatch,
5006 		octetStringIndexer, octetStringFilter,
5007 		NULL },
5008 
5009 	{"( 2.5.13.14 NAME 'integerMatch' "
5010 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5011 		SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
5012 		NULL, NULL, integerMatch,
5013 		integerIndexer, integerFilter,
5014 		NULL },
5015 
5016 	{"( 2.5.13.15 NAME 'integerOrderingMatch' "
5017 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5018 		SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5019 		NULL, NULL, integerMatch,
5020 		NULL, NULL,
5021 		"integerMatch" },
5022 
5023 	{"( 2.5.13.16 NAME 'bitStringMatch' "
5024 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
5025 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5026 		NULL, NULL, octetStringMatch,
5027 		octetStringIndexer, octetStringFilter,
5028 		NULL },
5029 
5030 	{"( 2.5.13.17 NAME 'octetStringMatch' "
5031 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5032 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5033 		NULL, NULL, octetStringMatch,
5034 		octetStringIndexer, octetStringFilter,
5035 		NULL },
5036 
5037 	{"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
5038 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5039 		SLAP_MR_ORDERING, NULL,
5040 		NULL, NULL, octetStringOrderingMatch,
5041 		NULL, NULL,
5042 		"octetStringMatch" },
5043 
5044 	{"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
5045 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5046 		SLAP_MR_SUBSTR, NULL,
5047 		NULL, NULL, octetStringSubstringsMatch,
5048 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
5049 		"octetStringMatch" },
5050 
5051 	{"( 2.5.13.20 NAME 'telephoneNumberMatch' "
5052 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
5053 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5054 		NULL,
5055 		telephoneNumberNormalize, octetStringMatch,
5056 		octetStringIndexer, octetStringFilter,
5057 		NULL },
5058 
5059 	{"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
5060 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
5061 		SLAP_MR_SUBSTR, NULL,
5062 		NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
5063 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
5064 		"telephoneNumberMatch" },
5065 
5066 	{"( 2.5.13.22 NAME 'presentationAddressMatch' "
5067 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
5068 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5069 		NULL, NULL, NULL, NULL, NULL, NULL },
5070 
5071 	{"( 2.5.13.23 NAME 'uniqueMemberMatch' "
5072 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
5073 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5074 		NULL, uniqueMemberNormalize, uniqueMemberMatch,
5075 		uniqueMemberIndexer, uniqueMemberFilter,
5076 		NULL },
5077 
5078 	{"( 2.5.13.24 NAME 'protocolInformationMatch' "
5079 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
5080 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5081 		NULL, NULL, NULL, NULL, NULL, NULL },
5082 
5083 	{"( 2.5.13.27 NAME 'generalizedTimeMatch' "
5084 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5085 		SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
5086 		NULL, generalizedTimeNormalize, octetStringMatch,
5087 		generalizedTimeIndexer, generalizedTimeFilter,
5088 		NULL },
5089 
5090 	{"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
5091 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5092 		SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5093 		NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
5094 		NULL, NULL,
5095 		"generalizedTimeMatch" },
5096 
5097 	{"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
5098 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5099 		SLAP_MR_EQUALITY | SLAP_MR_EXT,
5100 			integerFirstComponentMatchSyntaxes,
5101 		NULL, firstComponentNormalize, integerMatch,
5102 		octetStringIndexer, octetStringFilter,
5103 		NULL },
5104 
5105 	{"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
5106 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
5107 		SLAP_MR_EQUALITY | SLAP_MR_EXT,
5108 			objectIdentifierFirstComponentMatchSyntaxes,
5109 		NULL, firstComponentNormalize, octetStringMatch,
5110 		octetStringIndexer, octetStringFilter,
5111 		NULL },
5112 
5113 	{"( 2.5.13.34 NAME 'certificateExactMatch' "
5114 		"SYNTAX 1.3.6.1.1.15.1 )",
5115 		SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
5116 		NULL, certificateExactNormalize, octetStringMatch,
5117 		octetStringIndexer, octetStringFilter,
5118 		NULL },
5119 
5120 	{"( 2.5.13.35 NAME 'certificateMatch' "
5121 		"SYNTAX 1.3.6.1.1.15.2 )",
5122 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5123 		NULL, NULL, NULL, NULL, NULL,
5124 		NULL },
5125 
5126 	{"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
5127 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5128 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5129 		NULL, IA5StringNormalize, octetStringMatch,
5130 		octetStringIndexer, octetStringFilter,
5131 		IA5StringApproxMatchOID },
5132 
5133 	{"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
5134 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5135 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5136 		NULL, IA5StringNormalize, octetStringMatch,
5137 		octetStringIndexer, octetStringFilter,
5138 		IA5StringApproxMatchOID },
5139 
5140 	{"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
5141 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5142 		SLAP_MR_SUBSTR, NULL,
5143 		NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5144 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
5145 		"caseIgnoreIA5Match" },
5146 
5147 	{"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
5148 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5149 		SLAP_MR_SUBSTR, NULL,
5150 		NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5151 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
5152 		"caseExactIA5Match" },
5153 
5154 #ifdef SLAPD_AUTHPASSWD
5155 	/* needs updating */
5156 	{"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
5157 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5158 		SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5159 		NULL, NULL, authPasswordMatch,
5160 		NULL, NULL,
5161 		NULL},
5162 #endif
5163 
5164 	{"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
5165 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5166 		SLAP_MR_EXT, NULL,
5167 		NULL, NULL, integerBitAndMatch,
5168 		NULL, NULL,
5169 		"integerMatch" },
5170 
5171 	{"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
5172 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5173 		SLAP_MR_EXT, NULL,
5174 		NULL, NULL, integerBitOrMatch,
5175 		NULL, NULL,
5176 		"integerMatch" },
5177 
5178 	{"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
5179 		"SYNTAX 1.3.6.1.1.16.1 )",
5180 		SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
5181 		NULL, UUIDNormalize, octetStringMatch,
5182 		octetStringIndexer, octetStringFilter,
5183 		NULL},
5184 
5185 	{"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
5186 		"SYNTAX 1.3.6.1.1.16.1 )",
5187 		SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
5188 		NULL, UUIDNormalize, octetStringOrderingMatch,
5189 		octetStringIndexer, octetStringFilter,
5190 		"UUIDMatch"},
5191 
5192 	{"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
5193 		"SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5194 		SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
5195 		NULL, csnNormalize, csnMatch,
5196 		csnIndexer, csnFilter,
5197 		NULL},
5198 
5199 	{"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
5200 		"SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5201 		SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5202 		NULL, NULL, csnOrderingMatch,
5203 		NULL, NULL,
5204 		"CSNMatch" },
5205 
5206 	{"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
5207 		"SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
5208 		SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
5209 		NULL, csnSidNormalize, octetStringMatch,
5210 		octetStringIndexer, octetStringFilter,
5211 		NULL },
5212 
5213 	/* FIXME: OID is unused, but not registered yet */
5214 	{"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
5215 		"SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
5216 		SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5217 		NULL, authzNormalize, authzMatch,
5218 		NULL, NULL,
5219 		NULL},
5220 
5221 	{NULL, SLAP_MR_NONE, NULL,
5222 		NULL, NULL, NULL, NULL, NULL,
5223 		NULL }
5224 };
5225 
5226 int
5227 slap_schema_init( void )
5228 {
5229 	int		res;
5230 	int		i;
5231 
5232 	/* we should only be called once (from main) */
5233 	assert( schema_init_done == 0 );
5234 
5235 	for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
5236 		res = register_syntax( &syntax_defs[i] );
5237 
5238 		if ( res ) {
5239 			fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
5240 				 syntax_defs[i].sd_desc );
5241 			return LDAP_OTHER;
5242 		}
5243 	}
5244 
5245 	for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
5246 		if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
5247 			mrule_defs[i].mrd_compat_syntaxes == NULL )
5248 		{
5249 			fprintf( stderr,
5250 				"slap_schema_init: Ignoring unusable matching rule %s\n",
5251 				 mrule_defs[i].mrd_desc );
5252 			continue;
5253 		}
5254 
5255 		res = register_matching_rule( &mrule_defs[i] );
5256 
5257 		if ( res ) {
5258 			fprintf( stderr,
5259 				"slap_schema_init: Error registering matching rule %s\n",
5260 				 mrule_defs[i].mrd_desc );
5261 			return LDAP_OTHER;
5262 		}
5263 	}
5264 
5265 	res = slap_schema_load();
5266 	schema_init_done = 1;
5267 	return res;
5268 }
5269 
5270 void
5271 schema_destroy( void )
5272 {
5273 	oidm_destroy();
5274 	oc_destroy();
5275 	at_destroy();
5276 	mr_destroy();
5277 	mru_destroy();
5278 	syn_destroy();
5279 
5280 	if( schema_init_done ) {
5281 		ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
5282 		ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
5283 	}
5284 }
5285