xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/schema_init.c (revision 2de962bd804263c16657f586aa00f1704045df8e)
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/schema_init.c,v 1.386.2.20 2008/04/14 20:01:31 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 
2277 	iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2278 		? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2279 	if ( iv.bv_len > (int) sizeof(ibuf) ) {
2280 		iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2281 	} else {
2282 		iv.bv_val = ibuf;
2283 		iv.bv_len = sizeof(ibuf);
2284 	}
2285 
2286 	rc = integerVal2Key( value, keys, &iv, ctx );
2287 	if ( rc == 0 )
2288 		*keysp = keys;
2289 
2290 	if ( iv.bv_val != ibuf ) {
2291 		slap_sl_free( iv.bv_val, ctx );
2292 	}
2293 	return rc;
2294 }
2295 
2296 static int
2297 countryStringValidate(
2298 	Syntax *syntax,
2299 	struct berval *val )
2300 {
2301 	if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2302 
2303 	if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2304 		return LDAP_INVALID_SYNTAX;
2305 	}
2306 	if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2307 		return LDAP_INVALID_SYNTAX;
2308 	}
2309 
2310 	return LDAP_SUCCESS;
2311 }
2312 
2313 static int
2314 printableStringValidate(
2315 	Syntax *syntax,
2316 	struct berval *val )
2317 {
2318 	ber_len_t i;
2319 
2320 	if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2321 
2322 	for(i=0; i < val->bv_len; i++) {
2323 		if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2324 			return LDAP_INVALID_SYNTAX;
2325 		}
2326 	}
2327 
2328 	return LDAP_SUCCESS;
2329 }
2330 
2331 static int
2332 printablesStringValidate(
2333 	Syntax *syntax,
2334 	struct berval *val )
2335 {
2336 	ber_len_t i, len;
2337 
2338 	if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2339 
2340 	for(i=0,len=0; i < val->bv_len; i++) {
2341 		int c = val->bv_val[i];
2342 
2343 		if( c == '$' ) {
2344 			if( len == 0 ) {
2345 				return LDAP_INVALID_SYNTAX;
2346 			}
2347 			len = 0;
2348 
2349 		} else if ( SLAP_PRINTABLE(c) ) {
2350 			len++;
2351 		} else {
2352 			return LDAP_INVALID_SYNTAX;
2353 		}
2354 	}
2355 
2356 	if( len == 0 ) {
2357 		return LDAP_INVALID_SYNTAX;
2358 	}
2359 
2360 	return LDAP_SUCCESS;
2361 }
2362 
2363 static int
2364 IA5StringValidate(
2365 	Syntax *syntax,
2366 	struct berval *val )
2367 {
2368 	ber_len_t i;
2369 
2370 	for(i=0; i < val->bv_len; i++) {
2371 		if( !LDAP_ASCII(val->bv_val[i]) ) {
2372 			return LDAP_INVALID_SYNTAX;
2373 		}
2374 	}
2375 
2376 	return LDAP_SUCCESS;
2377 }
2378 
2379 static int
2380 IA5StringNormalize(
2381 	slap_mask_t use,
2382 	Syntax *syntax,
2383 	MatchingRule *mr,
2384 	struct berval *val,
2385 	struct berval *normalized,
2386 	void *ctx )
2387 {
2388 	char *p, *q;
2389 	int casefold = !SLAP_MR_ASSOCIATED( mr,
2390 		slap_schema.si_mr_caseExactIA5Match );
2391 
2392 	assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2393 
2394 	p = val->bv_val;
2395 
2396 	/* Ignore initial whitespace */
2397 	while ( ASCII_SPACE( *p ) ) p++;
2398 
2399 	normalized->bv_len = val->bv_len - ( p - val->bv_val );
2400 	normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2401 	AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2402 	normalized->bv_val[normalized->bv_len] = '\0';
2403 
2404 	p = q = normalized->bv_val;
2405 
2406 	while ( *p ) {
2407 		if ( ASCII_SPACE( *p ) ) {
2408 			*q++ = *p++;
2409 
2410 			/* Ignore the extra whitespace */
2411 			while ( ASCII_SPACE( *p ) ) {
2412 				p++;
2413 			}
2414 
2415 		} else if ( casefold ) {
2416 			/* Most IA5 rules require casefolding */
2417 			*q++ = TOLOWER(*p); p++;
2418 
2419 		} else {
2420 			*q++ = *p++;
2421 		}
2422 	}
2423 
2424 	assert( normalized->bv_val <= p );
2425 	assert( q <= p );
2426 
2427 	/*
2428 	 * If the string ended in space, backup the pointer one
2429 	 * position.  One is enough because the above loop collapsed
2430 	 * all whitespace to a single space.
2431 	 */
2432 	if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2433 
2434 	/* null terminate */
2435 	*q = '\0';
2436 
2437 	normalized->bv_len = q - normalized->bv_val;
2438 
2439 	return LDAP_SUCCESS;
2440 }
2441 
2442 static int
2443 UUIDValidate(
2444 	Syntax *syntax,
2445 	struct berval *in )
2446 {
2447 	int i;
2448 	if( in->bv_len != 36 ) {
2449 		return LDAP_INVALID_SYNTAX;
2450 	}
2451 
2452 	for( i=0; i<36; i++ ) {
2453 		switch(i) {
2454 			case 8:
2455 			case 13:
2456 			case 18:
2457 			case 23:
2458 				if( in->bv_val[i] != '-' ) {
2459 					return LDAP_INVALID_SYNTAX;
2460 				}
2461 				break;
2462 			default:
2463 				if( !ASCII_HEX( in->bv_val[i]) ) {
2464 					return LDAP_INVALID_SYNTAX;
2465 				}
2466 		}
2467 	}
2468 
2469 	return LDAP_SUCCESS;
2470 }
2471 
2472 static int
2473 UUIDPretty(
2474 	Syntax *syntax,
2475 	struct berval *in,
2476 	struct berval *out,
2477 	void *ctx )
2478 {
2479 	int i;
2480 	int rc=LDAP_INVALID_SYNTAX;
2481 
2482 	assert( in != NULL );
2483 	assert( out != NULL );
2484 
2485 	if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2486 
2487 	out->bv_len = 36;
2488 	out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2489 
2490 	for( i=0; i<36; i++ ) {
2491 		switch(i) {
2492 			case 8:
2493 			case 13:
2494 			case 18:
2495 			case 23:
2496 				if( in->bv_val[i] != '-' ) {
2497 					goto handle_error;
2498 				}
2499 				out->bv_val[i] = '-';
2500 				break;
2501 
2502 			default:
2503 				if( !ASCII_HEX( in->bv_val[i]) ) {
2504 					goto handle_error;
2505 				}
2506 				out->bv_val[i] = TOLOWER( in->bv_val[i] );
2507 		}
2508 	}
2509 
2510 	rc = LDAP_SUCCESS;
2511 	out->bv_val[ out->bv_len ] = '\0';
2512 
2513 	if( 0 ) {
2514 handle_error:
2515 		slap_sl_free( out->bv_val, ctx );
2516 		out->bv_val = NULL;
2517 	}
2518 
2519 	return rc;
2520 }
2521 
2522 int
2523 UUIDNormalize(
2524 	slap_mask_t usage,
2525 	Syntax *syntax,
2526 	MatchingRule *mr,
2527 	struct berval *val,
2528 	struct berval *normalized,
2529 	void *ctx )
2530 {
2531 	unsigned char octet = '\0';
2532 	int i;
2533 	int j;
2534 
2535 	if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2536 		/* NOTE: must be a normalized UUID */
2537 		assert( val->bv_len == 16 );
2538 
2539 		normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2540 		normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2541 			val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2542 		assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2543 
2544 		return LDAP_SUCCESS;
2545 	}
2546 
2547 	normalized->bv_len = 16;
2548 	normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2549 
2550 	for( i=0, j=0; i<36; i++ ) {
2551 		unsigned char nibble;
2552 		if( val->bv_val[i] == '-' ) {
2553 			continue;
2554 
2555 		} else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2556 			nibble = val->bv_val[i] - '0';
2557 
2558 		} else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2559 			nibble = val->bv_val[i] - ('a'-10);
2560 
2561 		} else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2562 			nibble = val->bv_val[i] - ('A'-10);
2563 
2564 		} else {
2565 			slap_sl_free( normalized->bv_val, ctx );
2566 			return LDAP_INVALID_SYNTAX;
2567 		}
2568 
2569 		if( j & 1 ) {
2570 			octet |= nibble;
2571 			normalized->bv_val[j>>1] = octet;
2572 		} else {
2573 			octet = nibble << 4;
2574 		}
2575 		j++;
2576 	}
2577 
2578 	normalized->bv_val[normalized->bv_len] = 0;
2579 	return LDAP_SUCCESS;
2580 }
2581 
2582 
2583 
2584 int
2585 numericStringValidate(
2586 	Syntax *syntax,
2587 	struct berval *in )
2588 {
2589 	ber_len_t i;
2590 
2591 	if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2592 
2593 	for(i=0; i < in->bv_len; i++) {
2594 		if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2595 			return LDAP_INVALID_SYNTAX;
2596 		}
2597 	}
2598 
2599 	return LDAP_SUCCESS;
2600 }
2601 
2602 static int
2603 numericStringNormalize(
2604 	slap_mask_t usage,
2605 	Syntax *syntax,
2606 	MatchingRule *mr,
2607 	struct berval *val,
2608 	struct berval *normalized,
2609 	void *ctx )
2610 {
2611 	/* removal all spaces */
2612 	char *p, *q;
2613 
2614 	assert( !BER_BVISEMPTY( val ) );
2615 
2616 	normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2617 
2618 	p = val->bv_val;
2619 	q = normalized->bv_val;
2620 
2621 	while ( *p ) {
2622 		if ( ASCII_SPACE( *p ) ) {
2623 			/* Ignore whitespace */
2624 			p++;
2625 		} else {
2626 			*q++ = *p++;
2627 		}
2628 	}
2629 
2630 	/* we should have copied no more than is in val */
2631 	assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2632 
2633 	/* null terminate */
2634 	*q = '\0';
2635 
2636 	normalized->bv_len = q - normalized->bv_val;
2637 
2638 	if( BER_BVISEMPTY( normalized ) ) {
2639 		normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2640 		normalized->bv_val[0] = ' ';
2641 		normalized->bv_val[1] = '\0';
2642 		normalized->bv_len = 1;
2643 	}
2644 
2645 	return LDAP_SUCCESS;
2646 }
2647 
2648 /*
2649  * Integer conversion macros that will use the largest available
2650  * type.
2651  */
2652 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2653 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b)
2654 # define SLAP_LONG           long long
2655 #else
2656 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2657 # define SLAP_LONG           long
2658 #endif /* HAVE_STRTOLL ... */
2659 
2660 static int
2661 integerBitAndMatch(
2662 	int *matchp,
2663 	slap_mask_t flags,
2664 	Syntax *syntax,
2665 	MatchingRule *mr,
2666 	struct berval *value,
2667 	void *assertedValue )
2668 {
2669 	SLAP_LONG lValue, lAssertedValue;
2670 
2671 	errno = 0;
2672 	/* safe to assume integers are NUL terminated? */
2673 	lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2674 	if( errno == ERANGE )
2675 	{
2676 		return LDAP_CONSTRAINT_VIOLATION;
2677 	}
2678 
2679 	lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2680 		NULL, 10);
2681 	if( errno == ERANGE )
2682 	{
2683 		return LDAP_CONSTRAINT_VIOLATION;
2684 	}
2685 
2686 	*matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2687 	return LDAP_SUCCESS;
2688 }
2689 
2690 static int
2691 integerBitOrMatch(
2692 	int *matchp,
2693 	slap_mask_t flags,
2694 	Syntax *syntax,
2695 	MatchingRule *mr,
2696 	struct berval *value,
2697 	void *assertedValue )
2698 {
2699 	SLAP_LONG lValue, lAssertedValue;
2700 
2701 	errno = 0;
2702 	/* safe to assume integers are NUL terminated? */
2703 	lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2704 	if( errno == ERANGE )
2705 	{
2706 		return LDAP_CONSTRAINT_VIOLATION;
2707 	}
2708 
2709 	lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2710 		NULL, 10);
2711 	if( errno == ERANGE )
2712 	{
2713 		return LDAP_CONSTRAINT_VIOLATION;
2714 	}
2715 
2716 	*matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2717 	return LDAP_SUCCESS;
2718 }
2719 
2720 static int
2721 serialNumberAndIssuerCheck(
2722 	struct berval *in,
2723 	struct berval *sn,
2724 	struct berval *is,
2725 	void *ctx
2726 )
2727 {
2728 	int is_hex = 0, n;
2729 
2730 	if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2731 
2732 	if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2733 		/* Parse old format */
2734 		is->bv_val = ber_bvchr( in, '$' );
2735 		if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
2736 
2737 		sn->bv_val = in->bv_val;
2738 		sn->bv_len = is->bv_val - in->bv_val;
2739 
2740 		is->bv_val++;
2741 		is->bv_len = in->bv_len - (sn->bv_len + 1);
2742 
2743 		/* eat leading zeros */
2744 		for( n=0; n < (sn->bv_len-1); n++ ) {
2745 			if( sn->bv_val[n] != '0' ) break;
2746 		}
2747 		sn->bv_val += n;
2748 		sn->bv_len -= n;
2749 
2750 		for( n=0; n < sn->bv_len; n++ ) {
2751 			if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2752 		}
2753 
2754 	} else {
2755 		/* Parse GSER format */
2756 		int havesn=0,haveissuer=0;
2757 		struct berval x = *in;
2758 		struct berval ni;
2759 		x.bv_val++;
2760 		x.bv_len-=2;
2761 
2762 		/* eat leading spaces */
2763 		for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2764 			/* empty */;
2765 		}
2766 
2767 		if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2768 			return LDAP_INVALID_SYNTAX;
2769 		}
2770 
2771 		/* should be at issuer or serialNumber NamedValue */
2772 		if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2773 			/* parse issuer */
2774 			x.bv_val += STRLENOF("issuer");
2775 			x.bv_len -= STRLENOF("issuer");
2776 
2777 			if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2778 			x.bv_val++; x.bv_len--;
2779 
2780 			/* eat leading spaces */
2781 			for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2782 				/* empty */;
2783 			}
2784 
2785 			/* For backward compatibility, this part is optional */
2786 			if( !strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:"))) {
2787 				x.bv_val += STRLENOF("rdnSequence:");
2788 				x.bv_len -= STRLENOF("rdnSequence:");
2789 			}
2790 
2791 			if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2792 			x.bv_val++; x.bv_len--;
2793 
2794 			is->bv_val = x.bv_val;
2795 			is->bv_len = 0;
2796 
2797 			for( ; is->bv_len < x.bv_len; ) {
2798 				if ( is->bv_val[is->bv_len] != '"' ) {
2799 					is->bv_len++;
2800 					continue;
2801 				}
2802 				if ( is->bv_val[is->bv_len+1] == '"' ) {
2803 					/* double dquote */
2804 					is->bv_len+=2;
2805 					continue;
2806 				}
2807 				break;
2808 			}
2809 			x.bv_val += is->bv_len+1;
2810 			x.bv_len -= is->bv_len+1;
2811 
2812 			if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2813 				return LDAP_INVALID_SYNTAX;
2814 			}
2815 
2816 			haveissuer++;
2817 
2818 		} else if( strncasecmp( x.bv_val, "serialNumber",
2819 			STRLENOF("serialNumber")) == 0 )
2820 		{
2821 			/* parse serialNumber */
2822 			int neg=0;
2823 			x.bv_val += STRLENOF("serialNumber");
2824 			x.bv_len -= STRLENOF("serialNumber");
2825 
2826 			if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2827 			x.bv_val++; x.bv_len--;
2828 
2829 			/* eat leading spaces */
2830 			for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2831 				/* empty */;
2832 			}
2833 
2834 			sn->bv_val = x.bv_val;
2835 			sn->bv_len = 0;
2836 
2837 			if( sn->bv_val[0] == '-' ) {
2838 				neg++;
2839 				sn->bv_len++;
2840 			}
2841 
2842 			if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2843 				sn->bv_val[1] == 'X' )) {
2844 				is_hex = 1;
2845 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2846 					if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2847 				}
2848 			} else if ( sn->bv_val[0] == '\'' ) {
2849 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2850 					if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2851 				}
2852 				if ( sn->bv_val[sn->bv_len] == '\'' &&
2853 					sn->bv_val[sn->bv_len+1] == 'H' )
2854 					is_hex = 1;
2855 				else
2856 					return LDAP_INVALID_SYNTAX;
2857 				sn->bv_len += 2;
2858 			} else {
2859 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2860 					if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2861 				}
2862 			}
2863 
2864 			if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2865 			if (( sn->bv_len > 1+neg ) && ( sn->bv_val[neg] == '0' )) {
2866 				return LDAP_INVALID_SYNTAX;
2867 			}
2868 
2869 			x.bv_val += sn->bv_len; x.bv_len -= sn->bv_len;
2870 
2871 			if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2872 				return LDAP_INVALID_SYNTAX;
2873 			}
2874 
2875 			havesn++;
2876 
2877 		} else return LDAP_INVALID_SYNTAX;
2878 
2879 		if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2880 		x.bv_val++; x.bv_len--;
2881 
2882 		/* eat spaces */
2883 		for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2884 			/* empty */;
2885 		}
2886 
2887 		/* should be at remaining NamedValue */
2888 		if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2889 			STRLENOF("issuer" )) == 0 ))
2890 		{
2891 			/* parse issuer */
2892 			x.bv_val += STRLENOF("issuer");
2893 			x.bv_len -= STRLENOF("issuer");
2894 
2895 			if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2896 			x.bv_val++; x.bv_len--;
2897 
2898 			/* eat leading spaces */
2899 			for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2900 				 /* empty */;
2901 			}
2902 
2903 			/* For backward compatibility, this part is optional */
2904 			if( !strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:"))) {
2905 				x.bv_val += STRLENOF("rdnSequence:");
2906 				x.bv_len -= STRLENOF("rdnSequence:");
2907 			}
2908 
2909 			if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2910 			x.bv_val++; x.bv_len--;
2911 
2912 			is->bv_val = x.bv_val;
2913 			is->bv_len = 0;
2914 
2915 			for( ; is->bv_len < x.bv_len; ) {
2916 				if ( is->bv_val[is->bv_len] != '"' ) {
2917 					is->bv_len++;
2918 					continue;
2919 				}
2920 				if ( is->bv_val[is->bv_len+1] == '"' ) {
2921 					/* double dquote */
2922 					is->bv_len+=2;
2923 					continue;
2924 				}
2925 				break;
2926 			}
2927 			x.bv_val += is->bv_len+1;
2928 			x.bv_len -= is->bv_len+1;
2929 
2930 		} else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2931 			STRLENOF("serialNumber")) == 0 ))
2932 		{
2933 			/* parse serialNumber */
2934 			int neg=0;
2935 			x.bv_val += STRLENOF("serialNumber");
2936 			x.bv_len -= STRLENOF("serialNumber");
2937 
2938 			if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2939 			x.bv_val++; x.bv_len--;
2940 
2941 			/* eat leading spaces */
2942 			for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2943 				/* empty */;
2944 			}
2945 
2946 			sn->bv_val = x.bv_val;
2947 			sn->bv_len = 0;
2948 
2949 			if( sn->bv_val[0] == '-' ) {
2950 				neg++;
2951 				sn->bv_len++;
2952 			}
2953 
2954 			if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2955 				sn->bv_val[1] == 'X' )) {
2956 				is_hex = 1;
2957 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2958 					if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2959 				}
2960 			} else if ( sn->bv_val[0] == '\'' ) {
2961 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2962 					if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2963 				}
2964 				if ( sn->bv_val[sn->bv_len] == '\'' &&
2965 					sn->bv_val[sn->bv_len+1] == 'H' )
2966 					is_hex = 1;
2967 				else
2968 					return LDAP_INVALID_SYNTAX;
2969 				sn->bv_len += 2;
2970 			} else {
2971 				for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2972 					if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2973 				}
2974 			}
2975 
2976 			if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2977 			if (( sn->bv_len > 1+neg ) && ( sn->bv_val[neg] == '0' )) {
2978 				return LDAP_INVALID_SYNTAX;
2979 			}
2980 
2981 			x.bv_val += sn->bv_len;
2982 			x.bv_len -= sn->bv_len;
2983 
2984 		} else return LDAP_INVALID_SYNTAX;
2985 
2986 		/* eat trailing spaces */
2987 		for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2988 			/* empty */;
2989 		}
2990 
2991 		/* should have no characters left... */
2992 		if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2993 
2994 		ber_dupbv_x( &ni, is, ctx );
2995 		*is = ni;
2996 
2997 		/* need to handle double dquotes here */
2998 	}
2999 	return 0;
3000 }
3001 
3002 static int
3003 serialNumberAndIssuerValidate(
3004 	Syntax *syntax,
3005 	struct berval *in )
3006 {
3007 	int rc;
3008 	struct berval sn, i;
3009 
3010 	Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3011 		in->bv_val, 0, 0 );
3012 
3013 	rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3014 	if ( rc )
3015 		return rc;
3016 
3017 	/* validate DN -- doesn't handle double dquote */
3018 	rc = dnValidate( NULL, &i );
3019 	if( rc )
3020 		rc = LDAP_INVALID_SYNTAX;
3021 
3022 	if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3023 		slap_sl_free( i.bv_val, NULL );
3024 	}
3025 
3026 	Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: OKAY\n",
3027 		0, 0, 0 );
3028 	return rc;
3029 }
3030 
3031 int
3032 serialNumberAndIssuerPretty(
3033 	Syntax *syntax,
3034 	struct berval *in,
3035 	struct berval *out,
3036 	void *ctx )
3037 {
3038 	int n, rc;
3039 	struct berval sn, i, ni;
3040 
3041 	assert( in != NULL );
3042 	assert( out != NULL );
3043 
3044 	Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3045 		in->bv_val, 0, 0 );
3046 
3047 	rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3048 	if ( rc )
3049 		return rc;
3050 
3051 	rc = dnPretty( syntax, &i, &ni, ctx );
3052 
3053 	if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3054 		slap_sl_free( i.bv_val, ctx );
3055 	}
3056 
3057 	if( rc ) return LDAP_INVALID_SYNTAX;
3058 
3059 	/* make room from sn + "$" */
3060 	out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3061 		+ sn.bv_len + ni.bv_len;
3062 	out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3063 
3064 	if( out->bv_val == NULL ) {
3065 		out->bv_len = 0;
3066 		slap_sl_free( ni.bv_val, ctx );
3067 		return LDAP_OTHER;
3068 	}
3069 
3070 	n = 0;
3071 	AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3072 		STRLENOF("{ serialNumber "));
3073 	n = STRLENOF("{ serialNumber ");
3074 
3075 	AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3076 	n += sn.bv_len;
3077 
3078 	AC_MEMCPY( &out->bv_val[n], ", issuer rdnSequence:\"", STRLENOF(", issuer rdnSequence:\""));
3079 	n += STRLENOF(", issuer rdnSequence:\"");
3080 
3081 	AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3082 	n += ni.bv_len;
3083 
3084 	AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
3085 	n += STRLENOF("\" }");
3086 
3087 	out->bv_val[n] = '\0';
3088 
3089 	assert( n == out->bv_len );
3090 
3091 	Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
3092 		out->bv_val, 0, 0 );
3093 
3094 	slap_sl_free( ni.bv_val, ctx );
3095 
3096 	return LDAP_SUCCESS;
3097 }
3098 
3099 /*
3100  * This routine is called by certificateExactNormalize when
3101  * certificateExactNormalize receives a search string instead of
3102  * a certificate. This routine checks if the search value is valid
3103  * and then returns the normalized value
3104  */
3105 static int
3106 serialNumberAndIssuerNormalize(
3107 	slap_mask_t usage,
3108 	Syntax *syntax,
3109 	MatchingRule *mr,
3110 	struct berval *in,
3111 	struct berval *out,
3112 	void *ctx )
3113 {
3114 	struct berval sn, sn2, i, ni;
3115 	char sbuf[64], *stmp = sbuf;
3116 	int rc;
3117 	ber_len_t n;
3118 
3119 	assert( in != NULL );
3120 	assert( out != NULL );
3121 
3122 	Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3123 		in->bv_val, 0, 0 );
3124 
3125 	rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3126 	if ( rc )
3127 		return rc;
3128 
3129 	rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3130 
3131 	if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3132 		slap_sl_free( i.bv_val, ctx );
3133 	}
3134 
3135 	if( rc ) return LDAP_INVALID_SYNTAX;
3136 
3137 	/* Convert sn to canonical hex */
3138 	if ( sn.bv_len > sizeof( sbuf )) {
3139 		stmp = slap_sl_malloc( sn.bv_len, ctx );
3140 	}
3141 	sn2.bv_val = stmp;
3142 	sn2.bv_len = sn.bv_len;
3143 	if ( lutil_str2bin( &sn, &sn2, ctx )) {
3144 		rc = LDAP_INVALID_SYNTAX;
3145 		goto func_leave;
3146 	}
3147 
3148 	/* make room for sn + "$" */
3149 	out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3150 		+ ( sn2.bv_len * 2 + 3 ) + ni.bv_len;
3151 	out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3152 
3153 	if( out->bv_val == NULL ) {
3154 		out->bv_len = 0;
3155 		slap_sl_free( ni.bv_val, ctx );
3156 		rc = LDAP_OTHER;
3157 		goto func_leave;
3158 	}
3159 
3160 	n = 0;
3161 	AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3162 		STRLENOF( "{ serialNumber " ));
3163 	n = STRLENOF( "{ serialNumber " );
3164 
3165 	AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3166 	{
3167 		int j;
3168 		unsigned char *v = (unsigned char *)sn2.bv_val;
3169 		out->bv_val[n++] = '\'';
3170 		for ( j = 0; j < sn2.bv_len; j++ ) {
3171 			snprintf( &out->bv_val[n], out->bv_len - n + 1,
3172 				"%02X", v[j] );
3173 			n += 2;
3174 		}
3175 		out->bv_val[n++] = '\'';
3176 		out->bv_val[n++] = 'H';
3177 	}
3178 
3179 	AC_MEMCPY( &out->bv_val[n], ", issuer rdnSequence:\"", STRLENOF( ", issuer rdnSequence:\"" ));
3180 	n += STRLENOF( ", issuer rdnSequence:\"" );
3181 
3182 	AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3183 	n += ni.bv_len;
3184 
3185 	AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
3186 	n += STRLENOF( "\" }" );
3187 
3188 	out->bv_val[n] = '\0';
3189 
3190 	assert( n == out->bv_len );
3191 
3192 	Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
3193 		out->bv_val, 0, 0 );
3194 
3195 func_leave:
3196 	if ( stmp != sbuf )
3197 		slap_sl_free( stmp, ctx );
3198 	slap_sl_free( ni.bv_val, ctx );
3199 
3200 	return rc;
3201 }
3202 
3203 static int
3204 certificateExactNormalize(
3205 	slap_mask_t usage,
3206 	Syntax *syntax,
3207 	MatchingRule *mr,
3208 	struct berval *val,
3209 	struct berval *normalized,
3210 	void *ctx )
3211 {
3212 	BerElementBuffer berbuf;
3213 	BerElement *ber = (BerElement *)&berbuf;
3214 	ber_tag_t tag;
3215 	ber_len_t len;
3216 	ber_int_t i;
3217 	char serialbuf[64], *serial = serialbuf;
3218 	ber_len_t seriallen;
3219 	struct berval issuer_dn = BER_BVNULL, bvdn;
3220 	unsigned char *p;
3221 	int rc = LDAP_INVALID_SYNTAX;
3222 
3223 	if( BER_BVISEMPTY( val ) ) goto done;
3224 
3225 	if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3226 		return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
3227 	}
3228 
3229 	assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3230 
3231 	ber_init2( ber, val, LBER_USE_DER );
3232 	tag = ber_skip_tag( ber, &len );	/* Signed Sequence */
3233 	tag = ber_skip_tag( ber, &len );	/* Sequence */
3234 	tag = ber_peek_tag( ber, &len );	/* Optional version? */
3235 	if ( tag == SLAP_X509_OPT_C_VERSION ) {
3236 		tag = ber_skip_tag( ber, &len );
3237 		tag = ber_get_int( ber, &i );	/* version */
3238 	}
3239 
3240 	/* NOTE: move the test here from certificateValidate,
3241 	 * so that we can validate certs with serial longer
3242 	 * than sizeof(ber_int_t) */
3243 	tag = ber_peek_tag( ber, &len );	/* serial */
3244 
3245 	/* Use hex format. '123456789abcdef'H
3246 	 */
3247 	{
3248 		unsigned char *ptr;
3249 		char *sptr;
3250 
3251 		tag = ber_skip_tag( ber, &len );
3252 		ptr = (unsigned char *)ber->ber_ptr;
3253 		ber_skip_data( ber, len );
3254 
3255 		/* Check for minimal encodings */
3256 		if ( len > 1 ) {
3257 			if ( ptr[0] & 0x80 ) {
3258 				if (( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ))
3259 					return LDAP_INVALID_SYNTAX;
3260 			} else if ( ptr[0] == 0 ) {
3261 				if (!( ptr[1] & 0x80 ))
3262 					return LDAP_INVALID_SYNTAX;
3263 			}
3264 		}
3265 
3266 		seriallen = len * 2 + 4;	/* quotes, H, NUL */
3267 		if ( seriallen > sizeof( serialbuf ))
3268 			serial = slap_sl_malloc( seriallen, ctx );
3269 		sptr = serial;
3270 		*sptr++ = '\'';
3271 		for ( i = 0; i<len; i++ ) {
3272 			sprintf( sptr, "%02X", ptr[i] );
3273 			sptr += 2;
3274 		}
3275 		*sptr++ = '\'';
3276 		*sptr++ = 'H';
3277 		seriallen--;
3278 	}
3279 	tag = ber_skip_tag( ber, &len );	/* SignatureAlg */
3280 	ber_skip_data( ber, len );
3281 	tag = ber_peek_tag( ber, &len );	/* IssuerDN */
3282 	len = ber_ptrlen( ber );
3283 	bvdn.bv_val = val->bv_val + len;
3284 	bvdn.bv_len = val->bv_len - len;
3285 
3286 	rc = dnX509normalize( &bvdn, &issuer_dn );
3287 	if( rc != LDAP_SUCCESS ) goto done;
3288 
3289 	normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3290 		+ seriallen + issuer_dn.bv_len;
3291 	normalized->bv_val = ch_malloc(normalized->bv_len+1);
3292 
3293 	p = (unsigned char *)normalized->bv_val;
3294 
3295 	AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3296 	p += STRLENOF( "{ serialNumber " );
3297 
3298 	AC_MEMCPY(p, serial, seriallen);
3299 	p += seriallen;
3300 
3301 	AC_MEMCPY(p, ", issuer rdnSequence:\"", STRLENOF( ", issuer rdnSequence:\"" ));
3302 	p += STRLENOF( ", issuer rdnSequence:\"" );
3303 
3304 	AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3305 	p += issuer_dn.bv_len;
3306 
3307 	AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3308 	p += STRLENOF( "\" }" );
3309 
3310 	*p = '\0';
3311 
3312 	Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3313 		normalized->bv_val, NULL, NULL );
3314 
3315 	rc = LDAP_SUCCESS;
3316 
3317 done:
3318 	if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3319 	if ( serial != serialbuf ) ber_memfree_x( serial, ctx );
3320 
3321 	return rc;
3322 }
3323 
3324 static int
3325 hexValidate(
3326 	Syntax *syntax,
3327 	struct berval *in )
3328 {
3329 	int	i;
3330 
3331 	assert( in != NULL );
3332 	assert( !BER_BVISNULL( in ) );
3333 
3334 	for ( i = 0; i < in->bv_len; i++ ) {
3335 		if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
3336 			return LDAP_INVALID_SYNTAX;
3337 		}
3338 	}
3339 
3340 	return LDAP_SUCCESS;
3341 }
3342 
3343 /* Normalize a SID as used inside a CSN:
3344  * three-digit numeric string */
3345 static int
3346 hexNormalize(
3347 	slap_mask_t usage,
3348 	Syntax *syntax,
3349 	MatchingRule *mr,
3350 	struct berval *val,
3351 	struct berval *normalized,
3352 	void *ctx )
3353 {
3354 	int	i;
3355 
3356 	assert( val != NULL );
3357 	assert( normalized != NULL );
3358 
3359 	ber_dupbv_x( normalized, val, ctx );
3360 
3361 	for ( i = 0; i < normalized->bv_len; i++ ) {
3362 		if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
3363 			ber_memfree_x( normalized->bv_val, ctx );
3364 			BER_BVZERO( normalized );
3365 			return LDAP_INVALID_SYNTAX;
3366 		}
3367 
3368 		normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3369 	}
3370 
3371 	return LDAP_SUCCESS;
3372 }
3373 
3374 static int
3375 sidValidate (
3376 	Syntax *syntax,
3377 	struct berval *in )
3378 {
3379 	assert( in != NULL );
3380 	assert( !BER_BVISNULL( in ) );
3381 
3382 	if ( in->bv_len != 3 ) {
3383 		return LDAP_INVALID_SYNTAX;
3384 	}
3385 
3386 	return hexValidate( NULL, in );
3387 }
3388 
3389 /* Normalize a SID as used inside a CSN:
3390  * three-digit numeric string */
3391 static int
3392 sidNormalize(
3393 	slap_mask_t usage,
3394 	Syntax *syntax,
3395 	MatchingRule *mr,
3396 	struct berval *val,
3397 	struct berval *normalized,
3398 	void *ctx )
3399 {
3400 	if ( val->bv_len != 3 ) {
3401 		return LDAP_INVALID_SYNTAX;
3402 	}
3403 
3404 	return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
3405 }
3406 
3407 static int
3408 sidPretty(
3409 	Syntax *syntax,
3410 	struct berval *val,
3411 	struct berval *out,
3412 	void *ctx )
3413 {
3414 	return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3415 }
3416 
3417 /* Normalize a SID as used inside a CSN, either as-is
3418  * (assertion value) or extracted from the CSN
3419  * (attribute value) */
3420 static int
3421 csnSidNormalize(
3422 	slap_mask_t usage,
3423 	Syntax *syntax,
3424 	MatchingRule *mr,
3425 	struct berval *val,
3426 	struct berval *normalized,
3427 	void *ctx )
3428 {
3429 	struct berval	bv;
3430 	char		*ptr,
3431 			buf[ 4 ];
3432 
3433 
3434 	if ( BER_BVISEMPTY( val ) ) {
3435 		return LDAP_INVALID_SYNTAX;
3436 	}
3437 
3438 	if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3439 		return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
3440 	}
3441 
3442 	assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3443 
3444 	ptr = ber_bvchr( val, '#' );
3445 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3446 		return LDAP_INVALID_SYNTAX;
3447 	}
3448 
3449 	bv.bv_val = ptr + 1;
3450 	bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3451 
3452 	ptr = ber_bvchr( &bv, '#' );
3453 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3454 		return LDAP_INVALID_SYNTAX;
3455 	}
3456 
3457 	bv.bv_val = ptr + 1;
3458 	bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3459 
3460 	ptr = ber_bvchr( &bv, '#' );
3461 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3462 		return LDAP_INVALID_SYNTAX;
3463 	}
3464 
3465 	bv.bv_len = ptr - bv.bv_val;
3466 
3467 	if ( bv.bv_len == 2 ) {
3468 		/* OpenLDAP 2.3 SID */
3469 		buf[ 0 ] = '0';
3470 		buf[ 1 ] = bv.bv_val[ 0 ];
3471 		buf[ 2 ] = bv.bv_val[ 1 ];
3472 		buf[ 3 ] = '\0';
3473 
3474 		bv.bv_val = buf;
3475 		bv.bv_len = 3;
3476 	}
3477 
3478 	return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
3479 }
3480 
3481 static int
3482 csnValidate(
3483 	Syntax *syntax,
3484 	struct berval *in )
3485 {
3486 	struct berval	bv;
3487 	char		*ptr;
3488 	int		rc;
3489 
3490 	assert( in != NULL );
3491 	assert( !BER_BVISNULL( in ) );
3492 
3493 	if ( BER_BVISEMPTY( in ) ) {
3494 		return LDAP_INVALID_SYNTAX;
3495 	}
3496 
3497 	bv = *in;
3498 
3499 	ptr = ber_bvchr( &bv, '#' );
3500 	if ( ptr == NULL || ptr - bv.bv_val == bv.bv_len ) {
3501 		return LDAP_INVALID_SYNTAX;
3502 	}
3503 
3504 	bv.bv_len = ptr - bv.bv_val;
3505 	if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
3506 		bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
3507 	{
3508 		return LDAP_INVALID_SYNTAX;
3509 	}
3510 
3511 	rc = generalizedTimeValidate( NULL, &bv );
3512 	if ( rc != LDAP_SUCCESS ) {
3513 		return rc;
3514 	}
3515 
3516 	bv.bv_val = ptr + 1;
3517 	bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3518 
3519 	ptr = ber_bvchr( &bv, '#' );
3520 	if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3521 		return LDAP_INVALID_SYNTAX;
3522 	}
3523 
3524 	bv.bv_len = ptr - bv.bv_val;
3525 	if ( bv.bv_len != 6 ) {
3526 		return LDAP_INVALID_SYNTAX;
3527 	}
3528 
3529 	rc = hexValidate( NULL, &bv );
3530 	if ( rc != LDAP_SUCCESS ) {
3531 		return rc;
3532 	}
3533 
3534 	bv.bv_val = ptr + 1;
3535 	bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3536 
3537 	ptr = ber_bvchr( &bv, '#' );
3538 	if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3539 		return LDAP_INVALID_SYNTAX;
3540 	}
3541 
3542 	bv.bv_len = ptr - bv.bv_val;
3543 	if ( bv.bv_len == 2 ) {
3544 		/* tolerate old 2-digit replica-id */
3545 		rc = hexValidate( NULL, &bv );
3546 
3547 	} else {
3548 		rc = sidValidate( NULL, &bv );
3549 	}
3550 	if ( rc != LDAP_SUCCESS ) {
3551 		return rc;
3552 	}
3553 
3554 	bv.bv_val = ptr + 1;
3555 	bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3556 
3557 	if ( bv.bv_len != 6 ) {
3558 		return LDAP_INVALID_SYNTAX;
3559 	}
3560 
3561 	return hexValidate( NULL, &bv );
3562 }
3563 
3564 /* Normalize a CSN in OpenLDAP 2.1 format */
3565 static int
3566 csnNormalize21(
3567 	slap_mask_t usage,
3568 	Syntax *syntax,
3569 	MatchingRule *mr,
3570 	struct berval *val,
3571 	struct berval *normalized,
3572 	void *ctx )
3573 {
3574 	struct berval	gt, cnt, sid, mod;
3575 	struct berval	bv;
3576 	char		buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
3577 	char		*ptr;
3578 	int		i;
3579 
3580 	assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3581 	assert( !BER_BVISEMPTY( val ) );
3582 
3583 	gt = *val;
3584 
3585 	ptr = ber_bvchr( &gt, '#' );
3586 	if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3587 		return LDAP_INVALID_SYNTAX;
3588 	}
3589 
3590 	gt.bv_len = ptr - gt.bv_val;
3591 	if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
3592 		return LDAP_INVALID_SYNTAX;
3593 	}
3594 
3595 	if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
3596 		return LDAP_INVALID_SYNTAX;
3597 	}
3598 
3599 	cnt.bv_val = ptr + 1;
3600 	cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3601 
3602 	ptr = ber_bvchr( &cnt, '#' );
3603 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3604 		return LDAP_INVALID_SYNTAX;
3605 	}
3606 
3607 	cnt.bv_len = ptr - cnt.bv_val;
3608 	if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
3609 		return LDAP_INVALID_SYNTAX;
3610 	}
3611 
3612 	if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
3613 		return LDAP_INVALID_SYNTAX;
3614 	}
3615 
3616 	cnt.bv_val += STRLENOF( "0x" );
3617 	cnt.bv_len -= STRLENOF( "0x" );
3618 
3619 	sid.bv_val = ptr + 1;
3620 	sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3621 
3622 	ptr = ber_bvchr( &sid, '#' );
3623 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3624 		return LDAP_INVALID_SYNTAX;
3625 	}
3626 
3627 	sid.bv_len = ptr - sid.bv_val;
3628 	if ( sid.bv_len != STRLENOF( "0" ) ) {
3629 		return LDAP_INVALID_SYNTAX;
3630 	}
3631 
3632 	mod.bv_val = ptr + 1;
3633 	mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3634 	if ( mod.bv_len != STRLENOF( "0000" ) ) {
3635 		return LDAP_INVALID_SYNTAX;
3636 	}
3637 
3638 	bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3639 	bv.bv_val = buf;
3640 
3641 	ptr = bv.bv_val;
3642 	ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
3643 	ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
3644 		STRLENOF( "MM" ) );
3645 	ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
3646 		STRLENOF( "SS" ) );
3647 	ptr = lutil_strcopy( ptr, ".000000Z#00" );
3648 	ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3649 	*ptr++ = '#';
3650 	*ptr++ = '0';
3651 	*ptr++ = '0';
3652 	*ptr++ = sid.bv_val[ 0 ];
3653 	*ptr++ = '#';
3654 	*ptr++ = '0';
3655 	*ptr++ = '0';
3656 	for ( i = 0; i < mod.bv_len; i++ ) {
3657 		*ptr++ = TOLOWER( mod.bv_val[ i ] );
3658 	}
3659 	*ptr = '\0';
3660 
3661 	assert( ptr - bv.bv_val == bv.bv_len );
3662 
3663 	if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
3664 		return LDAP_INVALID_SYNTAX;
3665 	}
3666 
3667 	ber_dupbv_x( normalized, &bv, ctx );
3668 
3669 	return LDAP_SUCCESS;
3670 }
3671 
3672 /* Normalize a CSN in OpenLDAP 2.3 format */
3673 static int
3674 csnNormalize23(
3675 	slap_mask_t usage,
3676 	Syntax *syntax,
3677 	MatchingRule *mr,
3678 	struct berval *val,
3679 	struct berval *normalized,
3680 	void *ctx )
3681 {
3682 	struct berval	gt, cnt, sid, mod;
3683 	struct berval	bv;
3684 	char		buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
3685 	char		*ptr;
3686 	int		i;
3687 
3688 	assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3689 	assert( !BER_BVISEMPTY( val ) );
3690 
3691 	gt = *val;
3692 
3693 	ptr = ber_bvchr( &gt, '#' );
3694 	if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3695 		return LDAP_INVALID_SYNTAX;
3696 	}
3697 
3698 	gt.bv_len = ptr - gt.bv_val;
3699 	if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3700 		return LDAP_INVALID_SYNTAX;
3701 	}
3702 
3703 	cnt.bv_val = ptr + 1;
3704 	cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3705 
3706 	ptr = ber_bvchr( &cnt, '#' );
3707 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3708 		return LDAP_INVALID_SYNTAX;
3709 	}
3710 
3711 	cnt.bv_len = ptr - cnt.bv_val;
3712 	if ( cnt.bv_len != STRLENOF( "000000" ) ) {
3713 		return LDAP_INVALID_SYNTAX;
3714 	}
3715 
3716 	sid.bv_val = ptr + 1;
3717 	sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3718 
3719 	ptr = ber_bvchr( &sid, '#' );
3720 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3721 		return LDAP_INVALID_SYNTAX;
3722 	}
3723 
3724 	sid.bv_len = ptr - sid.bv_val;
3725 	if ( sid.bv_len != STRLENOF( "00" ) ) {
3726 		return LDAP_INVALID_SYNTAX;
3727 	}
3728 
3729 	mod.bv_val = ptr + 1;
3730 	mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3731 	if ( mod.bv_len != STRLENOF( "000000" ) ) {
3732 		return LDAP_INVALID_SYNTAX;
3733 	}
3734 
3735 	bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3736 	bv.bv_val = buf;
3737 
3738 	ptr = bv.bv_val;
3739 	ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
3740 	ptr = lutil_strcopy( ptr, ".000000Z#" );
3741 	ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3742 	*ptr++ = '#';
3743 	*ptr++ = '0';
3744 	for ( i = 0; i < sid.bv_len; i++ ) {
3745 		*ptr++ = TOLOWER( sid.bv_val[ i ] );
3746 	}
3747 	*ptr++ = '#';
3748 	for ( i = 0; i < mod.bv_len; i++ ) {
3749 		*ptr++ = TOLOWER( mod.bv_val[ i ] );
3750 	}
3751 	*ptr = '\0';
3752 
3753 	assert( ptr - bv.bv_val == bv.bv_len );
3754 	if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
3755 		return LDAP_INVALID_SYNTAX;
3756 	}
3757 
3758 	ber_dupbv_x( normalized, &bv, ctx );
3759 
3760 	return LDAP_SUCCESS;
3761 }
3762 
3763 /* Normalize a CSN */
3764 static int
3765 csnNormalize(
3766 	slap_mask_t usage,
3767 	Syntax *syntax,
3768 	MatchingRule *mr,
3769 	struct berval *val,
3770 	struct berval *normalized,
3771 	void *ctx )
3772 {
3773 	struct berval	cnt, sid, mod;
3774 	char		*ptr;
3775 	int		i;
3776 
3777 	assert( val != NULL );
3778 	assert( normalized != NULL );
3779 
3780 	assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3781 
3782 	if ( BER_BVISEMPTY( val ) ) {
3783 		return LDAP_INVALID_SYNTAX;
3784 	}
3785 
3786 	if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
3787 		/* Openldap <= 2.3 */
3788 
3789 		return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
3790 	}
3791 
3792 	if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
3793 		/* Openldap 2.1 */
3794 
3795 		return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
3796 	}
3797 
3798 	if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
3799 		return LDAP_INVALID_SYNTAX;
3800 	}
3801 
3802 	ptr = ber_bvchr( val, '#' );
3803 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3804 		return LDAP_INVALID_SYNTAX;
3805 	}
3806 
3807 	if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
3808 		return LDAP_INVALID_SYNTAX;
3809 	}
3810 
3811 	cnt.bv_val = ptr + 1;
3812 	cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3813 
3814 	ptr = ber_bvchr( &cnt, '#' );
3815 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3816 		return LDAP_INVALID_SYNTAX;
3817 	}
3818 
3819 	if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
3820 		return LDAP_INVALID_SYNTAX;
3821 	}
3822 
3823 	sid.bv_val = ptr + 1;
3824 	sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3825 
3826 	ptr = ber_bvchr( &sid, '#' );
3827 	if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3828 		return LDAP_INVALID_SYNTAX;
3829 	}
3830 
3831 	sid.bv_len = ptr - sid.bv_val;
3832 	if ( sid.bv_len != STRLENOF( "000" ) ) {
3833 		return LDAP_INVALID_SYNTAX;
3834 	}
3835 
3836 	mod.bv_val = ptr + 1;
3837 	mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3838 
3839 	if ( mod.bv_len != STRLENOF( "000000" ) ) {
3840 		return LDAP_INVALID_SYNTAX;
3841 	}
3842 
3843 	ber_dupbv_x( normalized, val, ctx );
3844 
3845 	for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
3846 		i < normalized->bv_len; i++ )
3847 	{
3848 		/* assume it's already validated that's all hex digits */
3849 		normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3850 	}
3851 
3852 	return LDAP_SUCCESS;
3853 }
3854 
3855 static int
3856 csnPretty(
3857 	Syntax *syntax,
3858 	struct berval *val,
3859 	struct berval *out,
3860 	void *ctx )
3861 {
3862 	return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3863 }
3864 
3865 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3866 /* slight optimization - does not need the start parameter */
3867 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3868 enum { start = 0 };
3869 #endif
3870 
3871 static int
3872 check_time_syntax (struct berval *val,
3873 	int start,
3874 	int *parts,
3875 	struct berval *fraction)
3876 {
3877 	/*
3878 	 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3879 	 * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
3880 	 * GeneralizedTime supports leap seconds, UTCTime does not.
3881 	 */
3882 	static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3883 	static const int mdays[2][12] = {
3884 		/* non-leap years */
3885 		{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3886 		/* leap years */
3887 		{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3888 	};
3889 	char *p, *e;
3890 	int part, c, c1, c2, tzoffset, leapyear = 0;
3891 
3892 	p = val->bv_val;
3893 	e = p + val->bv_len;
3894 
3895 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3896 	parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3897 #endif
3898 	for (part = start; part < 7 && p < e; part++) {
3899 		c1 = *p;
3900 		if (!ASCII_DIGIT(c1)) {
3901 			break;
3902 		}
3903 		p++;
3904 		if (p == e) {
3905 			return LDAP_INVALID_SYNTAX;
3906 		}
3907 		c = *p++;
3908 		if (!ASCII_DIGIT(c)) {
3909 			return LDAP_INVALID_SYNTAX;
3910 		}
3911 		c += c1 * 10 - '0' * 11;
3912 		if ((part | 1) == 3) {
3913 			--c;
3914 			if (c < 0) {
3915 				return LDAP_INVALID_SYNTAX;
3916 			}
3917 		}
3918 		if (c >= ceiling[part]) {
3919 			if (! (c == 60 && part == 6 && start == 0))
3920 				return LDAP_INVALID_SYNTAX;
3921 		}
3922 		parts[part] = c;
3923 	}
3924 	if (part < 5 + start) {
3925 		return LDAP_INVALID_SYNTAX;
3926 	}
3927 	for (; part < 9; part++) {
3928 		parts[part] = 0;
3929 	}
3930 
3931 	/* leapyear check for the Gregorian calendar (year>1581) */
3932 	if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3933 		leapyear = 1;
3934 	}
3935 
3936 	if (parts[3] >= mdays[leapyear][parts[2]]) {
3937 		return LDAP_INVALID_SYNTAX;
3938 	}
3939 
3940 	if (start == 0) {
3941 		fraction->bv_val = p;
3942 		fraction->bv_len = 0;
3943 		if (p < e && (*p == '.' || *p == ',')) {
3944 			char *end_num;
3945 			while (++p < e && ASCII_DIGIT(*p)) {
3946 				/* EMTPY */;
3947 			}
3948 			if (p - fraction->bv_val == 1) {
3949 				return LDAP_INVALID_SYNTAX;
3950 			}
3951 			for (end_num = p; end_num[-1] == '0'; --end_num) {
3952 				/* EMPTY */;
3953 			}
3954 			c = end_num - fraction->bv_val;
3955 			if (c != 1) fraction->bv_len = c;
3956 		}
3957 	}
3958 
3959 	if (p == e) {
3960 		/* no time zone */
3961 		return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3962 	}
3963 
3964 	tzoffset = *p++;
3965 	switch (tzoffset) {
3966 	default:
3967 		return LDAP_INVALID_SYNTAX;
3968 	case 'Z':
3969 		/* UTC */
3970 		break;
3971 	case '+':
3972 	case '-':
3973 		for (part = 7; part < 9 && p < e; part++) {
3974 			c1 = *p;
3975 			if (!ASCII_DIGIT(c1)) {
3976 				break;
3977 			}
3978 			p++;
3979 			if (p == e) {
3980 				return LDAP_INVALID_SYNTAX;
3981 			}
3982 			c2 = *p++;
3983 			if (!ASCII_DIGIT(c2)) {
3984 				return LDAP_INVALID_SYNTAX;
3985 			}
3986 			parts[part] = c1 * 10 + c2 - '0' * 11;
3987 			if (parts[part] >= ceiling[part]) {
3988 				return LDAP_INVALID_SYNTAX;
3989 			}
3990 		}
3991 		if (part < 8 + start) {
3992 			return LDAP_INVALID_SYNTAX;
3993 		}
3994 
3995 		if (tzoffset == '-') {
3996 			/* negative offset to UTC, ie west of Greenwich */
3997 			parts[4] += parts[7];
3998 			parts[5] += parts[8];
3999 			/* offset is just hhmm, no seconds */
4000 			for (part = 6; --part >= 0; ) {
4001 				if (part != 3) {
4002 					c = ceiling[part];
4003 				} else {
4004 					c = mdays[leapyear][parts[2]];
4005 				}
4006 				if (parts[part] >= c) {
4007 					if (part == 0) {
4008 						return LDAP_INVALID_SYNTAX;
4009 					}
4010 					parts[part] -= c;
4011 					parts[part - 1]++;
4012 					continue;
4013 				} else if (part != 5) {
4014 					break;
4015 				}
4016 			}
4017 		} else {
4018 			/* positive offset to UTC, ie east of Greenwich */
4019 			parts[4] -= parts[7];
4020 			parts[5] -= parts[8];
4021 			for (part = 6; --part >= 0; ) {
4022 				if (parts[part] < 0) {
4023 					if (part == 0) {
4024 						return LDAP_INVALID_SYNTAX;
4025 					}
4026 					if (part != 3) {
4027 						c = ceiling[part];
4028 					} else {
4029 						/* make first arg to % non-negative */
4030 						c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
4031 					}
4032 					parts[part] += c;
4033 					parts[part - 1]--;
4034 					continue;
4035 				} else if (part != 5) {
4036 					break;
4037 				}
4038 			}
4039 		}
4040 	}
4041 
4042 	return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
4043 }
4044 
4045 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4046 
4047 #if 0
4048 static int
4049 xutcTimeNormalize(
4050 	Syntax *syntax,
4051 	struct berval *val,
4052 	struct berval *normalized )
4053 {
4054 	int parts[9], rc;
4055 
4056 	rc = check_time_syntax(val, 1, parts, NULL);
4057 	if (rc != LDAP_SUCCESS) {
4058 		return rc;
4059 	}
4060 
4061 	normalized->bv_val = ch_malloc( 14 );
4062 	if ( normalized->bv_val == NULL ) {
4063 		return LBER_ERROR_MEMORY;
4064 	}
4065 
4066 	sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
4067 		parts[1], parts[2] + 1, parts[3] + 1,
4068 		parts[4], parts[5], parts[6] );
4069 	normalized->bv_len = 13;
4070 
4071 	return LDAP_SUCCESS;
4072 }
4073 #endif /* 0 */
4074 
4075 static int
4076 utcTimeValidate(
4077 	Syntax *syntax,
4078 	struct berval *in )
4079 {
4080 	int parts[9];
4081 	return check_time_syntax(in, 1, parts, NULL);
4082 }
4083 
4084 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
4085 
4086 static int
4087 generalizedTimeValidate(
4088 	Syntax *syntax,
4089 	struct berval *in )
4090 {
4091 	int parts[9];
4092 	struct berval fraction;
4093 	return check_time_syntax(in, 0, parts, &fraction);
4094 }
4095 
4096 static int
4097 generalizedTimeNormalize(
4098 	slap_mask_t usage,
4099 	Syntax *syntax,
4100 	MatchingRule *mr,
4101 	struct berval *val,
4102 	struct berval *normalized,
4103 	void *ctx )
4104 {
4105 	int parts[9], rc;
4106 	unsigned int len;
4107 	struct berval fraction;
4108 
4109 	rc = check_time_syntax(val, 0, parts, &fraction);
4110 	if (rc != LDAP_SUCCESS) {
4111 		return rc;
4112 	}
4113 
4114 	len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
4115 	normalized->bv_val = slap_sl_malloc( len + 1, ctx );
4116 	if ( BER_BVISNULL( normalized ) ) {
4117 		return LBER_ERROR_MEMORY;
4118 	}
4119 
4120 	sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
4121 		parts[0], parts[1], parts[2] + 1, parts[3] + 1,
4122 		parts[4], parts[5], parts[6] );
4123 	if ( !BER_BVISEMPTY( &fraction ) ) {
4124 		memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
4125 			fraction.bv_val, fraction.bv_len );
4126 		normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
4127 	}
4128 	strcpy( normalized->bv_val + len-1, "Z" );
4129 	normalized->bv_len = len;
4130 
4131 	return LDAP_SUCCESS;
4132 }
4133 
4134 static int
4135 generalizedTimeOrderingMatch(
4136 	int *matchp,
4137 	slap_mask_t flags,
4138 	Syntax *syntax,
4139 	MatchingRule *mr,
4140 	struct berval *value,
4141 	void *assertedValue )
4142 {
4143 	struct berval *asserted = (struct berval *) assertedValue;
4144 	ber_len_t v_len  = value->bv_len;
4145 	ber_len_t av_len = asserted->bv_len;
4146 
4147 	/* ignore trailing 'Z' when comparing */
4148 	int match = memcmp( value->bv_val, asserted->bv_val,
4149 		(v_len < av_len ? v_len : av_len) - 1 );
4150 	if ( match == 0 ) match = v_len - av_len;
4151 
4152 	*matchp = match;
4153 	return LDAP_SUCCESS;
4154 }
4155 
4156 /* Index generation function */
4157 int generalizedTimeIndexer(
4158 	slap_mask_t use,
4159 	slap_mask_t flags,
4160 	Syntax *syntax,
4161 	MatchingRule *mr,
4162 	struct berval *prefix,
4163 	BerVarray values,
4164 	BerVarray *keysp,
4165 	void *ctx )
4166 {
4167 	int i, j;
4168 	BerVarray keys;
4169 	char tmp[5];
4170 	BerValue bvtmp; /* 40 bit index */
4171 	struct lutil_tm tm;
4172 	struct lutil_timet tt;
4173 
4174 	bvtmp.bv_len = sizeof(tmp);
4175 	bvtmp.bv_val = tmp;
4176 	for( i=0; values[i].bv_val != NULL; i++ ) {
4177 		/* just count them */
4178 	}
4179 
4180 	/* we should have at least one value at this point */
4181 	assert( i > 0 );
4182 
4183 	keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
4184 
4185 	/* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4186 	for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
4187 		assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
4188 		/* Use 40 bits of time for key */
4189 		if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
4190 			lutil_tm2time( &tm, &tt );
4191 			tmp[0] = tt.tt_gsec & 0xff;
4192 			tmp[4] = tt.tt_sec & 0xff;
4193 			tt.tt_sec >>= 8;
4194 			tmp[3] = tt.tt_sec & 0xff;
4195 			tt.tt_sec >>= 8;
4196 			tmp[2] = tt.tt_sec & 0xff;
4197 			tt.tt_sec >>= 8;
4198 			tmp[1] = tt.tt_sec & 0xff;
4199 
4200 			ber_dupbv_x(&keys[j++], &bvtmp, ctx );
4201 		}
4202 	}
4203 
4204 	keys[j].bv_val = NULL;
4205 	keys[j].bv_len = 0;
4206 
4207 	*keysp = keys;
4208 
4209 	return LDAP_SUCCESS;
4210 }
4211 
4212 /* Index generation function */
4213 int generalizedTimeFilter(
4214 	slap_mask_t use,
4215 	slap_mask_t flags,
4216 	Syntax *syntax,
4217 	MatchingRule *mr,
4218 	struct berval *prefix,
4219 	void * assertedValue,
4220 	BerVarray *keysp,
4221 	void *ctx )
4222 {
4223 	BerVarray keys;
4224 	char tmp[5];
4225 	BerValue bvtmp; /* 40 bit index */
4226 	BerValue *value = (BerValue *) assertedValue;
4227 	struct lutil_tm tm;
4228 	struct lutil_timet tt;
4229 
4230 	bvtmp.bv_len = sizeof(tmp);
4231 	bvtmp.bv_val = tmp;
4232 	/* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4233 	/* Use 40 bits of time for key */
4234 	if ( value->bv_val && value->bv_len >= 10 &&
4235 		lutil_parsetime( value->bv_val, &tm ) == 0 ) {
4236 
4237 		lutil_tm2time( &tm, &tt );
4238 		tmp[0] = tt.tt_gsec & 0xff;
4239 		tmp[4] = tt.tt_sec & 0xff;
4240 		tt.tt_sec >>= 8;
4241 		tmp[3] = tt.tt_sec & 0xff;
4242 		tt.tt_sec >>= 8;
4243 		tmp[2] = tt.tt_sec & 0xff;
4244 		tt.tt_sec >>= 8;
4245 		tmp[1] = tt.tt_sec & 0xff;
4246 
4247 		keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
4248 		ber_dupbv_x(keys, &bvtmp, ctx );
4249 		keys[1].bv_val = NULL;
4250 		keys[1].bv_len = 0;
4251 	} else {
4252 		keys = NULL;
4253 	}
4254 
4255 	*keysp = keys;
4256 
4257 	return LDAP_SUCCESS;
4258 }
4259 
4260 static int
4261 deliveryMethodValidate(
4262 	Syntax *syntax,
4263 	struct berval *val )
4264 {
4265 #undef LENOF
4266 #define LENOF(s) (sizeof(s)-1)
4267 	struct berval tmp = *val;
4268 	/*
4269      *	DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
4270 	 *	pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
4271 	 *		"g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
4272 	 */
4273 again:
4274 	if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4275 
4276 	switch( tmp.bv_val[0] ) {
4277 	case 'a':
4278 	case 'A':
4279 		if(( tmp.bv_len >= LENOF("any") ) &&
4280 			( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
4281 		{
4282 			tmp.bv_len -= LENOF("any");
4283 			tmp.bv_val += LENOF("any");
4284 			break;
4285 		}
4286 		return LDAP_INVALID_SYNTAX;
4287 
4288 	case 'm':
4289 	case 'M':
4290 		if(( tmp.bv_len >= LENOF("mhs") ) &&
4291 			( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
4292 		{
4293 			tmp.bv_len -= LENOF("mhs");
4294 			tmp.bv_val += LENOF("mhs");
4295 			break;
4296 		}
4297 		return LDAP_INVALID_SYNTAX;
4298 
4299 	case 'p':
4300 	case 'P':
4301 		if(( tmp.bv_len >= LENOF("physical") ) &&
4302 			( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
4303 		{
4304 			tmp.bv_len -= LENOF("physical");
4305 			tmp.bv_val += LENOF("physical");
4306 			break;
4307 		}
4308 		return LDAP_INVALID_SYNTAX;
4309 
4310 	case 't':
4311 	case 'T': /* telex or teletex or telephone */
4312 		if(( tmp.bv_len >= LENOF("telex") ) &&
4313 			( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
4314 		{
4315 			tmp.bv_len -= LENOF("telex");
4316 			tmp.bv_val += LENOF("telex");
4317 			break;
4318 		}
4319 		if(( tmp.bv_len >= LENOF("teletex") ) &&
4320 			( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
4321 		{
4322 			tmp.bv_len -= LENOF("teletex");
4323 			tmp.bv_val += LENOF("teletex");
4324 			break;
4325 		}
4326 		if(( tmp.bv_len >= LENOF("telephone") ) &&
4327 			( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
4328 		{
4329 			tmp.bv_len -= LENOF("telephone");
4330 			tmp.bv_val += LENOF("telephone");
4331 			break;
4332 		}
4333 		return LDAP_INVALID_SYNTAX;
4334 
4335 	case 'g':
4336 	case 'G': /* g3fax or g4fax */
4337 		if(( tmp.bv_len >= LENOF("g3fax") ) && (
4338 			( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
4339 			( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
4340 		{
4341 			tmp.bv_len -= LENOF("g3fax");
4342 			tmp.bv_val += LENOF("g3fax");
4343 			break;
4344 		}
4345 		return LDAP_INVALID_SYNTAX;
4346 
4347 	case 'i':
4348 	case 'I':
4349 		if(( tmp.bv_len >= LENOF("ia5") ) &&
4350 			( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
4351 		{
4352 			tmp.bv_len -= LENOF("ia5");
4353 			tmp.bv_val += LENOF("ia5");
4354 			break;
4355 		}
4356 		return LDAP_INVALID_SYNTAX;
4357 
4358 	case 'v':
4359 	case 'V':
4360 		if(( tmp.bv_len >= LENOF("videotex") ) &&
4361 			( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
4362 		{
4363 			tmp.bv_len -= LENOF("videotex");
4364 			tmp.bv_val += LENOF("videotex");
4365 			break;
4366 		}
4367 		return LDAP_INVALID_SYNTAX;
4368 
4369 	default:
4370 		return LDAP_INVALID_SYNTAX;
4371 	}
4372 
4373 	if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
4374 
4375 	while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4376 		tmp.bv_len++;
4377 		tmp.bv_val--;
4378 	}
4379 	if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
4380 		tmp.bv_len++;
4381 		tmp.bv_val--;
4382 	} else {
4383 		return LDAP_INVALID_SYNTAX;
4384 	}
4385 	while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4386 		tmp.bv_len++;
4387 		tmp.bv_val--;
4388 	}
4389 
4390 	goto again;
4391 }
4392 
4393 static int
4394 nisNetgroupTripleValidate(
4395 	Syntax *syntax,
4396 	struct berval *val )
4397 {
4398 	char *p, *e;
4399 	int commas = 0;
4400 
4401 	if ( BER_BVISEMPTY( val ) ) {
4402 		return LDAP_INVALID_SYNTAX;
4403 	}
4404 
4405 	p = (char *)val->bv_val;
4406 	e = p + val->bv_len;
4407 
4408 	if ( *p != '(' /*')'*/ ) {
4409 		return LDAP_INVALID_SYNTAX;
4410 	}
4411 
4412 	for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
4413 		if ( *p == ',' ) {
4414 			commas++;
4415 			if ( commas > 2 ) {
4416 				return LDAP_INVALID_SYNTAX;
4417 			}
4418 
4419 		} else if ( !AD_CHAR( *p ) ) {
4420 			return LDAP_INVALID_SYNTAX;
4421 		}
4422 	}
4423 
4424 	if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4425 		return LDAP_INVALID_SYNTAX;
4426 	}
4427 
4428 	p++;
4429 
4430 	if (p != e) {
4431 		return LDAP_INVALID_SYNTAX;
4432 	}
4433 
4434 	return LDAP_SUCCESS;
4435 }
4436 
4437 static int
4438 bootParameterValidate(
4439 	Syntax *syntax,
4440 	struct berval *val )
4441 {
4442 	char *p, *e;
4443 
4444 	if ( BER_BVISEMPTY( val ) ) {
4445 		return LDAP_INVALID_SYNTAX;
4446 	}
4447 
4448 	p = (char *)val->bv_val;
4449 	e = p + val->bv_len;
4450 
4451 	/* key */
4452 	for (; ( p < e ) && ( *p != '=' ); p++ ) {
4453 		if ( !AD_CHAR( *p ) ) {
4454 			return LDAP_INVALID_SYNTAX;
4455 		}
4456 	}
4457 
4458 	if ( *p != '=' ) {
4459 		return LDAP_INVALID_SYNTAX;
4460 	}
4461 
4462 	/* server */
4463 	for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4464 		if ( !AD_CHAR( *p ) ) {
4465 			return LDAP_INVALID_SYNTAX;
4466 		}
4467 	}
4468 
4469 	if ( *p != ':' ) {
4470 		return LDAP_INVALID_SYNTAX;
4471 	}
4472 
4473 	/* path */
4474 	for ( p++; p < e; p++ ) {
4475 		if ( !SLAP_PRINTABLE( *p ) ) {
4476 			return LDAP_INVALID_SYNTAX;
4477 		}
4478 	}
4479 
4480 	return LDAP_SUCCESS;
4481 }
4482 
4483 static int
4484 firstComponentNormalize(
4485 	slap_mask_t usage,
4486 	Syntax *syntax,
4487 	MatchingRule *mr,
4488 	struct berval *val,
4489 	struct berval *normalized,
4490 	void *ctx )
4491 {
4492 	int rc;
4493 	struct berval comp;
4494 	ber_len_t len;
4495 
4496 	if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
4497 		ber_dupbv_x( normalized, val, ctx );
4498 		return LDAP_SUCCESS;
4499 	}
4500 
4501 	if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4502 
4503 	if( val->bv_val[0] != '(' /*')'*/ &&
4504 		val->bv_val[0] != '{' /*'}'*/ )
4505 	{
4506 		return LDAP_INVALID_SYNTAX;
4507 	}
4508 
4509 	/* trim leading white space */
4510 	for( len=1;
4511 		len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
4512 		len++ )
4513 	{
4514 		/* empty */
4515 	}
4516 
4517 	/* grab next word */
4518 	comp.bv_val = &val->bv_val[len];
4519 	len = val->bv_len - len;
4520 	for( comp.bv_len = 0;
4521 		!ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
4522 		comp.bv_len++ )
4523 	{
4524 		/* empty */
4525 	}
4526 
4527 	if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
4528 		rc = numericoidValidate( NULL, &comp );
4529 	} else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
4530 		rc = integerValidate( NULL, &comp );
4531 	} else {
4532 		rc = LDAP_INVALID_SYNTAX;
4533 	}
4534 
4535 
4536 	if( rc == LDAP_SUCCESS ) {
4537 		ber_dupbv_x( normalized, &comp, ctx );
4538 	}
4539 
4540 	return rc;
4541 }
4542 
4543 static char *country_gen_syn[] = {
4544 	"1.3.6.1.4.1.1466.115.121.1.15",
4545 	"1.3.6.1.4.1.1466.115.121.1.26",
4546 	"1.3.6.1.4.1.1466.115.121.1.44",
4547 	NULL
4548 };
4549 
4550 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4551 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4552 
4553 static slap_syntax_defs_rec syntax_defs[] = {
4554 	{"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4555 		X_BINARY X_NOT_H_R ")",
4556 		SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4557 	{"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4558 		0, NULL, NULL, NULL},
4559 	{"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4560 		0, NULL, NULL, NULL},
4561 	{"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4562 		X_NOT_H_R ")",
4563 		SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4564 	{"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4565 		X_NOT_H_R ")",
4566 		SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4567 	{"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4568 		0, NULL, bitStringValidate, NULL },
4569 	{"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4570 		0, NULL, booleanValidate, NULL},
4571 	{"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4572 		X_BINARY X_NOT_H_R ")",
4573 		SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4574 		NULL, certificateValidate, NULL},
4575 	{"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4576 		X_BINARY X_NOT_H_R ")",
4577 		SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4578 		NULL, certificateListValidate, NULL},
4579 	{"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4580 		X_BINARY X_NOT_H_R ")",
4581 		SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4582 		NULL, sequenceValidate, NULL},
4583 #if 0	/* need to go __after__ printableString */
4584 	{"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4585 		0, "1.3.6.1.4.1.1466.115.121.1.44",
4586 		countryStringValidate, NULL},
4587 #endif
4588 	{"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4589 		0, NULL, dnValidate, dnPretty},
4590 	{"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4591 		0, NULL, rdnValidate, rdnPretty},
4592 #ifdef LDAP_COMP_MATCH
4593 	{"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4594 		0, NULL, allComponentsValidate, NULL},
4595  	{"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4596 		0, NULL, componentFilterValidate, NULL},
4597 #endif
4598 	{"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4599 		0, NULL, NULL, NULL},
4600 	{"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4601 		0, NULL, deliveryMethodValidate, NULL},
4602 	{"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4603 		0, NULL, UTF8StringValidate, NULL},
4604 	{"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4605 		0, NULL, NULL, NULL},
4606 	{"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4607 		0, NULL, NULL, NULL},
4608 	{"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4609 		0, NULL, NULL, NULL},
4610 	{"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4611 		0, NULL, NULL, NULL},
4612 	{"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4613 		0, NULL, NULL, NULL},
4614 	{"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4615 		0, NULL, printablesStringValidate, NULL},
4616 	{"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4617 		SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4618 	{"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4619 		0, NULL, generalizedTimeValidate, NULL},
4620 	{"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4621 		0, NULL, NULL, NULL},
4622 	{"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4623 		0, NULL, IA5StringValidate, NULL},
4624 	{"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4625 		0, NULL, integerValidate, NULL},
4626 	{"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4627 		SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4628 	{"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4629 		0, NULL, NULL, NULL},
4630 	{"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4631 		0, NULL, NULL, NULL},
4632 	{"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4633 		0, NULL, NULL, NULL},
4634 	{"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4635 		0, NULL, NULL, NULL},
4636 	{"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4637 		0, NULL, NULL, NULL},
4638 	{"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4639 		0, NULL, nameUIDValidate, nameUIDPretty },
4640 	{"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4641 		0, NULL, NULL, NULL},
4642 	{"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4643 		0, NULL, numericStringValidate, NULL},
4644 	{"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4645 		0, NULL, NULL, NULL},
4646 	{"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4647 		0, NULL, numericoidValidate, NULL},
4648 	{"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4649 		0, NULL, IA5StringValidate, NULL},
4650 	{"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4651 		0, NULL, blobValidate, NULL},
4652 	{"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4653 		0, NULL, UTF8StringValidate, NULL},
4654 	{"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4655 		0, NULL, NULL, NULL},
4656 	{"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4657 		0, NULL, NULL, NULL},
4658 	{"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4659 		0, NULL, printableStringValidate, NULL},
4660 	/* moved here because now depends on Directory String, IA5 String
4661 	 * and Printable String */
4662 	{"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4663 		0, country_gen_syn, countryStringValidate, NULL},
4664 	{"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4665 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4666 		0, NULL, subtreeSpecificationValidate, NULL},
4667 	{"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4668 		X_BINARY X_NOT_H_R ")",
4669 		SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4670 	{"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4671 		0, NULL, printableStringValidate, NULL},
4672 	{"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4673 		0, NULL, NULL, NULL},
4674 	{"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4675 		0, NULL, printablesStringValidate, NULL},
4676 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4677 	{"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4678 		0, NULL, utcTimeValidate, NULL},
4679 #endif
4680 	{"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4681 		0, NULL, NULL, NULL},
4682 	{"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4683 		0, NULL, NULL, NULL},
4684 	{"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4685 		0, NULL, NULL, NULL},
4686 	{"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4687 		0, NULL, NULL, NULL},
4688 	{"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4689 		0, NULL, NULL, NULL},
4690 
4691 	/* RFC 2307 NIS Syntaxes */
4692 	{"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4693 		0, NULL, nisNetgroupTripleValidate, NULL},
4694 	{"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4695 		0, NULL, bootParameterValidate, NULL},
4696 
4697 	/* draft-zeilenga-ldap-x509 */
4698 	{"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4699 		SLAP_SYNTAX_HIDE, NULL,
4700 		serialNumberAndIssuerValidate,
4701 		serialNumberAndIssuerPretty},
4702 	{"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4703 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4704 	{"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4705 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4706 	{"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4707 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4708 	{"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4709 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4710 	{"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4711 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4712 	{"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4713 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4714 
4715 #ifdef SLAPD_AUTHPASSWD
4716 	/* needs updating */
4717 	{"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4718 		SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4719 #endif
4720 
4721 	{"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4722 		0, NULL, UUIDValidate, UUIDPretty},
4723 
4724 	{"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4725 		SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
4726 
4727 	{"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
4728 		SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
4729 
4730 	/* OpenLDAP Void Syntax */
4731 	{"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4732 		SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
4733 
4734 	/* FIXME: OID is unused, but not registered yet */
4735 	{"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4736 		SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
4737 
4738 	{NULL, 0, NULL, NULL, NULL}
4739 };
4740 
4741 char *csnSIDMatchSyntaxes[] = {
4742 	"1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
4743 	NULL
4744 };
4745 char *certificateExactMatchSyntaxes[] = {
4746 	"1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4747 	NULL
4748 };
4749 #ifdef LDAP_COMP_MATCH
4750 char *componentFilterMatchSyntaxes[] = {
4751 	"1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4752 	NULL
4753 };
4754 #endif
4755 char *directoryStringSyntaxes[] = {
4756 	"1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4757 	NULL
4758 };
4759 char *integerFirstComponentMatchSyntaxes[] = {
4760 	"1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4761 	"1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4762 	NULL
4763 };
4764 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4765 	"1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4766 	"1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
4767 	"1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4768 	"1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4769 	"1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4770 	"1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4771 	"1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4772 	"1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4773 	NULL
4774 };
4775 
4776 /*
4777  * Other matching rules in X.520 that we do not use (yet):
4778  *
4779  * 2.5.13.25	uTCTimeMatch
4780  * 2.5.13.26	uTCTimeOrderingMatch
4781  * 2.5.13.31*	directoryStringFirstComponentMatch
4782  * 2.5.13.32*	wordMatch
4783  * 2.5.13.33*	keywordMatch
4784  * 2.5.13.36+	certificatePairExactMatch
4785  * 2.5.13.37+	certificatePairMatch
4786  * 2.5.13.38+	certificateListExactMatch
4787  * 2.5.13.39+	certificateListMatch
4788  * 2.5.13.40+	algorithmIdentifierMatch
4789  * 2.5.13.41*	storedPrefixMatch
4790  * 2.5.13.42	attributeCertificateMatch
4791  * 2.5.13.43	readerAndKeyIDMatch
4792  * 2.5.13.44	attributeIntegrityMatch
4793  *
4794  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4795  * (+) described in draft-zeilenga-ldap-x509
4796  */
4797 static slap_mrule_defs_rec mrule_defs[] = {
4798 	/*
4799 	 * EQUALITY matching rules must be listed after associated APPROX
4800 	 * matching rules.  So, we list all APPROX matching rules first.
4801 	 */
4802 	{"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4803 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4804 		SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4805 		NULL, NULL, directoryStringApproxMatch,
4806 		directoryStringApproxIndexer, directoryStringApproxFilter,
4807 		NULL},
4808 
4809 	{"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4810 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4811 		SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4812 		NULL, NULL, IA5StringApproxMatch,
4813 		IA5StringApproxIndexer, IA5StringApproxFilter,
4814 		NULL},
4815 
4816 	/*
4817 	 * Other matching rules
4818 	 */
4819 
4820 	{"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4821 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4822 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4823 		NULL, NULL, octetStringMatch,
4824 		octetStringIndexer, octetStringFilter,
4825 		NULL },
4826 
4827 	{"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4828 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4829 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4830 		NULL, dnNormalize, dnMatch,
4831 		octetStringIndexer, octetStringFilter,
4832 		NULL },
4833 
4834 	{"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4835 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4836 		SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4837 		NULL, dnNormalize, dnRelativeMatch,
4838 		NULL, NULL,
4839 		NULL },
4840 
4841 	{"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4842 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4843 		SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4844 		NULL, dnNormalize, dnRelativeMatch,
4845 		NULL, NULL,
4846 		NULL },
4847 
4848 	{"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4849 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4850 		SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4851 		NULL, dnNormalize, dnRelativeMatch,
4852 		NULL, NULL,
4853 		NULL },
4854 
4855 	{"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4856 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4857 		SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4858 		NULL, dnNormalize, dnRelativeMatch,
4859 		NULL, NULL,
4860 		NULL },
4861 
4862 	{"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4863 		"SYNTAX 1.2.36.79672281.1.5.0 )",
4864 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4865 		NULL, rdnNormalize, rdnMatch,
4866 		octetStringIndexer, octetStringFilter,
4867 		NULL },
4868 
4869 #ifdef LDAP_COMP_MATCH
4870 	{"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4871 		"SYNTAX 1.2.36.79672281.1.5.2 )",
4872 		SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4873 		NULL, NULL , componentFilterMatch,
4874 		octetStringIndexer, octetStringFilter,
4875 		NULL },
4876 
4877         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4878                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4879                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4880                 NULL, NULL , allComponentsMatch,
4881                 octetStringIndexer, octetStringFilter,
4882                 NULL },
4883 
4884         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4885                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4886                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4887                 NULL, NULL , directoryComponentsMatch,
4888                 octetStringIndexer, octetStringFilter,
4889                 NULL },
4890 #endif
4891 
4892 	{"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4893 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4894 		SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4895 		NULL, UTF8StringNormalize, octetStringMatch,
4896 		octetStringIndexer, octetStringFilter,
4897 		directoryStringApproxMatchOID },
4898 
4899 	{"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4900 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4901 		SLAP_MR_ORDERING, directoryStringSyntaxes,
4902 		NULL, UTF8StringNormalize, octetStringOrderingMatch,
4903 		NULL, NULL,
4904 		"caseIgnoreMatch" },
4905 
4906 	{"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4907 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4908 		SLAP_MR_SUBSTR, directoryStringSyntaxes,
4909 		NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4910 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
4911 		"caseIgnoreMatch" },
4912 
4913 	{"( 2.5.13.5 NAME 'caseExactMatch' "
4914 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4915 		SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4916 		NULL, UTF8StringNormalize, octetStringMatch,
4917 		octetStringIndexer, octetStringFilter,
4918 		directoryStringApproxMatchOID },
4919 
4920 	{"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4921 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4922 		SLAP_MR_ORDERING, directoryStringSyntaxes,
4923 		NULL, UTF8StringNormalize, octetStringOrderingMatch,
4924 		NULL, NULL,
4925 		"caseExactMatch" },
4926 
4927 	{"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4928 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4929 		SLAP_MR_SUBSTR, directoryStringSyntaxes,
4930 		NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4931 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
4932 		"caseExactMatch" },
4933 
4934 	{"( 2.5.13.8 NAME 'numericStringMatch' "
4935 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4936 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4937 		NULL, numericStringNormalize, octetStringMatch,
4938 		octetStringIndexer, octetStringFilter,
4939 		NULL },
4940 
4941 	{"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4942 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4943 		SLAP_MR_ORDERING, NULL,
4944 		NULL, numericStringNormalize, octetStringOrderingMatch,
4945 		NULL, NULL,
4946 		"numericStringMatch" },
4947 
4948 	{"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4949 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4950 		SLAP_MR_SUBSTR, NULL,
4951 		NULL, numericStringNormalize, octetStringSubstringsMatch,
4952 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
4953 		"numericStringMatch" },
4954 
4955 	{"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4956 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4957 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4958 		NULL, NULL, NULL, NULL, NULL, NULL },
4959 
4960 	{"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4961 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4962 		SLAP_MR_SUBSTR, NULL,
4963 		NULL, NULL, NULL, NULL, NULL,
4964 		"caseIgnoreListMatch" },
4965 
4966 	{"( 2.5.13.13 NAME 'booleanMatch' "
4967 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4968 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4969 		NULL, NULL, booleanMatch,
4970 		octetStringIndexer, octetStringFilter,
4971 		NULL },
4972 
4973 	{"( 2.5.13.14 NAME 'integerMatch' "
4974 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4975 		SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
4976 		NULL, NULL, integerMatch,
4977 		integerIndexer, integerFilter,
4978 		NULL },
4979 
4980 	{"( 2.5.13.15 NAME 'integerOrderingMatch' "
4981 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4982 		SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4983 		NULL, NULL, integerMatch,
4984 		NULL, NULL,
4985 		"integerMatch" },
4986 
4987 	{"( 2.5.13.16 NAME 'bitStringMatch' "
4988 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4989 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4990 		NULL, NULL, octetStringMatch,
4991 		octetStringIndexer, octetStringFilter,
4992 		NULL },
4993 
4994 	{"( 2.5.13.17 NAME 'octetStringMatch' "
4995 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4996 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4997 		NULL, NULL, octetStringMatch,
4998 		octetStringIndexer, octetStringFilter,
4999 		NULL },
5000 
5001 	{"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
5002 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5003 		SLAP_MR_ORDERING, NULL,
5004 		NULL, NULL, octetStringOrderingMatch,
5005 		NULL, NULL,
5006 		"octetStringMatch" },
5007 
5008 	{"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
5009 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5010 		SLAP_MR_SUBSTR, NULL,
5011 		NULL, NULL, octetStringSubstringsMatch,
5012 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
5013 		"octetStringMatch" },
5014 
5015 	{"( 2.5.13.20 NAME 'telephoneNumberMatch' "
5016 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
5017 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5018 		NULL,
5019 		telephoneNumberNormalize, octetStringMatch,
5020 		octetStringIndexer, octetStringFilter,
5021 		NULL },
5022 
5023 	{"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
5024 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
5025 		SLAP_MR_SUBSTR, NULL,
5026 		NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
5027 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
5028 		"telephoneNumberMatch" },
5029 
5030 	{"( 2.5.13.22 NAME 'presentationAddressMatch' "
5031 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
5032 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5033 		NULL, NULL, NULL, NULL, NULL, NULL },
5034 
5035 	{"( 2.5.13.23 NAME 'uniqueMemberMatch' "
5036 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
5037 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5038 		NULL, uniqueMemberNormalize, uniqueMemberMatch,
5039 		uniqueMemberIndexer, uniqueMemberFilter,
5040 		NULL },
5041 
5042 	{"( 2.5.13.24 NAME 'protocolInformationMatch' "
5043 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
5044 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5045 		NULL, NULL, NULL, NULL, NULL, NULL },
5046 
5047 	{"( 2.5.13.27 NAME 'generalizedTimeMatch' "
5048 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5049 		SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
5050 		NULL, generalizedTimeNormalize, octetStringMatch,
5051 		generalizedTimeIndexer, generalizedTimeFilter,
5052 		NULL },
5053 
5054 	{"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
5055 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5056 		SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5057 		NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
5058 		NULL, NULL,
5059 		"generalizedTimeMatch" },
5060 
5061 	{"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
5062 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5063 		SLAP_MR_EQUALITY | SLAP_MR_EXT,
5064 			integerFirstComponentMatchSyntaxes,
5065 		NULL, firstComponentNormalize, integerMatch,
5066 		octetStringIndexer, octetStringFilter,
5067 		NULL },
5068 
5069 	{"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
5070 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
5071 		SLAP_MR_EQUALITY | SLAP_MR_EXT,
5072 			objectIdentifierFirstComponentMatchSyntaxes,
5073 		NULL, firstComponentNormalize, octetStringMatch,
5074 		octetStringIndexer, octetStringFilter,
5075 		NULL },
5076 
5077 	{"( 2.5.13.34 NAME 'certificateExactMatch' "
5078 		"SYNTAX 1.3.6.1.1.15.1 )",
5079 		SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
5080 		NULL, certificateExactNormalize, octetStringMatch,
5081 		octetStringIndexer, octetStringFilter,
5082 		NULL },
5083 
5084 	{"( 2.5.13.35 NAME 'certificateMatch' "
5085 		"SYNTAX 1.3.6.1.1.15.2 )",
5086 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5087 		NULL, NULL, NULL, NULL, NULL,
5088 		NULL },
5089 
5090 	{"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
5091 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5092 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5093 		NULL, IA5StringNormalize, octetStringMatch,
5094 		octetStringIndexer, octetStringFilter,
5095 		IA5StringApproxMatchOID },
5096 
5097 	{"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
5098 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5099 		SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5100 		NULL, IA5StringNormalize, octetStringMatch,
5101 		octetStringIndexer, octetStringFilter,
5102 		IA5StringApproxMatchOID },
5103 
5104 	{"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
5105 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5106 		SLAP_MR_SUBSTR, NULL,
5107 		NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5108 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
5109 		"caseIgnoreIA5Match" },
5110 
5111 	{"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
5112 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5113 		SLAP_MR_SUBSTR, NULL,
5114 		NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5115 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
5116 		"caseExactIA5Match" },
5117 
5118 #ifdef SLAPD_AUTHPASSWD
5119 	/* needs updating */
5120 	{"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
5121 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5122 		SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5123 		NULL, NULL, authPasswordMatch,
5124 		NULL, NULL,
5125 		NULL},
5126 #endif
5127 
5128 	{"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
5129 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5130 		SLAP_MR_EXT, NULL,
5131 		NULL, NULL, integerBitAndMatch,
5132 		NULL, NULL,
5133 		"integerMatch" },
5134 
5135 	{"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
5136 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5137 		SLAP_MR_EXT, NULL,
5138 		NULL, NULL, integerBitOrMatch,
5139 		NULL, NULL,
5140 		"integerMatch" },
5141 
5142 	{"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
5143 		"SYNTAX 1.3.6.1.1.16.1 )",
5144 		SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
5145 		NULL, UUIDNormalize, octetStringMatch,
5146 		octetStringIndexer, octetStringFilter,
5147 		NULL},
5148 
5149 	{"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
5150 		"SYNTAX 1.3.6.1.1.16.1 )",
5151 		SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
5152 		NULL, UUIDNormalize, octetStringOrderingMatch,
5153 		octetStringIndexer, octetStringFilter,
5154 		"UUIDMatch"},
5155 
5156 	{"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
5157 		"SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5158 		SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
5159 		NULL, csnNormalize, csnMatch,
5160 		csnIndexer, csnFilter,
5161 		NULL},
5162 
5163 	{"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
5164 		"SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5165 		SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5166 		NULL, NULL, csnOrderingMatch,
5167 		NULL, NULL,
5168 		"CSNMatch" },
5169 
5170 	{"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
5171 		"SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
5172 		SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
5173 		NULL, csnSidNormalize, octetStringMatch,
5174 		octetStringIndexer, octetStringFilter,
5175 		NULL },
5176 
5177 	/* FIXME: OID is unused, but not registered yet */
5178 	{"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
5179 		"SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
5180 		SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5181 		NULL, authzNormalize, authzMatch,
5182 		NULL, NULL,
5183 		NULL},
5184 
5185 	{NULL, SLAP_MR_NONE, NULL,
5186 		NULL, NULL, NULL, NULL, NULL,
5187 		NULL }
5188 };
5189 
5190 int
5191 slap_schema_init( void )
5192 {
5193 	int		res;
5194 	int		i;
5195 
5196 	/* we should only be called once (from main) */
5197 	assert( schema_init_done == 0 );
5198 
5199 	for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
5200 		res = register_syntax( &syntax_defs[i] );
5201 
5202 		if ( res ) {
5203 			fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
5204 				 syntax_defs[i].sd_desc );
5205 			return LDAP_OTHER;
5206 		}
5207 	}
5208 
5209 	for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
5210 		if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
5211 			mrule_defs[i].mrd_compat_syntaxes == NULL )
5212 		{
5213 			fprintf( stderr,
5214 				"slap_schema_init: Ignoring unusable matching rule %s\n",
5215 				 mrule_defs[i].mrd_desc );
5216 			continue;
5217 		}
5218 
5219 		res = register_matching_rule( &mrule_defs[i] );
5220 
5221 		if ( res ) {
5222 			fprintf( stderr,
5223 				"slap_schema_init: Error registering matching rule %s\n",
5224 				 mrule_defs[i].mrd_desc );
5225 			return LDAP_OTHER;
5226 		}
5227 	}
5228 
5229 	res = slap_schema_load();
5230 	schema_init_done = 1;
5231 	return res;
5232 }
5233 
5234 void
5235 schema_destroy( void )
5236 {
5237 	oidm_destroy();
5238 	oc_destroy();
5239 	at_destroy();
5240 	mr_destroy();
5241 	mru_destroy();
5242 	syn_destroy();
5243 
5244 	if( schema_init_done ) {
5245 		ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
5246 		ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
5247 	}
5248 }
5249