xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/getdn.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: getdn.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $	*/
2 
3 /* OpenLDAP: pkg/ldap/libraries/libldap/getdn.c,v 1.130.2.5 2009/11/18 01:03:02 quanah Exp */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2009 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* Portions Copyright (c) 1994 Regents of the University of Michigan.
18  * All rights reserved.
19  */
20 
21 #include "portable.h"
22 
23 #include <stdio.h>
24 
25 #include <ac/stdlib.h>
26 #include <ac/socket.h>
27 #include <ac/string.h>
28 #include <ac/time.h>
29 
30 #include "ldap-int.h"
31 #include "ldap_schema.h"
32 
33 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
34  * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
35 #define DC_IN_UFN
36 
37 /* parsing/printing routines */
38 static int str2strval( const char *str, ber_len_t stoplen, struct berval *val,
39 		const char **next, unsigned flags, int *retFlags, void *ctx );
40 static int DCE2strval( const char *str, struct berval *val,
41 		const char **next, unsigned flags, void *ctx );
42 static int IA52strval( const char *str, struct berval *val,
43 		const char **next, unsigned flags, void *ctx );
44 static int quotedIA52strval( const char *str, struct berval *val,
45 		const char **next, unsigned flags, void *ctx );
46 static int hexstr2binval( const char *str, struct berval *val,
47 		const char **next, unsigned flags, void *ctx );
48 static int hexstr2bin( const char *str, char *c );
49 static int byte2hexpair( const char *val, char *pair );
50 static int binval2hexstr( struct berval *val, char *str );
51 static int strval2strlen( struct berval *val, unsigned flags,
52 		ber_len_t *len );
53 static int strval2str( struct berval *val, char *str, unsigned flags,
54 		ber_len_t *len );
55 static int strval2IA5strlen( struct berval *val, unsigned flags,
56 		ber_len_t *len );
57 static int strval2IA5str( struct berval *val, char *str, unsigned flags,
58 		ber_len_t *len );
59 static int strval2DCEstrlen( struct berval *val, unsigned flags,
60 		ber_len_t *len );
61 static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
62 		ber_len_t *len );
63 static int strval2ADstrlen( struct berval *val, unsigned flags,
64 		ber_len_t *len );
65 static int strval2ADstr( struct berval *val, char *str, unsigned flags,
66 		ber_len_t *len );
67 static int dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN );
68 
69 /* AVA helpers */
70 static LDAPAVA * ldapava_new(
71 	const struct berval *attr, const struct berval *val, unsigned flags, void *ctx );
72 
73 /* Higher level helpers */
74 static int rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len,
75 		int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
76 static int rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len,
77 		int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
78 static int rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len  );
79 static int rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len );
80 static int rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len );
81 static int rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flag, ber_len_t *len, int first );
82 static int rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len );
83 static int rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first );
84 
85 /*
86  * RFC 1823 ldap_get_dn
87  */
88 char *
89 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
90 {
91 	char		*dn;
92 	BerElement	tmp;
93 
94 	Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
95 
96 	assert( ld != NULL );
97 	assert( LDAP_VALID(ld) );
98 	assert( entry != NULL );
99 
100 	tmp = *entry->lm_ber;	/* struct copy */
101 	if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
102 		ld->ld_errno = LDAP_DECODING_ERROR;
103 		return( NULL );
104 	}
105 
106 	return( dn );
107 }
108 
109 int
110 ldap_get_dn_ber( LDAP *ld, LDAPMessage *entry, BerElement **berout,
111 	BerValue *dn )
112 {
113 	BerElement	tmp, *ber;
114 	ber_len_t	len = 0;
115 	int rc = LDAP_SUCCESS;
116 
117 	Debug( LDAP_DEBUG_TRACE, "ldap_get_dn_ber\n", 0, 0, 0 );
118 
119 	assert( ld != NULL );
120 	assert( LDAP_VALID(ld) );
121 	assert( entry != NULL );
122 	assert( dn != NULL );
123 
124 	dn->bv_val = NULL;
125 	dn->bv_len = 0;
126 
127 	if ( berout ) {
128 		*berout = NULL;
129 		ber = ldap_alloc_ber_with_options( ld );
130 		if( ber == NULL ) {
131 			return LDAP_NO_MEMORY;
132 		}
133 		*berout = ber;
134 	} else {
135 		ber = &tmp;
136 	}
137 
138 	*ber = *entry->lm_ber;	/* struct copy */
139 	if ( ber_scanf( ber, "{ml{" /*}*/, dn, &len ) == LBER_ERROR ) {
140 		rc = ld->ld_errno = LDAP_DECODING_ERROR;
141 	}
142 	if ( rc == LDAP_SUCCESS ) {
143 		/* set the length to avoid overrun */
144 		rc = ber_set_option( ber, LBER_OPT_REMAINING_BYTES, &len );
145 		if( rc != LBER_OPT_SUCCESS ) {
146 			rc = ld->ld_errno = LDAP_LOCAL_ERROR;
147 		}
148 	}
149 	if ( rc != LDAP_SUCCESS && berout ) {
150 		ber_free( ber, 0 );
151 		*berout = NULL;
152 	}
153 	return rc;
154 }
155 
156 /*
157  * RFC 1823 ldap_dn2ufn
158  */
159 char *
160 ldap_dn2ufn( LDAP_CONST char *dn )
161 {
162 	char	*out = NULL;
163 
164 	Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
165 
166 	( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
167 		&out, LDAP_DN_FORMAT_UFN );
168 
169 	return( out );
170 }
171 
172 /*
173  * RFC 1823 ldap_explode_dn
174  */
175 char **
176 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
177 {
178 	LDAPDN	tmpDN;
179 	char	**values = NULL;
180 	int	iRDN;
181 	unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
182 
183 	Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
184 
185 	if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP )
186 			!= LDAP_SUCCESS ) {
187 		return NULL;
188 	}
189 
190 	if( tmpDN == NULL ) {
191 		values = LDAP_MALLOC( sizeof( char * ) );
192 		if( values == NULL ) return NULL;
193 
194 		values[0] = NULL;
195 		return values;
196 	}
197 
198 	for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ );
199 
200 	values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) );
201 	if ( values == NULL ) {
202 		ldap_dnfree( tmpDN );
203 		return NULL;
204 	}
205 
206 	for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
207 		ldap_rdn2str( tmpDN[ iRDN ], &values[ iRDN ], flag );
208 	}
209 	ldap_dnfree( tmpDN );
210 	values[ iRDN ] = NULL;
211 
212 	return values;
213 }
214 
215 char **
216 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
217 {
218 	LDAPRDN		tmpRDN;
219 	char		**values = NULL;
220 	const char 	*p;
221 	int		iAVA;
222 
223 	Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
224 
225 	/*
226 	 * we only parse the first rdn
227 	 * FIXME: we prefer efficiency over checking if the _ENTIRE_
228 	 * dn can be parsed
229 	 */
230 	if ( ldap_str2rdn( rdn, &tmpRDN, (char **) &p, LDAP_DN_FORMAT_LDAP )
231 			!= LDAP_SUCCESS ) {
232 		return( NULL );
233 	}
234 
235 	for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) ;
236 	values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) );
237 	if ( values == NULL ) {
238 		ldap_rdnfree( tmpRDN );
239 		return( NULL );
240 	}
241 
242 	for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) {
243 		ber_len_t	l = 0, vl, al = 0;
244 		char		*str;
245 		LDAPAVA		*ava = tmpRDN[ iAVA ];
246 
247 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
248 			vl = 1 + 2 * ava->la_value.bv_len;
249 
250 		} else {
251 			if ( strval2strlen( &ava->la_value,
252 						ava->la_flags, &vl ) ) {
253 				goto error_return;
254 			}
255 		}
256 
257 		if ( !notypes ) {
258 			al = ava->la_attr.bv_len;
259 			l = vl + ava->la_attr.bv_len + 1;
260 
261 			str = LDAP_MALLOC( l + 1 );
262 			AC_MEMCPY( str, ava->la_attr.bv_val,
263 					ava->la_attr.bv_len );
264 			str[ al++ ] = '=';
265 
266 		} else {
267 			l = vl;
268 			str = LDAP_MALLOC( l + 1 );
269 		}
270 
271 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
272 			str[ al++ ] = '#';
273 			if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) {
274 				goto error_return;
275 			}
276 
277 		} else {
278 			if ( strval2str( &ava->la_value, &str[ al ],
279 					ava->la_flags, &vl ) ) {
280 				goto error_return;
281 			}
282 		}
283 
284 		str[ l ] = '\0';
285 		values[ iAVA ] = str;
286 	}
287 	values[ iAVA ] = NULL;
288 
289 	ldap_rdnfree( tmpRDN );
290 
291 	return( values );
292 
293 error_return:;
294 	LBER_VFREE( values );
295 	ldap_rdnfree( tmpRDN );
296 	return( NULL );
297 }
298 
299 char *
300 ldap_dn2dcedn( LDAP_CONST char *dn )
301 {
302 	char	*out = NULL;
303 
304 	Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
305 
306 	( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
307 				   &out, LDAP_DN_FORMAT_DCE );
308 
309 	return( out );
310 }
311 
312 char *
313 ldap_dcedn2dn( LDAP_CONST char *dce )
314 {
315 	char	*out = NULL;
316 
317 	Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
318 
319 	( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
320 
321 	return( out );
322 }
323 
324 char *
325 ldap_dn2ad_canonical( LDAP_CONST char *dn )
326 {
327 	char	*out = NULL;
328 
329 	Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
330 
331 	( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
332 		       &out, LDAP_DN_FORMAT_AD_CANONICAL );
333 
334 	return( out );
335 }
336 
337 /*
338  * function that changes the string representation of dnin
339  * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
340  *
341  * fin can be one of:
342  * 	LDAP_DN_FORMAT_LDAP		(RFC 4514 liberal, plus some RFC 1779)
343  * 	LDAP_DN_FORMAT_LDAPV3	(RFC 4514)
344  * 	LDAP_DN_FORMAT_LDAPV2	(RFC 1779)
345  * 	LDAP_DN_FORMAT_DCE		(?)
346  *
347  * fout can be any of the above except
348  * 	LDAP_DN_FORMAT_LDAP
349  * plus:
350  * 	LDAP_DN_FORMAT_UFN		(RFC 1781, partial and with extensions)
351  * 	LDAP_DN_FORMAT_AD_CANONICAL	(?)
352  */
353 int
354 ldap_dn_normalize( LDAP_CONST char *dnin,
355 	unsigned fin, char **dnout, unsigned fout )
356 {
357 	int	rc;
358 	LDAPDN	tmpDN = NULL;
359 
360 	Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
361 
362 	assert( dnout != NULL );
363 
364 	*dnout = NULL;
365 
366 	if ( dnin == NULL ) {
367 		return( LDAP_SUCCESS );
368 	}
369 
370 	rc = ldap_str2dn( dnin , &tmpDN, fin );
371 	if ( rc != LDAP_SUCCESS ) {
372 		return( rc );
373 	}
374 
375 	rc = ldap_dn2str( tmpDN, dnout, fout );
376 
377 	ldap_dnfree( tmpDN );
378 
379 	return( rc );
380 }
381 
382 /* States */
383 #define B4AVA			0x0000
384 
385 /* #define	B4ATTRTYPE		0x0001 */
386 #define B4OIDATTRTYPE		0x0002
387 #define B4STRINGATTRTYPE	0x0003
388 
389 #define B4AVAEQUALS		0x0100
390 #define B4AVASEP		0x0200
391 #define B4RDNSEP		0x0300
392 #define GOTAVA			0x0400
393 
394 #define B4ATTRVALUE		0x0010
395 #define B4STRINGVALUE		0x0020
396 #define B4IA5VALUEQUOTED	0x0030
397 #define B4IA5VALUE		0x0040
398 #define B4BINARYVALUE		0x0050
399 
400 /*
401  * Helpers (mostly from slap.h)
402  * c is assumed to Unicode in an ASCII compatible format (UTF-8)
403  * Macros assume "C" Locale (ASCII)
404  */
405 #define LDAP_DN_ASCII_SPACE(c) \
406 	( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
407 #define LDAP_DN_ASCII_LOWER(c)		LDAP_LOWER(c)
408 #define LDAP_DN_ASCII_UPPER(c)		LDAP_UPPER(c)
409 #define LDAP_DN_ASCII_ALPHA(c)		LDAP_ALPHA(c)
410 
411 #define LDAP_DN_ASCII_DIGIT(c)		LDAP_DIGIT(c)
412 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c)	LDAP_HEXLOWER(c)
413 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c)	LDAP_HEXUPPER(c)
414 #define LDAP_DN_ASCII_HEXDIGIT(c)	LDAP_HEX(c)
415 #define LDAP_DN_ASCII_ALNUM(c)		LDAP_ALNUM(c)
416 #define LDAP_DN_ASCII_PRINTABLE(c)	( (c) >= ' ' && (c) <= '~' )
417 
418 /* attribute type */
419 #define LDAP_DN_OID_LEADCHAR(c)		LDAP_DIGIT(c)
420 #define LDAP_DN_DESC_LEADCHAR(c)	LDAP_ALPHA(c)
421 #define LDAP_DN_DESC_CHAR(c)		LDAP_LDH(c)
422 #define LDAP_DN_LANG_SEP(c)		( (c) == ';' )
423 #define LDAP_DN_ATTRDESC_CHAR(c) \
424 	( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
425 
426 /* special symbols */
427 #define LDAP_DN_AVA_EQUALS(c)		( (c) == '=' )
428 #define LDAP_DN_AVA_SEP(c)		( (c) == '+' )
429 #define LDAP_DN_RDN_SEP(c)		( (c) == ',' )
430 #define LDAP_DN_RDN_SEP_V2(c)		( LDAP_DN_RDN_SEP(c) || (c) == ';' )
431 #define LDAP_DN_OCTOTHORPE(c)		( (c) == '#' )
432 #define LDAP_DN_QUOTES(c)		( (c) == '\"' )
433 #define LDAP_DN_ESCAPE(c)		( (c) == '\\' )
434 #define LDAP_DN_VALUE_END(c) \
435 	( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
436 
437 /* NOTE: according to RFC 4514, '=' can be escaped and treated as special,
438  * i.e. escaped both as "\<hexpair>" and * as "\=", but it is treated as
439  * a regular char, i.e. it can also appear as '='.
440  *
441  * As such, in 2.2 we used to allow reading unescaped '=', but we always
442  * produced escaped '\3D'; this changes since 2.3, if compatibility issues
443  * do not arise
444  */
445 #define LDAP_DN_NE(c) \
446 	( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
447 	  || LDAP_DN_QUOTES(c) \
448 	  || (c) == '<' || (c) == '>' )
449 #define LDAP_DN_MAYESCAPE(c) \
450 	( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \
451 	  || LDAP_DN_AVA_EQUALS(c) \
452 	  || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) )
453 #define LDAP_DN_SHOULDESCAPE(c)		( LDAP_DN_AVA_EQUALS(c) )
454 
455 #define LDAP_DN_NEEDESCAPE(c) \
456 	( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
457 #define LDAP_DN_NEEDESCAPE_LEAD(c) 	LDAP_DN_MAYESCAPE(c)
458 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
459 	( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
460 #define LDAP_DN_WILLESCAPE_CHAR(c) \
461 	( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) )
462 #define LDAP_DN_IS_PRETTY(f)		( (f) & LDAP_DN_PRETTY )
463 #define LDAP_DN_WILLESCAPE_HEX(f, c) \
464 	( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
465 
466 /* LDAPv2 */
467 #define	LDAP_DN_VALUE_END_V2(c) \
468 	( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
469 /* RFC 1779 */
470 #define	LDAP_DN_V2_SPECIAL(c) \
471 	  ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
472 	    || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
473 	    || LDAP_DN_OCTOTHORPE(c) )
474 #define LDAP_DN_V2_PAIR(c) \
475 	  ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
476 
477 /*
478  * DCE (mostly from Luke Howard and IBM implementation for AIX)
479  *
480  * From: "Application Development Guide - Directory Services" (FIXME: add link?)
481  * Here escapes and valid chars for GDS are considered; as soon as more
482  * specific info is found, the macros will be updated.
483  *
484  * Chars:	'a'-'z', 'A'-'Z', '0'-'9',
485  *		'.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
486  *
487  * Metachars:	'/', ',', '=', '\'.
488  *
489  * the '\' is used to escape other metachars.
490  *
491  * Assertion:		'='
492  * RDN separator:	'/'
493  * AVA separator:	','
494  *
495  * Attribute types must start with alphabetic chars and can contain
496  * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
497  */
498 #define LDAP_DN_RDN_SEP_DCE(c)		( (c) == '/' )
499 #define LDAP_DN_AVA_SEP_DCE(c)		( (c) == ',' )
500 #define LDAP_DN_ESCAPE_DCE(c)		( LDAP_DN_ESCAPE(c) )
501 #define	LDAP_DN_VALUE_END_DCE(c) \
502 	( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
503 #define LDAP_DN_NEEDESCAPE_DCE(c) \
504 	( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
505 
506 /* AD Canonical */
507 #define LDAP_DN_RDN_SEP_AD(c)		( (c) == '/' )
508 #define LDAP_DN_ESCAPE_AD(c)		( LDAP_DN_ESCAPE(c) )
509 #define LDAP_DN_AVA_SEP_AD(c)		( (c) == ',' )	/* assume same as DCE */
510 #define	LDAP_DN_VALUE_END_AD(c) \
511 	( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
512 #define LDAP_DN_NEEDESCAPE_AD(c) \
513 	( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
514 
515 /* generics */
516 #define LDAP_DN_HEXPAIR(s) \
517 	( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
518 /* better look at the AttributeDescription? */
519 
520 /* FIXME: no composite rdn or non-"dc" types, right?
521  * (what about "dc" in OID form?) */
522 /* FIXME: we do not allow binary values in domain, right? */
523 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
524 /* NOTE: don't use strcasecmp() as it is locale specific! */
525 #define	LDAP_DC_ATTR	"dc"
526 #define	LDAP_DC_ATTRU	"DC"
527 #define LDAP_DN_IS_RDN_DC( r ) \
528 	( (r) && (r)[0] && !(r)[1] \
529 	  && ((r)[0]->la_flags & LDAP_AVA_STRING) \
530 	  && ((r)[0]->la_attr.bv_len == 2) \
531 	  && (((r)[0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \
532 		|| ((r)[0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \
533 	  && (((r)[0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \
534 		|| ((r)[0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1])))
535 
536 /* Composite rules */
537 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
538 	( LDAP_DN_LDAPV2(f) \
539 	  || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
540 #define LDAP_DN_ALLOW_SPACES(f) \
541 	( LDAP_DN_LDAPV2(f) \
542 	  || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
543 #define LDAP_DN_LDAP(f) \
544 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
545 #define LDAP_DN_LDAPV3(f) \
546 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
547 #define LDAP_DN_LDAPV2(f) \
548 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
549 #define LDAP_DN_DCE(f) \
550 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
551 #define LDAP_DN_UFN(f) \
552 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
553 #define LDAP_DN_ADC(f) \
554 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
555 #define LDAP_DN_FORMAT(f)		( (f) & LDAP_DN_FORMAT_MASK )
556 
557 /*
558  * LDAPAVA helpers (will become part of the API for operations
559  * on structural representations of DNs).
560  */
561 static LDAPAVA *
562 ldapava_new( const struct berval *attr, const struct berval *val,
563 		unsigned flags, void *ctx )
564 {
565 	LDAPAVA *ava;
566 
567 	assert( attr != NULL );
568 	assert( val != NULL );
569 
570 	ava = LDAP_MALLOCX( sizeof( LDAPAVA ) + attr->bv_len + 1, ctx );
571 
572 	if ( ava ) {
573 		ava->la_attr.bv_len = attr->bv_len;
574 		ava->la_attr.bv_val = (char *)(ava+1);
575 		AC_MEMCPY( ava->la_attr.bv_val, attr->bv_val, attr->bv_len );
576 		ava->la_attr.bv_val[attr->bv_len] = '\0';
577 
578 		ava->la_value = *val;
579 		ava->la_flags = flags | LDAP_AVA_FREE_VALUE;
580 
581 		ava->la_private = NULL;
582 	}
583 
584 	return( ava );
585 }
586 
587 void
588 ldapava_free( LDAPAVA *ava, void *ctx )
589 {
590 	assert( ava != NULL );
591 
592 #if 0
593 	/* ava's private must be freed by caller
594 	 * (at present let's skip this check because la_private
595 	 * basically holds static data) */
596 	assert( ava->la_private == NULL );
597 #endif
598 
599 	if (ava->la_flags & LDAP_AVA_FREE_VALUE)
600 		LDAP_FREEX( ava->la_value.bv_val, ctx );
601 
602 	LDAP_FREEX( ava, ctx );
603 }
604 
605 void
606 ldap_rdnfree( LDAPRDN rdn )
607 {
608 	ldap_rdnfree_x( rdn, NULL );
609 }
610 
611 void
612 ldap_rdnfree_x( LDAPRDN rdn, void *ctx )
613 {
614 	int iAVA;
615 
616 	if ( rdn == NULL ) {
617 		return;
618 	}
619 
620 	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
621 		ldapava_free( rdn[ iAVA ], ctx );
622 	}
623 
624 	LDAP_FREEX( rdn, ctx );
625 }
626 
627 void
628 ldap_dnfree( LDAPDN dn )
629 {
630 	ldap_dnfree_x( dn, NULL );
631 }
632 
633 void
634 ldap_dnfree_x( LDAPDN dn, void *ctx )
635 {
636 	int iRDN;
637 
638 	if ( dn == NULL ) {
639 		return;
640 	}
641 
642 	for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
643 		ldap_rdnfree_x( dn[ iRDN ], ctx );
644 	}
645 
646 	LDAP_FREEX( dn, ctx );
647 }
648 
649 /*
650  * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
651  * into a structural representation of the DN, by separating attribute
652  * types and values encoded in the more appropriate form, which is
653  * string or OID for attribute types and binary form of the BER encoded
654  * value or Unicode string. Formats different from LDAPv3 are parsed
655  * according to their own rules and turned into the more appropriate
656  * form according to LDAPv3.
657  *
658  * NOTE: I realize the code is getting spaghettish; it is rather
659  * experimental and will hopefully turn into something more simple
660  * and readable as soon as it works as expected.
661  */
662 
663 /*
664  * Default sizes of AVA and RDN static working arrays; if required
665  * the are dynamically resized.  The values can be tuned in case
666  * of special requirements (e.g. very deep DN trees or high number
667  * of AVAs per RDN).
668  */
669 #define	TMP_AVA_SLOTS	8
670 #define	TMP_RDN_SLOTS	32
671 
672 int
673 ldap_str2dn( LDAP_CONST char *str, LDAPDN *dn, unsigned flags )
674 {
675 	struct berval	bv;
676 
677 	assert( str != NULL );
678 
679 	bv.bv_len = strlen( str );
680 	bv.bv_val = (char *) str;
681 
682 	return ldap_bv2dn_x( &bv, dn, flags, NULL );
683 }
684 
685 int
686 ldap_bv2dn( struct berval *bv, LDAPDN *dn, unsigned flags )
687 {
688 	return ldap_bv2dn_x( bv, dn, flags, NULL );
689 }
690 
691 int
692 ldap_bv2dn_x( struct berval *bvin, LDAPDN *dn, unsigned flags, void *ctx )
693 {
694 	const char 	*p;
695 	int		rc = LDAP_DECODING_ERROR;
696 	int		nrdns = 0;
697 
698 	LDAPDN		newDN = NULL;
699 	LDAPRDN		newRDN = NULL, tmpDN_[TMP_RDN_SLOTS], *tmpDN = tmpDN_;
700 	int		num_slots = TMP_RDN_SLOTS;
701 	char		*str, *end;
702 	struct berval	bvtmp, *bv = &bvtmp;
703 
704 	assert( bvin != NULL );
705 	assert( bvin->bv_val != NULL );
706 	assert( dn != NULL );
707 
708 	*bv = *bvin;
709 	str = bv->bv_val;
710 	end = str + bv->bv_len;
711 
712 	Debug( LDAP_DEBUG_ARGS, "=> ldap_bv2dn(%s,%u)\n", str, flags, 0 );
713 
714 	*dn = NULL;
715 
716 	switch ( LDAP_DN_FORMAT( flags ) ) {
717 	case LDAP_DN_FORMAT_LDAP:
718 	case LDAP_DN_FORMAT_LDAPV3:
719 	case LDAP_DN_FORMAT_DCE:
720 		break;
721 
722 		/* allow DN enclosed in brackets */
723 	case LDAP_DN_FORMAT_LDAPV2:
724 		if ( str[0] == '<' ) {
725 			if ( bv->bv_len < 2 || end[ -1 ] != '>' ) {
726 				rc = LDAP_DECODING_ERROR;
727 				goto parsing_error;
728 			}
729 			bv->bv_val++;
730 			bv->bv_len -= 2;
731 			str++;
732 			end--;
733 		}
734 		break;
735 
736 	/* unsupported in str2dn */
737 	case LDAP_DN_FORMAT_UFN:
738 	case LDAP_DN_FORMAT_AD_CANONICAL:
739 		return LDAP_PARAM_ERROR;
740 
741 	case LDAP_DN_FORMAT_LBER:
742 	default:
743 		return LDAP_PARAM_ERROR;
744 	}
745 
746 	if ( bv->bv_len == 0 ) {
747 		return LDAP_SUCCESS;
748 	}
749 
750 	if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) {
751 		/* value must have embedded NULs */
752 		return LDAP_DECODING_ERROR;
753 	}
754 
755 	p = str;
756 	if ( LDAP_DN_DCE( flags ) ) {
757 
758 		/*
759 		 * (from Luke Howard: thnx) A RDN separator is required
760 		 * at the beginning of an (absolute) DN.
761 		 */
762 		if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
763 			goto parsing_error;
764 		}
765 		p++;
766 
767 	/*
768 	 * actually we do not want to accept by default the DCE form,
769 	 * we do not want to auto-detect it
770 	 */
771 #if 0
772 	} else if ( LDAP_DN_LDAP( flags ) ) {
773 		/*
774 		 * if dn starts with '/' let's make it a DCE dn
775 		 */
776 		if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
777 			flags |= LDAP_DN_FORMAT_DCE;
778 			p++;
779 		}
780 #endif
781 	}
782 
783 	for ( ; p < end; p++ ) {
784 		int		err;
785 		struct berval 	tmpbv;
786 		tmpbv.bv_len = bv->bv_len - ( p - str );
787 		tmpbv.bv_val = (char *)p;
788 
789 		err = ldap_bv2rdn_x( &tmpbv, &newRDN, (char **) &p, flags,ctx);
790 		if ( err != LDAP_SUCCESS ) {
791 			goto parsing_error;
792 		}
793 
794 		/*
795 		 * We expect a rdn separator
796 		 */
797 		if ( p < end && p[ 0 ] ) {
798 			switch ( LDAP_DN_FORMAT( flags ) ) {
799 			case LDAP_DN_FORMAT_LDAPV3:
800 				if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
801 					rc = LDAP_DECODING_ERROR;
802 					goto parsing_error;
803 				}
804 				break;
805 
806 			case LDAP_DN_FORMAT_LDAP:
807 			case LDAP_DN_FORMAT_LDAPV2:
808 				if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
809 					rc = LDAP_DECODING_ERROR;
810 					goto parsing_error;
811 				}
812 				break;
813 
814 			case LDAP_DN_FORMAT_DCE:
815 				if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
816 					rc = LDAP_DECODING_ERROR;
817 					goto parsing_error;
818 				}
819 				break;
820 			}
821 		}
822 
823 
824 		tmpDN[nrdns++] = newRDN;
825 		newRDN = NULL;
826 
827 		/*
828 		 * make the static RDN array dynamically rescalable
829 		 */
830 		if ( nrdns == num_slots ) {
831 			LDAPRDN	*tmp;
832 
833 			if ( tmpDN == tmpDN_ ) {
834 				tmp = LDAP_MALLOCX( num_slots * 2 * sizeof( LDAPRDN * ), ctx );
835 				if ( tmp == NULL ) {
836 					rc = LDAP_NO_MEMORY;
837 					goto parsing_error;
838 				}
839 				AC_MEMCPY( tmp, tmpDN, num_slots * sizeof( LDAPRDN * ) );
840 
841 			} else {
842 				tmp = LDAP_REALLOCX( tmpDN, num_slots * 2 * sizeof( LDAPRDN * ), ctx );
843 				if ( tmp == NULL ) {
844 					rc = LDAP_NO_MEMORY;
845 					goto parsing_error;
846 				}
847 			}
848 
849 			tmpDN = tmp;
850 			num_slots *= 2;
851 		}
852 
853 		if ( p >= end || p[ 0 ] == '\0' ) {
854 			/*
855 			 * the DN is over, phew
856 			 */
857 			newDN = (LDAPDN)LDAP_MALLOCX( sizeof(LDAPRDN *) * (nrdns+1), ctx );
858 			if ( newDN == NULL ) {
859 				rc = LDAP_NO_MEMORY;
860 				goto parsing_error;
861 			} else {
862 				int i;
863 
864 				if ( LDAP_DN_DCE( flags ) ) {
865 					/* add in reversed order */
866 					for ( i=0; i<nrdns; i++ )
867 						newDN[i] = tmpDN[nrdns-1-i];
868 				} else {
869 					for ( i=0; i<nrdns; i++ )
870 						newDN[i] = tmpDN[i];
871 				}
872 				newDN[nrdns] = NULL;
873 				rc = LDAP_SUCCESS;
874 			}
875 			goto return_result;
876 		}
877 	}
878 
879 parsing_error:;
880 	if ( newRDN ) {
881 		ldap_rdnfree_x( newRDN, ctx );
882 	}
883 
884 	for ( nrdns-- ;nrdns >= 0; nrdns-- ) {
885 		ldap_rdnfree_x( tmpDN[nrdns], ctx );
886 	}
887 
888 return_result:;
889 
890 	if ( tmpDN != tmpDN_ ) {
891 		LDAP_FREEX( tmpDN, ctx );
892 	}
893 
894 	Debug( LDAP_DEBUG_ARGS, "<= ldap_bv2dn(%s)=%d %s\n", str, rc,
895 			rc ? ldap_err2string( rc ) : "" );
896 	*dn = newDN;
897 
898 	return( rc );
899 }
900 
901 /*
902  * ldap_str2rdn
903  *
904  * Parses a relative DN according to flags up to a rdn separator
905  * or to the end of str.
906  * Returns the rdn and a pointer to the string continuation, which
907  * corresponds to the rdn separator or to '\0' in case the string is over.
908  */
909 int
910 ldap_str2rdn( LDAP_CONST char *str, LDAPRDN *rdn,
911 	char **n_in, unsigned flags )
912 {
913 	struct berval	bv;
914 
915 	assert( str != NULL );
916 	assert( str[ 0 ] != '\0' );	/* FIXME: is this required? */
917 
918 	bv.bv_len = strlen( str );
919 	bv.bv_val = (char *) str;
920 
921 	return ldap_bv2rdn_x( &bv, rdn, n_in, flags, NULL );
922 }
923 
924 int
925 ldap_bv2rdn( struct berval *bv, LDAPRDN *rdn,
926 	char **n_in, unsigned flags )
927 {
928 	return ldap_bv2rdn_x( bv, rdn, n_in, flags, NULL );
929 }
930 
931 int
932 ldap_bv2rdn_x( struct berval *bv, LDAPRDN *rdn,
933 	char **n_in, unsigned flags, void *ctx )
934 {
935 	const char  	**n = (const char **) n_in;
936 	const char 	*p;
937 	int		navas = 0;
938 	int 		state = B4AVA;
939 	int		rc = LDAP_DECODING_ERROR;
940 	int		attrTypeEncoding = LDAP_AVA_STRING,
941 			attrValueEncoding = LDAP_AVA_STRING;
942 
943 	struct berval	attrType = BER_BVNULL;
944 	struct berval 	attrValue = BER_BVNULL;
945 
946 	LDAPRDN		newRDN = NULL;
947 	LDAPAVA		*tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_;
948 	int		num_slots = TMP_AVA_SLOTS;
949 
950 	char		*str;
951 	ber_len_t	stoplen;
952 
953 	assert( bv != NULL );
954 	assert( bv->bv_len != 0 );
955 	assert( bv->bv_val != NULL );
956 	assert( rdn || flags & LDAP_DN_SKIP );
957 	assert( n != NULL );
958 
959 	str = bv->bv_val;
960 	stoplen = bv->bv_len;
961 
962 	if ( rdn ) {
963 		*rdn = NULL;
964 	}
965 	*n = NULL;
966 
967 	switch ( LDAP_DN_FORMAT( flags ) ) {
968 	case LDAP_DN_FORMAT_LDAP:
969 	case LDAP_DN_FORMAT_LDAPV3:
970 	case LDAP_DN_FORMAT_LDAPV2:
971 	case LDAP_DN_FORMAT_DCE:
972 		break;
973 
974 	/* unsupported in str2dn */
975 	case LDAP_DN_FORMAT_UFN:
976 	case LDAP_DN_FORMAT_AD_CANONICAL:
977 		return LDAP_PARAM_ERROR;
978 
979 	case LDAP_DN_FORMAT_LBER:
980 	default:
981 		return LDAP_PARAM_ERROR;
982 	}
983 
984 	if ( bv->bv_len == 0 ) {
985 		return LDAP_SUCCESS;
986 
987 	}
988 
989 	if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) {
990 		/* value must have embedded NULs */
991 		return LDAP_DECODING_ERROR;
992 	}
993 
994 	p = str;
995 	for ( ; p[ 0 ] || state == GOTAVA; ) {
996 
997 		/*
998 		 * The parser in principle advances one token a time,
999 		 * or toggles state if preferable.
1000 		 */
1001 		switch (state) {
1002 
1003 		/*
1004 		 * an AttributeType can be encoded as:
1005 		 * - its string representation; in detail, implementations
1006 		 *   MUST recognize AttributeType string type names listed
1007 		 *   in Section 3 of RFC 4514, and MAY recognize other names.
1008 		 * - its numeric OID (a dotted decimal string)
1009 		 */
1010 		case B4AVA:
1011 			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1012 				if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
1013 					/* error */
1014 					goto parsing_error;
1015 				}
1016 				p++;
1017 			}
1018 
1019 			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1020 				if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1021 					/* error */
1022 					goto parsing_error;
1023 				}
1024 
1025 				/* whitespace is allowed (and trimmed) */
1026 				p++;
1027 				while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1028 					p++;
1029 				}
1030 
1031 				if ( !p[ 0 ] ) {
1032 					/* error: we expected an AVA */
1033 					goto parsing_error;
1034 				}
1035 			}
1036 
1037 			/* oid */
1038 			if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
1039 				state = B4OIDATTRTYPE;
1040 				break;
1041 			}
1042 
1043 			/* else must be alpha */
1044 			if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
1045 				goto parsing_error;
1046 			}
1047 
1048 			/* LDAPv2 "oid." prefix */
1049 			if ( LDAP_DN_LDAPV2( flags ) ) {
1050 				/*
1051 				 * to be overly pedantic, we only accept
1052 				 * "OID." or "oid."
1053 				 */
1054 				if ( flags & LDAP_DN_PEDANTIC ) {
1055 					if ( !strncmp( p, "OID.", 4 )
1056 						|| !strncmp( p, "oid.", 4 ) ) {
1057 						p += 4;
1058 						state = B4OIDATTRTYPE;
1059 						break;
1060 					}
1061 				} else {
1062 				       if ( !strncasecmp( p, "oid.", 4 ) ) {
1063 					       p += 4;
1064 					       state = B4OIDATTRTYPE;
1065 					       break;
1066 				       }
1067 				}
1068 			}
1069 
1070 			state = B4STRINGATTRTYPE;
1071 			break;
1072 
1073 		case B4OIDATTRTYPE: {
1074 			int 		err = LDAP_SUCCESS;
1075 
1076 			attrType.bv_val = ldap_int_parse_numericoid( &p, &err,
1077 				LDAP_SCHEMA_SKIP);
1078 
1079 			if ( err != LDAP_SUCCESS ) {
1080 				goto parsing_error;
1081 			}
1082 			attrType.bv_len = p - attrType.bv_val;
1083 
1084 			attrTypeEncoding = LDAP_AVA_BINARY;
1085 
1086 			state = B4AVAEQUALS;
1087 			break;
1088 		}
1089 
1090 		case B4STRINGATTRTYPE: {
1091 			const char 	*startPos, *endPos = NULL;
1092 			ber_len_t 	len;
1093 
1094 			/*
1095 			 * the starting char has been found to be
1096 			 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1097 			 * FIXME: DCE attr types seem to have a more
1098 			 * restrictive syntax (no '-' ...)
1099 			 */
1100 			for ( startPos = p++; p[ 0 ]; p++ ) {
1101 				if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1102 					continue;
1103 				}
1104 
1105 				if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1106 
1107 					/*
1108 					 * RFC 4514 explicitly does not allow attribute
1109 					 * description options, such as language tags.
1110 					 */
1111 					if ( flags & LDAP_DN_PEDANTIC ) {
1112 						goto parsing_error;
1113 					}
1114 
1115 					/*
1116 					 * we trim ';' and following lang
1117 					 * and so from attribute types
1118 					 */
1119 					endPos = p;
1120 					for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1121 							|| LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1122 						/* no op */ ;
1123 					}
1124 					break;
1125 				}
1126 				break;
1127 			}
1128 
1129 			len = ( endPos ? endPos : p ) - startPos;
1130 			if ( len == 0 ) {
1131 				goto parsing_error;
1132 			}
1133 
1134 			attrTypeEncoding = LDAP_AVA_STRING;
1135 
1136 			/*
1137 			 * here we need to decide whether to use it as is
1138 			 * or turn it in OID form; as a consequence, we
1139 			 * need to decide whether to binary encode the value
1140 			 */
1141 
1142 			state = B4AVAEQUALS;
1143 
1144 			if ( flags & LDAP_DN_SKIP ) {
1145 				break;
1146 			}
1147 
1148 			attrType.bv_val = (char *)startPos;
1149 			attrType.bv_len = len;
1150 
1151 			break;
1152 		}
1153 
1154 		case B4AVAEQUALS:
1155 			/* spaces may not be allowed */
1156 			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1157 				if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1158 					goto parsing_error;
1159 				}
1160 
1161 				/* trim spaces */
1162 				for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1163 					/* no op */
1164 				}
1165 			}
1166 
1167 			/* need equal sign */
1168 			if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1169 				goto parsing_error;
1170 			}
1171 			p++;
1172 
1173 			/* spaces may not be allowed */
1174 			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1175 				if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1176 					goto parsing_error;
1177 				}
1178 
1179 				/* trim spaces */
1180 				for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1181 					/* no op */
1182 				}
1183 			}
1184 
1185 			/*
1186 			 * octothorpe means a BER encoded value will follow
1187 			 * FIXME: I don't think DCE will allow it
1188 			 */
1189 			if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1190 				p++;
1191 				attrValueEncoding = LDAP_AVA_BINARY;
1192 				state = B4BINARYVALUE;
1193 				break;
1194 			}
1195 
1196 			/* STRING value expected */
1197 
1198 			/*
1199 			 * if we're pedantic, an attribute type in OID form
1200 			 * SHOULD imply a BER encoded attribute value; we
1201 			 * should at least issue a warning
1202 			 */
1203 			if ( ( flags & LDAP_DN_PEDANTIC )
1204 				&& ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1205 				/* OID attrType SHOULD use binary encoding */
1206 				goto parsing_error;
1207 			}
1208 
1209 			attrValueEncoding = LDAP_AVA_STRING;
1210 
1211 			/*
1212 			 * LDAPv2 allows the attribute value to be quoted;
1213 			 * also, IA5 values are expected, in principle
1214 			 */
1215 			if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1216 				if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1217 					p++;
1218 					state = B4IA5VALUEQUOTED;
1219 					break;
1220 				}
1221 
1222 				if ( LDAP_DN_LDAPV2( flags ) ) {
1223 					state = B4IA5VALUE;
1224 					break;
1225 				}
1226 			}
1227 
1228 			/*
1229 			 * here STRING means RFC 4514 string
1230 			 * FIXME: what about DCE strings?
1231 			 */
1232 			if ( !p[ 0 ] ) {
1233 				/* empty value */
1234 				state = GOTAVA;
1235 			} else {
1236 				state = B4STRINGVALUE;
1237 			}
1238 			break;
1239 
1240 		case B4BINARYVALUE:
1241 			if ( hexstr2binval( p, &attrValue, &p, flags, ctx ) ) {
1242 				goto parsing_error;
1243 			}
1244 
1245 			state = GOTAVA;
1246 			break;
1247 
1248 		case B4STRINGVALUE:
1249 			switch ( LDAP_DN_FORMAT( flags ) ) {
1250 			case LDAP_DN_FORMAT_LDAP:
1251 			case LDAP_DN_FORMAT_LDAPV3:
1252 				if ( str2strval( p, stoplen - ( p - str ),
1253 							&attrValue, &p, flags,
1254 							&attrValueEncoding, ctx ) ) {
1255 					goto parsing_error;
1256 				}
1257 				break;
1258 
1259 			case LDAP_DN_FORMAT_DCE:
1260 				if ( DCE2strval( p, &attrValue, &p, flags, ctx ) ) {
1261 					goto parsing_error;
1262 				}
1263 				break;
1264 
1265 			default:
1266 				assert( 0 );
1267 			}
1268 
1269 			state = GOTAVA;
1270 			break;
1271 
1272 		case B4IA5VALUE:
1273 			if ( IA52strval( p, &attrValue, &p, flags, ctx ) ) {
1274 				goto parsing_error;
1275 			}
1276 
1277 			state = GOTAVA;
1278 			break;
1279 
1280 		case B4IA5VALUEQUOTED:
1281 
1282 			/* lead quote already stripped */
1283 			if ( quotedIA52strval( p, &attrValue,
1284 						&p, flags, ctx ) ) {
1285 				goto parsing_error;
1286 			}
1287 
1288 			state = GOTAVA;
1289 			break;
1290 
1291 		case GOTAVA: {
1292 			int	rdnsep = 0;
1293 
1294 			if ( !( flags & LDAP_DN_SKIP ) ) {
1295 				LDAPAVA *ava;
1296 
1297 				/*
1298 				 * we accept empty values
1299 				 */
1300 				ava = ldapava_new( &attrType, &attrValue,
1301 						attrValueEncoding, ctx );
1302 				if ( ava == NULL ) {
1303 					rc = LDAP_NO_MEMORY;
1304 					goto parsing_error;
1305 				}
1306 				tmpRDN[navas++] = ava;
1307 
1308 				attrValue.bv_val = NULL;
1309 				attrValue.bv_len = 0;
1310 
1311 				/*
1312 				 * prepare room for new AVAs if needed
1313 				 */
1314 				if (navas == num_slots) {
1315 					LDAPAVA **tmp;
1316 
1317 					if ( tmpRDN == tmpRDN_ ) {
1318 						tmp = LDAP_MALLOCX( num_slots * 2 * sizeof( LDAPAVA * ), ctx );
1319 						if ( tmp == NULL ) {
1320 							rc = LDAP_NO_MEMORY;
1321 							goto parsing_error;
1322 						}
1323 						AC_MEMCPY( tmp, tmpRDN, num_slots * sizeof( LDAPAVA * ) );
1324 
1325 					} else {
1326 						tmp = LDAP_REALLOCX( tmpRDN, num_slots * 2 * sizeof( LDAPAVA * ), ctx );
1327 						if ( tmp == NULL ) {
1328 							rc = LDAP_NO_MEMORY;
1329 							goto parsing_error;
1330 						}
1331 					}
1332 
1333 					tmpRDN = tmp;
1334 					num_slots *= 2;
1335 				}
1336 			}
1337 
1338 			/*
1339 			 * if we got an AVA separator ('+', or ',' for DCE )
1340 			 * we expect a new AVA for this RDN; otherwise
1341 			 * we add the RDN to the DN
1342 			 */
1343 			switch ( LDAP_DN_FORMAT( flags ) ) {
1344 			case LDAP_DN_FORMAT_LDAP:
1345 			case LDAP_DN_FORMAT_LDAPV3:
1346 			case LDAP_DN_FORMAT_LDAPV2:
1347 				if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1348 					rdnsep = 1;
1349 				}
1350 				break;
1351 
1352 			case LDAP_DN_FORMAT_DCE:
1353 				if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1354 					rdnsep = 1;
1355 				}
1356 				break;
1357 			}
1358 
1359 			if ( rdnsep ) {
1360 				/*
1361 				 * the RDN is over, phew
1362 				 */
1363 				*n = p;
1364 				if ( !( flags & LDAP_DN_SKIP ) ) {
1365 					newRDN = (LDAPRDN)LDAP_MALLOCX(
1366 						sizeof(LDAPAVA) * (navas+1), ctx );
1367 					if ( newRDN == NULL ) {
1368 						rc = LDAP_NO_MEMORY;
1369 						goto parsing_error;
1370 					} else {
1371 						AC_MEMCPY( newRDN, tmpRDN, sizeof(LDAPAVA *) * navas);
1372 						newRDN[navas] = NULL;
1373 					}
1374 
1375 				}
1376 				rc = LDAP_SUCCESS;
1377 				goto return_result;
1378 			}
1379 
1380 			/* they should have been used in an AVA */
1381 			attrType.bv_val = NULL;
1382 			attrValue.bv_val = NULL;
1383 
1384 			p++;
1385 			state = B4AVA;
1386 			break;
1387 		}
1388 
1389 		default:
1390 			assert( 0 );
1391 			goto parsing_error;
1392 		}
1393 	}
1394 	*n = p;
1395 
1396 parsing_error:;
1397 	/* They are set to NULL after they're used in an AVA */
1398 
1399 	if ( attrValue.bv_val ) {
1400 		LDAP_FREEX( attrValue.bv_val, ctx );
1401 	}
1402 
1403 	for ( navas-- ; navas >= 0; navas-- ) {
1404 		ldapava_free( tmpRDN[navas], ctx );
1405 	}
1406 
1407 return_result:;
1408 
1409 	if ( tmpRDN != tmpRDN_ ) {
1410 		LDAP_FREEX( tmpRDN, ctx );
1411 	}
1412 
1413 	if ( rdn ) {
1414 		*rdn = newRDN;
1415 	}
1416 
1417 	return( rc );
1418 }
1419 
1420 /*
1421  * reads in a UTF-8 string value, unescaping stuff:
1422  * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1423  * '\' + HEXPAIR(p) -> unhex(p)
1424  */
1425 static int
1426 str2strval( const char *str, ber_len_t stoplen, struct berval *val, const char **next, unsigned flags, int *retFlags, void *ctx )
1427 {
1428 	const char 	*p, *end, *startPos, *endPos = NULL;
1429 	ber_len_t	len, escapes;
1430 
1431 	assert( str != NULL );
1432 	assert( val != NULL );
1433 	assert( next != NULL );
1434 
1435 	*next = NULL;
1436 	end = str + stoplen;
1437 	for ( startPos = p = str, escapes = 0; p < end; p++ ) {
1438 		if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1439 			p++;
1440 			if ( p[ 0 ] == '\0' ) {
1441 				return( 1 );
1442 			}
1443 			if ( LDAP_DN_MAYESCAPE( p[ 0 ] ) ) {
1444 				escapes++;
1445 				continue;
1446 			}
1447 
1448 			if ( LDAP_DN_HEXPAIR( p ) ) {
1449 				char c;
1450 
1451 				hexstr2bin( p, &c );
1452 				escapes += 2;
1453 
1454 				if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1455 
1456 					/*
1457 					 * we assume the string is UTF-8
1458 					 */
1459 					*retFlags = LDAP_AVA_NONPRINTABLE;
1460 				}
1461 				p++;
1462 
1463 				continue;
1464 			}
1465 
1466 			if ( LDAP_DN_PEDANTIC & flags ) {
1467 				return( 1 );
1468 			}
1469 			/*
1470 			 * we do not allow escaping
1471 			 * of chars that don't need
1472 			 * to and do not belong to
1473 			 * HEXDIGITS
1474 			 */
1475 			return( 1 );
1476 
1477 		} else if ( !LDAP_DN_ASCII_PRINTABLE( p[ 0 ] ) ) {
1478 			if ( p[ 0 ] == '\0' ) {
1479 				return( 1 );
1480 			}
1481 			*retFlags = LDAP_AVA_NONPRINTABLE;
1482 
1483 		} else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1484 				|| ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1485 			break;
1486 
1487 		} else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1488 			/*
1489 			 * FIXME: maybe we can add
1490 			 * escapes if not pedantic?
1491 			 */
1492 			return( 1 );
1493 		}
1494 	}
1495 
1496 	/*
1497 	 * we do allow unescaped spaces at the end
1498 	 * of the value only in non-pedantic mode
1499 	 */
1500 	if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1501 			!LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1502 		if ( flags & LDAP_DN_PEDANTIC ) {
1503 			return( 1 );
1504 		}
1505 
1506 		/* strip trailing (unescaped) spaces */
1507 		for ( endPos = p - 1;
1508 				endPos > startPos + 1 &&
1509 				LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1510 				!LDAP_DN_ESCAPE( endPos[ -2 ] );
1511 				endPos-- ) {
1512 			/* no op */
1513 		}
1514 	}
1515 
1516 	*next = p;
1517 	if ( flags & LDAP_DN_SKIP ) {
1518 		return( 0 );
1519 	}
1520 
1521 	/*
1522 	 * FIXME: test memory?
1523 	 */
1524 	len = ( endPos ? endPos : p ) - startPos - escapes;
1525 	val->bv_len = len;
1526 
1527 	if ( escapes == 0 ) {
1528 		if ( *retFlags & LDAP_AVA_NONPRINTABLE ) {
1529 			val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1530 			AC_MEMCPY( val->bv_val, startPos, len );
1531 			val->bv_val[ len ] = '\0';
1532 		} else {
1533 			val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1534 		}
1535 
1536 	} else {
1537 		ber_len_t	s, d;
1538 
1539 		val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1540 		for ( s = 0, d = 0; d < len; ) {
1541 			if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1542 				s++;
1543 				if ( LDAP_DN_MAYESCAPE( startPos[ s ] ) ) {
1544 					val->bv_val[ d++ ] =
1545 						startPos[ s++ ];
1546 
1547 				} else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1548 					char 	c;
1549 
1550 					hexstr2bin( &startPos[ s ], &c );
1551 					val->bv_val[ d++ ] = c;
1552 					s += 2;
1553 
1554 				} else {
1555 					/* we should never get here */
1556 					assert( 0 );
1557 				}
1558 
1559 			} else {
1560 				val->bv_val[ d++ ] = startPos[ s++ ];
1561 			}
1562 		}
1563 
1564 		val->bv_val[ d ] = '\0';
1565 		assert( d == len );
1566 	}
1567 
1568 	return( 0 );
1569 }
1570 
1571 static int
1572 DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1573 {
1574 	const char 	*p, *startPos, *endPos = NULL;
1575 	ber_len_t	len, escapes;
1576 
1577 	assert( str != NULL );
1578 	assert( val != NULL );
1579 	assert( next != NULL );
1580 
1581 	*next = NULL;
1582 
1583 	for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1584 		if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1585 			p++;
1586 			if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1587 				escapes++;
1588 
1589 			} else {
1590 				return( 1 );
1591 			}
1592 
1593 		} else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1594 			break;
1595 		}
1596 
1597 		/*
1598 		 * FIXME: can we accept anything else? I guess we need
1599 		 * to stop if a value is not legal
1600 		 */
1601 	}
1602 
1603 	/*
1604 	 * (unescaped) trailing spaces are trimmed must be silently ignored;
1605 	 * so we eat them
1606 	 */
1607 	if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1608 			!LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1609 		if ( flags & LDAP_DN_PEDANTIC ) {
1610 			return( 1 );
1611 		}
1612 
1613 		/* strip trailing (unescaped) spaces */
1614 		for ( endPos = p - 1;
1615 				endPos > startPos + 1 &&
1616 				LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1617 				!LDAP_DN_ESCAPE( endPos[ -2 ] );
1618 				endPos-- ) {
1619 			/* no op */
1620 		}
1621 	}
1622 
1623 	*next = p;
1624 	if ( flags & LDAP_DN_SKIP ) {
1625 		return( 0 );
1626 	}
1627 
1628 	len = ( endPos ? endPos : p ) - startPos - escapes;
1629 	val->bv_len = len;
1630 	if ( escapes == 0 ){
1631 		val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1632 
1633 	} else {
1634 		ber_len_t	s, d;
1635 
1636 		val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1637 		for ( s = 0, d = 0; d < len; ) {
1638 			/*
1639 			 * This point is reached only if escapes
1640 			 * are properly used, so all we need to
1641 			 * do is eat them
1642 			 */
1643 			if (  LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1644 				s++;
1645 
1646 			}
1647 			val->bv_val[ d++ ] = startPos[ s++ ];
1648 		}
1649 		val->bv_val[ d ] = '\0';
1650 		assert( strlen( val->bv_val ) == len );
1651 	}
1652 
1653 	return( 0 );
1654 }
1655 
1656 static int
1657 IA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1658 {
1659 	const char 	*p, *startPos, *endPos = NULL;
1660 	ber_len_t	len, escapes;
1661 
1662 	assert( str != NULL );
1663 	assert( val != NULL );
1664 	assert( next != NULL );
1665 
1666 	*next = NULL;
1667 
1668 	/*
1669 	 * LDAPv2 (RFC 1779)
1670 	 */
1671 
1672 	for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1673 		if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1674 			p++;
1675 			if ( p[ 0 ] == '\0' ) {
1676 				return( 1 );
1677 			}
1678 
1679 			if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1680 					&& ( LDAP_DN_PEDANTIC & flags ) ) {
1681 				return( 1 );
1682 			}
1683 			escapes++;
1684 
1685 		} else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1686 			break;
1687 		}
1688 
1689 		/*
1690 		 * FIXME: can we accept anything else? I guess we need
1691 		 * to stop if a value is not legal
1692 		 */
1693 	}
1694 
1695 	/* strip trailing (unescaped) spaces */
1696 	for ( endPos = p;
1697 			endPos > startPos + 1 &&
1698 			LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1699 			!LDAP_DN_ESCAPE( endPos[ -2 ] );
1700 			endPos-- ) {
1701 		/* no op */
1702 	}
1703 
1704 	*next = p;
1705 	if ( flags & LDAP_DN_SKIP ) {
1706 		return( 0 );
1707 	}
1708 
1709 	len = ( endPos ? endPos : p ) - startPos - escapes;
1710 	val->bv_len = len;
1711 	if ( escapes == 0 ) {
1712 		val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1713 
1714 	} else {
1715 		ber_len_t	s, d;
1716 
1717 		val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1718 		for ( s = 0, d = 0; d < len; ) {
1719 			if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1720 				s++;
1721 			}
1722 			val->bv_val[ d++ ] = startPos[ s++ ];
1723 		}
1724 		val->bv_val[ d ] = '\0';
1725 		assert( strlen( val->bv_val ) == len );
1726 	}
1727 
1728 	return( 0 );
1729 }
1730 
1731 static int
1732 quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1733 {
1734 	const char 	*p, *startPos, *endPos = NULL;
1735 	ber_len_t	len;
1736 	unsigned	escapes = 0;
1737 
1738 	assert( str != NULL );
1739 	assert( val != NULL );
1740 	assert( next != NULL );
1741 
1742 	*next = NULL;
1743 
1744 	/* initial quote already eaten */
1745 	for ( startPos = p = str; p[ 0 ]; p++ ) {
1746 		/*
1747 		 * According to RFC 1779, the quoted value can
1748 		 * contain escaped as well as unescaped special values;
1749 		 * as a consequence we tolerate escaped values
1750 		 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1751 		 * (e.g. '","' -> '\,').
1752 		 */
1753 		if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1754 			if ( p[ 1 ] == '\0' ) {
1755 				return( 1 );
1756 			}
1757 			p++;
1758 
1759 			if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1760 					&& ( LDAP_DN_PEDANTIC & flags ) ) {
1761 				/*
1762 				 * do we allow to escape normal chars?
1763 				 * LDAPv2 does not allow any mechanism
1764 				 * for escaping chars with '\' and hex
1765 				 * pair
1766 				 */
1767 				return( 1 );
1768 			}
1769 			escapes++;
1770 
1771 		} else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1772 			endPos = p;
1773 			/* eat closing quotes */
1774 			p++;
1775 			break;
1776 		}
1777 
1778 		/*
1779 		 * FIXME: can we accept anything else? I guess we need
1780 		 * to stop if a value is not legal
1781 		 */
1782 	}
1783 
1784 	if ( endPos == NULL ) {
1785 		return( 1 );
1786 	}
1787 
1788 	/* Strip trailing (unescaped) spaces */
1789 	for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1790 		/* no op */
1791 	}
1792 
1793 	*next = p;
1794 	if ( flags & LDAP_DN_SKIP ) {
1795 		return( 0 );
1796 	}
1797 
1798 	len = endPos - startPos - escapes;
1799 	assert( endPos >= startPos + escapes );
1800 	val->bv_len = len;
1801 	if ( escapes == 0 ) {
1802 		val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1803 
1804 	} else {
1805 		ber_len_t	s, d;
1806 
1807 		val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1808 		val->bv_len = len;
1809 
1810 		for ( s = d = 0; d < len; ) {
1811 			if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1812 				s++;
1813 			}
1814 			val->bv_val[ d++ ] = str[ s++ ];
1815 		}
1816 		val->bv_val[ d ] = '\0';
1817 		assert( strlen( val->bv_val ) == len );
1818 	}
1819 
1820 	return( 0 );
1821 }
1822 
1823 static int
1824 hexstr2bin( const char *str, char *c )
1825 {
1826 	char	c1, c2;
1827 
1828 	assert( str != NULL );
1829 	assert( c != NULL );
1830 
1831 	c1 = str[ 0 ];
1832 	c2 = str[ 1 ];
1833 
1834 	if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1835 		*c = c1 - '0';
1836 
1837 	} else {
1838 		if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) {
1839 			*c = c1 - 'A' + 10;
1840 		} else {
1841 			assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) );
1842 			*c = c1 - 'a' + 10;
1843 		}
1844 	}
1845 
1846 	*c <<= 4;
1847 
1848 	if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1849 		*c += c2 - '0';
1850 
1851 	} else {
1852 		if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) {
1853 			*c += c2 - 'A' + 10;
1854 		} else {
1855 			assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) );
1856 			*c += c2 - 'a' + 10;
1857 		}
1858 	}
1859 
1860 	return( 0 );
1861 }
1862 
1863 static int
1864 hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1865 {
1866 	const char 	*p, *startPos, *endPos = NULL;
1867 	ber_len_t	len;
1868 	ber_len_t	s, d;
1869 
1870 	assert( str != NULL );
1871 	assert( val != NULL );
1872 	assert( next != NULL );
1873 
1874 	*next = NULL;
1875 
1876 	for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1877 		switch ( LDAP_DN_FORMAT( flags ) ) {
1878 		case LDAP_DN_FORMAT_LDAPV3:
1879 			if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1880 				goto end_of_value;
1881 			}
1882 			break;
1883 
1884 		case LDAP_DN_FORMAT_LDAP:
1885 		case LDAP_DN_FORMAT_LDAPV2:
1886 			if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1887 				goto end_of_value;
1888 			}
1889 			break;
1890 
1891 		case LDAP_DN_FORMAT_DCE:
1892 			if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1893 				goto end_of_value;
1894 			}
1895 			break;
1896 		}
1897 
1898 		if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1899 			if ( flags & LDAP_DN_PEDANTIC ) {
1900 				return( 1 );
1901 			}
1902 			endPos = p;
1903 
1904 			for ( ; p[ 0 ]; p++ ) {
1905 				switch ( LDAP_DN_FORMAT( flags ) ) {
1906 				case LDAP_DN_FORMAT_LDAPV3:
1907 					if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1908 						goto end_of_value;
1909 					}
1910 					break;
1911 
1912 				case LDAP_DN_FORMAT_LDAP:
1913 				case LDAP_DN_FORMAT_LDAPV2:
1914 					if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1915 						goto end_of_value;
1916 					}
1917 					break;
1918 
1919 				case LDAP_DN_FORMAT_DCE:
1920 					if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1921 						goto end_of_value;
1922 					}
1923 					break;
1924 				}
1925 			}
1926 			break;
1927 		}
1928 
1929 		if ( !LDAP_DN_HEXPAIR( p ) ) {
1930 			return( 1 );
1931 		}
1932 	}
1933 
1934 end_of_value:;
1935 
1936 	*next = p;
1937 	if ( flags & LDAP_DN_SKIP ) {
1938 		return( 0 );
1939 	}
1940 
1941 	len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1942 	/* must be even! */
1943 	assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1944 
1945 	val->bv_len = len;
1946 	val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1947 	if ( val->bv_val == NULL ) {
1948 		return( LDAP_NO_MEMORY );
1949 	}
1950 
1951 	for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1952 		char 	c;
1953 
1954 		hexstr2bin( &startPos[ s ], &c );
1955 
1956 		val->bv_val[ d ] = c;
1957 	}
1958 
1959 	val->bv_val[ d ] = '\0';
1960 
1961 	return( 0 );
1962 }
1963 
1964 /*
1965  * convert a byte in a hexadecimal pair
1966  */
1967 static int
1968 byte2hexpair( const char *val, char *pair )
1969 {
1970 	static const char	hexdig[] = "0123456789ABCDEF";
1971 
1972 	assert( val != NULL );
1973 	assert( pair != NULL );
1974 
1975 	/*
1976 	 * we assume the string has enough room for the hex encoding
1977 	 * of the value
1978 	 */
1979 
1980 	pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1981 	pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1982 
1983 	return( 0 );
1984 }
1985 
1986 /*
1987  * convert a binary value in hexadecimal pairs
1988  */
1989 static int
1990 binval2hexstr( struct berval *val, char *str )
1991 {
1992 	ber_len_t	s, d;
1993 
1994 	assert( val != NULL );
1995 	assert( str != NULL );
1996 
1997 	if ( val->bv_len == 0 ) {
1998 		return( 0 );
1999 	}
2000 
2001 	/*
2002 	 * we assume the string has enough room for the hex encoding
2003 	 * of the value
2004 	 */
2005 
2006 	for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
2007 		byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2008 	}
2009 
2010 	return( 0 );
2011 }
2012 
2013 /*
2014  * Length of the string representation, accounting for escaped hex
2015  * of UTF-8 chars
2016  */
2017 static int
2018 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
2019 {
2020 	ber_len_t	l, cl = 1;
2021 	char		*p, *end;
2022 	int		escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
2023 #ifdef PRETTY_ESCAPE
2024 	int		escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
2025 #endif /* PRETTY_ESCAPE */
2026 
2027 	assert( val != NULL );
2028 	assert( len != NULL );
2029 
2030 	*len = 0;
2031 	if ( val->bv_len == 0 ) {
2032 		return( 0 );
2033 	}
2034 
2035 	end = val->bv_val + val->bv_len - 1;
2036 	for ( l = 0, p = val->bv_val; p <= end; p += cl ) {
2037 
2038 		/*
2039 		 * escape '%x00'
2040 		 */
2041 		if ( p[ 0 ] == '\0' ) {
2042 			cl = 1;
2043 			l += 3;
2044 			continue;
2045 		}
2046 
2047 		cl = LDAP_UTF8_CHARLEN2( p, cl );
2048 		if ( cl == 0 ) {
2049 			/* illegal utf-8 char! */
2050 			return( -1 );
2051 
2052 		} else if ( cl > 1 ) {
2053 			ber_len_t cnt;
2054 
2055 			for ( cnt = 1; cnt < cl; cnt++ ) {
2056 				if ( ( p[ cnt ] & 0xc0 ) != 0x80 ) {
2057 					return( -1 );
2058 				}
2059 			}
2060 			l += escaped_byte_len * cl;
2061 
2062 		} else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2063 				|| LDAP_DN_SHOULDESCAPE( p[ 0 ] )
2064 				|| ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2065 				|| ( p == end && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2066 #ifdef PRETTY_ESCAPE
2067 #if 0
2068 			if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
2069 #else
2070 			if ( LDAP_DN_WILLESCAPE_CHAR( p[ 0 ] ) ) {
2071 #endif
2072 
2073 				/*
2074 				 * there might be some chars we want
2075 				 * to escape in form of a couple
2076 				 * of hexdigits for optimization purposes
2077 				 */
2078 				l += 3;
2079 
2080 			} else {
2081 				l += escaped_ascii_len;
2082 			}
2083 #else /* ! PRETTY_ESCAPE */
2084 			l += 3;
2085 #endif /* ! PRETTY_ESCAPE */
2086 
2087 		} else {
2088 			l++;
2089 		}
2090 	}
2091 
2092 	*len = l;
2093 
2094 	return( 0 );
2095 }
2096 
2097 /*
2098  * convert to string representation, escaping with hex the UTF-8 stuff;
2099  * assume the destination has enough room for escaping
2100  */
2101 static int
2102 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2103 {
2104 	ber_len_t	s, d, end;
2105 
2106 	assert( val != NULL );
2107 	assert( str != NULL );
2108 	assert( len != NULL );
2109 
2110 	if ( val->bv_len == 0 ) {
2111 		*len = 0;
2112 		return( 0 );
2113 	}
2114 
2115 	/*
2116 	 * we assume the string has enough room for the hex encoding
2117 	 * of the value
2118 	 */
2119 	for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2120 		ber_len_t	cl;
2121 
2122 		/*
2123 		 * escape '%x00'
2124 		 */
2125 		if ( val->bv_val[ s ] == '\0' ) {
2126 			cl = 1;
2127 			str[ d++ ] = '\\';
2128 			str[ d++ ] = '0';
2129 			str[ d++ ] = '0';
2130 			s++;
2131 			continue;
2132 		}
2133 
2134 		/*
2135 		 * The length was checked in strval2strlen();
2136 		 */
2137 		cl = LDAP_UTF8_CHARLEN( &val->bv_val[ s ] );
2138 
2139 		/*
2140 		 * there might be some chars we want to escape in form
2141 		 * of a couple of hexdigits for optimization purposes
2142 		 */
2143 		if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) )
2144 #ifdef PRETTY_ESCAPE
2145 #if 0
2146 				|| LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] )
2147 #else
2148 				|| LDAP_DN_WILLESCAPE_CHAR( val->bv_val[ s ] )
2149 #endif
2150 #else /* ! PRETTY_ESCAPE */
2151 				|| LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2152 				|| LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] )
2153 				|| ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2154 				|| ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
2155 
2156 #endif /* ! PRETTY_ESCAPE */
2157 				) {
2158 			for ( ; cl--; ) {
2159 				str[ d++ ] = '\\';
2160 				byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2161 				s++;
2162 				d += 2;
2163 			}
2164 
2165 		} else if ( cl > 1 ) {
2166 			for ( ; cl--; ) {
2167 				str[ d++ ] = val->bv_val[ s++ ];
2168 			}
2169 
2170 		} else {
2171 #ifdef PRETTY_ESCAPE
2172 			if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2173 					|| LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] )
2174 					|| ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2175 					|| ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2176 				str[ d++ ] = '\\';
2177 				if ( !LDAP_DN_IS_PRETTY( flags ) ) {
2178 					byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2179 					s++;
2180 					d += 2;
2181 					continue;
2182 				}
2183 			}
2184 #endif /* PRETTY_ESCAPE */
2185 			str[ d++ ] = val->bv_val[ s++ ];
2186 		}
2187 	}
2188 
2189 	*len = d;
2190 
2191 	return( 0 );
2192 }
2193 
2194 /*
2195  * Length of the IA5 string representation (no UTF-8 allowed)
2196  */
2197 static int
2198 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2199 {
2200 	ber_len_t	l;
2201 	char		*p;
2202 
2203 	assert( val != NULL );
2204 	assert( len != NULL );
2205 
2206 	*len = 0;
2207 	if ( val->bv_len == 0 ) {
2208 		return( 0 );
2209 	}
2210 
2211 	if ( flags & LDAP_AVA_NONPRINTABLE ) {
2212 		/*
2213 		 * Turn value into a binary encoded BER
2214 		 */
2215 		return( -1 );
2216 
2217 	} else {
2218 		for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2219 			if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2220 					|| LDAP_DN_SHOULDESCAPE( p[ 0 ] )
2221 					|| ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2222 					|| ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2223 				l += 2;
2224 
2225 			} else {
2226 				l++;
2227 			}
2228 		}
2229 	}
2230 
2231 	*len = l;
2232 
2233 	return( 0 );
2234 }
2235 
2236 /*
2237  * convert to string representation (np UTF-8)
2238  * assume the destination has enough room for escaping
2239  */
2240 static int
2241 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2242 {
2243 	ber_len_t	s, d, end;
2244 
2245 	assert( val != NULL );
2246 	assert( str != NULL );
2247 	assert( len != NULL );
2248 
2249 	if ( val->bv_len == 0 ) {
2250 		*len = 0;
2251 		return( 0 );
2252 	}
2253 
2254 	if ( flags & LDAP_AVA_NONPRINTABLE ) {
2255 		/*
2256 		 * Turn value into a binary encoded BER
2257 		 */
2258 		*len = 0;
2259 		return( -1 );
2260 
2261 	} else {
2262 		/*
2263 		 * we assume the string has enough room for the hex encoding
2264 		 * of the value
2265 		 */
2266 
2267 		for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2268 			if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2269 					|| LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] )
2270 					|| ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2271 					|| ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2272 				str[ d++ ] = '\\';
2273 			}
2274 			str[ d++ ] = val->bv_val[ s++ ];
2275 		}
2276 	}
2277 
2278 	*len = d;
2279 
2280 	return( 0 );
2281 }
2282 
2283 /*
2284  * Length of the (supposedly) DCE string representation,
2285  * accounting for escaped hex of UTF-8 chars
2286  */
2287 static int
2288 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2289 {
2290 	ber_len_t	l;
2291 	char		*p;
2292 
2293 	assert( val != NULL );
2294 	assert( len != NULL );
2295 
2296 	*len = 0;
2297 	if ( val->bv_len == 0 ) {
2298 		return( 0 );
2299 	}
2300 
2301 	if ( flags & LDAP_AVA_NONPRINTABLE ) {
2302 		/*
2303 		 * FIXME: Turn the value into a binary encoded BER?
2304 		 */
2305 		return( -1 );
2306 
2307 	} else {
2308 		for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2309 			if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2310 				l += 2;
2311 
2312 			} else {
2313 				l++;
2314 			}
2315 		}
2316 	}
2317 
2318 	*len = l;
2319 
2320 	return( 0 );
2321 }
2322 
2323 /*
2324  * convert to (supposedly) DCE string representation,
2325  * escaping with hex the UTF-8 stuff;
2326  * assume the destination has enough room for escaping
2327  */
2328 static int
2329 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2330 {
2331 	ber_len_t	s, d;
2332 
2333 	assert( val != NULL );
2334 	assert( str != NULL );
2335 	assert( len != NULL );
2336 
2337 	if ( val->bv_len == 0 ) {
2338 		*len = 0;
2339 		return( 0 );
2340 	}
2341 
2342 	if ( flags & LDAP_AVA_NONPRINTABLE ) {
2343 		/*
2344 		 * FIXME: Turn the value into a binary encoded BER?
2345 		 */
2346 		*len = 0;
2347 		return( -1 );
2348 
2349 	} else {
2350 
2351 		/*
2352 		 * we assume the string has enough room for the hex encoding
2353 		 * of the value
2354 		 */
2355 
2356 		for ( s = 0, d = 0; s < val->bv_len; ) {
2357 			if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2358 				str[ d++ ] = '\\';
2359 			}
2360 			str[ d++ ] = val->bv_val[ s++ ];
2361 		}
2362 	}
2363 
2364 	*len = d;
2365 
2366 	return( 0 );
2367 }
2368 
2369 /*
2370  * Length of the (supposedly) AD canonical string representation,
2371  * accounting for chars that need to be escaped
2372  */
2373 static int
2374 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2375 {
2376 	ber_len_t	l, cl;
2377 	char		*p;
2378 
2379 	assert( val != NULL );
2380 	assert( len != NULL );
2381 
2382 	*len = 0;
2383 	if ( val->bv_len == 0 ) {
2384 		return( 0 );
2385 	}
2386 
2387 	for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
2388 		cl = LDAP_UTF8_CHARLEN2( p, cl );
2389 		if ( cl == 0 ) {
2390 			/* illegal utf-8 char */
2391 			return -1;
2392 		} else if ( (cl == 1) && LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2393 			l += 2;
2394 		} else {
2395 			l += cl;
2396 		}
2397 	}
2398 
2399 	*len = l;
2400 
2401 	return( 0 );
2402 }
2403 
2404 /*
2405  * convert to (supposedly) AD string representation,
2406  * assume the destination has enough room for escaping
2407  */
2408 static int
2409 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2410 {
2411 	ber_len_t	s, d, cl;
2412 
2413 	assert( val != NULL );
2414 	assert( str != NULL );
2415 	assert( len != NULL );
2416 
2417 	if ( val->bv_len == 0 ) {
2418 		*len = 0;
2419 		return( 0 );
2420 	}
2421 
2422 	/*
2423 	 * we assume the string has enough room for the escaping
2424 	 * of the value
2425 	 */
2426 
2427 	for ( s = 0, d = 0; s < val->bv_len; ) {
2428 		cl = LDAP_UTF8_CHARLEN2( val->bv_val+s, cl );
2429 		if ( cl == 0 ) {
2430 			/* illegal utf-8 char */
2431 			return -1;
2432 		} else if ( (cl == 1) && LDAP_DN_NEEDESCAPE_AD(val->bv_val[ s ]) ) {
2433 			str[ d++ ] = '\\';
2434 		}
2435 		for (; cl--;) {
2436 			str[ d++ ] = val->bv_val[ s++ ];
2437 		}
2438 	}
2439 
2440 	*len = d;
2441 
2442 	return( 0 );
2443 }
2444 
2445 /*
2446  * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2447  * the first part of the AD representation of the DN is written in DNS
2448  * form, i.e. dot separated domain name components (as suggested
2449  * by Luke Howard, http://www.padl.com/~lukeh)
2450  */
2451 static int
2452 dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN )
2453 {
2454 	int 		i;
2455 	int		domain = 0, first = 1;
2456 	ber_len_t	l = 1; /* we move the null also */
2457 	char		*str;
2458 
2459 	/* we are guaranteed there's enough memory in str */
2460 
2461 	/* sanity */
2462 	assert( dn != NULL );
2463 	assert( bv != NULL );
2464 	assert( iRDN != NULL );
2465 	assert( *iRDN >= 0 );
2466 
2467 	str = bv->bv_val + pos;
2468 
2469 	for ( i = *iRDN; i >= 0; i-- ) {
2470 		LDAPRDN		rdn;
2471 		LDAPAVA		*ava;
2472 
2473 		assert( dn[ i ] != NULL );
2474 		rdn = dn[ i ];
2475 
2476 		assert( rdn[ 0 ] != NULL );
2477 		ava = rdn[ 0 ];
2478 
2479 		if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2480 			break;
2481 		}
2482 
2483 		domain = 1;
2484 
2485 		if ( first ) {
2486 			first = 0;
2487 			AC_MEMCPY( str, ava->la_value.bv_val,
2488 					ava->la_value.bv_len + 1);
2489 			l += ava->la_value.bv_len;
2490 
2491 		} else {
2492 			AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val + pos, l);
2493 			AC_MEMCPY( str, ava->la_value.bv_val,
2494 					ava->la_value.bv_len );
2495 			str[ ava->la_value.bv_len ] = '.';
2496 			l += ava->la_value.bv_len + 1;
2497 		}
2498 	}
2499 
2500 	*iRDN = i;
2501 	bv->bv_len = pos + l - 1;
2502 
2503 	return( domain );
2504 }
2505 
2506 static int
2507 rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len,
2508 	 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2509 {
2510 	int		iAVA;
2511 	ber_len_t	l = 0;
2512 
2513 	*len = 0;
2514 
2515 	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2516 		LDAPAVA		*ava = rdn[ iAVA ];
2517 
2518 		/* len(type) + '=' + '+' | ',' */
2519 		l += ava->la_attr.bv_len + 2;
2520 
2521 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
2522 			/* octothorpe + twice the length */
2523 			l += 1 + 2 * ava->la_value.bv_len;
2524 
2525 		} else {
2526 			ber_len_t	vl;
2527 			unsigned	f = flags | ava->la_flags;
2528 
2529 			if ( ( *s2l )( &ava->la_value, f, &vl ) ) {
2530 				return( -1 );
2531 			}
2532 			l += vl;
2533 		}
2534 	}
2535 
2536 	*len = l;
2537 
2538 	return( 0 );
2539 }
2540 
2541 static int
2542 rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len,
2543 	int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2544 {
2545 	int		iAVA;
2546 	ber_len_t	l = 0;
2547 
2548 	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2549 		LDAPAVA		*ava = rdn[ iAVA ];
2550 
2551 		AC_MEMCPY( &str[ l ], ava->la_attr.bv_val,
2552 				ava->la_attr.bv_len );
2553 		l += ava->la_attr.bv_len;
2554 
2555 		str[ l++ ] = '=';
2556 
2557 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
2558 			str[ l++ ] = '#';
2559 			if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2560 				return( -1 );
2561 			}
2562 			l += 2 * ava->la_value.bv_len;
2563 
2564 		} else {
2565 			ber_len_t	vl;
2566 			unsigned	f = flags | ava->la_flags;
2567 
2568 			if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) {
2569 				return( -1 );
2570 			}
2571 			l += vl;
2572 		}
2573 		str[ l++ ] = ( rdn[ iAVA + 1] ? '+' : ',' );
2574 	}
2575 
2576 	*len = l;
2577 
2578 	return( 0 );
2579 }
2580 
2581 static int
2582 rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
2583 {
2584 	int		iAVA;
2585 	ber_len_t	l = 0;
2586 
2587 	*len = 0;
2588 
2589 	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2590 		LDAPAVA		*ava = rdn[ iAVA ];
2591 
2592 		/* len(type) + '=' + ',' | '/' */
2593 		l += ava->la_attr.bv_len + 2;
2594 
2595 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
2596 			/* octothorpe + twice the length */
2597 			l += 1 + 2 * ava->la_value.bv_len;
2598 		} else {
2599 			ber_len_t	vl;
2600 			unsigned	f = flags | ava->la_flags;
2601 
2602 			if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) {
2603 				return( -1 );
2604 			}
2605 			l += vl;
2606 		}
2607 	}
2608 
2609 	*len = l;
2610 
2611 	return( 0 );
2612 }
2613 
2614 static int
2615 rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first )
2616 {
2617 	int		iAVA;
2618 	ber_len_t	l = 0;
2619 
2620 	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2621 		LDAPAVA		*ava = rdn[ iAVA ];
2622 
2623 		if ( first ) {
2624 			first = 0;
2625 		} else {
2626 			str[ l++ ] = ( iAVA ? ',' : '/' );
2627 		}
2628 
2629 		AC_MEMCPY( &str[ l ], ava->la_attr.bv_val,
2630 				ava->la_attr.bv_len );
2631 		l += ava->la_attr.bv_len;
2632 
2633 		str[ l++ ] = '=';
2634 
2635 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
2636 			str[ l++ ] = '#';
2637 			if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2638 				return( -1 );
2639 			}
2640 			l += 2 * ava->la_value.bv_len;
2641 		} else {
2642 			ber_len_t	vl;
2643 			unsigned	f = flags | ava->la_flags;
2644 
2645 			if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2646 				return( -1 );
2647 			}
2648 			l += vl;
2649 		}
2650 	}
2651 
2652 	*len = l;
2653 
2654 	return( 0 );
2655 }
2656 
2657 static int
2658 rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
2659 {
2660 	int		iAVA;
2661 	ber_len_t	l = 0;
2662 
2663 	assert( rdn != NULL );
2664 	assert( len != NULL );
2665 
2666 	*len = 0;
2667 
2668 	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2669 		LDAPAVA		*ava = rdn[ iAVA ];
2670 
2671 		/* ' + ' | ', ' */
2672 		l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2673 
2674 		/* FIXME: are binary values allowed in UFN? */
2675 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
2676 			/* octothorpe + twice the value */
2677 			l += 1 + 2 * ava->la_value.bv_len;
2678 
2679 		} else {
2680 			ber_len_t	vl;
2681 			unsigned	f = flags | ava->la_flags;
2682 
2683 			if ( strval2strlen( &ava->la_value, f, &vl ) ) {
2684 				return( -1 );
2685 			}
2686 			l += vl;
2687 		}
2688 	}
2689 
2690 	*len = l;
2691 
2692 	return( 0 );
2693 }
2694 
2695 static int
2696 rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len )
2697 {
2698 	int		iAVA;
2699 	ber_len_t	l = 0;
2700 
2701 	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2702 		LDAPAVA		*ava = rdn[ iAVA ];
2703 
2704 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
2705 			str[ l++ ] = '#';
2706 			if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2707 				return( -1 );
2708 			}
2709 			l += 2 * ava->la_value.bv_len;
2710 
2711 		} else {
2712 			ber_len_t	vl;
2713 			unsigned	f = flags | ava->la_flags;
2714 
2715 			if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) {
2716 				return( -1 );
2717 			}
2718 			l += vl;
2719 		}
2720 
2721 		if ( rdn[ iAVA + 1 ] ) {
2722 			AC_MEMCPY( &str[ l ], " + ", 3 );
2723 			l += 3;
2724 
2725 		} else {
2726 			AC_MEMCPY( &str[ l ], ", ", 2 );
2727 			l += 2;
2728 		}
2729 	}
2730 
2731 	*len = l;
2732 
2733 	return( 0 );
2734 }
2735 
2736 static int
2737 rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
2738 {
2739 	int		iAVA;
2740 	ber_len_t	l = 0;
2741 
2742 	assert( rdn != NULL );
2743 	assert( len != NULL );
2744 
2745 	*len = 0;
2746 
2747 	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2748 		LDAPAVA		*ava = rdn[ iAVA ];
2749 
2750 		/* ',' | '/' */
2751 		l++;
2752 
2753 		/* FIXME: are binary values allowed in UFN? */
2754 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
2755 			/* octothorpe + twice the value */
2756 			l += 1 + 2 * ava->la_value.bv_len;
2757 		} else {
2758 			ber_len_t	vl;
2759 			unsigned	f = flags | ava->la_flags;
2760 
2761 			if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) {
2762 				return( -1 );
2763 			}
2764 			l += vl;
2765 		}
2766 	}
2767 
2768 	*len = l;
2769 
2770 	return( 0 );
2771 }
2772 
2773 static int
2774 rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first )
2775 {
2776 	int		iAVA;
2777 	ber_len_t	l = 0;
2778 
2779 	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2780 		LDAPAVA		*ava = rdn[ iAVA ];
2781 
2782 		if ( first ) {
2783 			first = 0;
2784 		} else {
2785 			str[ l++ ] = ( iAVA ? ',' : '/' );
2786 		}
2787 
2788 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
2789 			str[ l++ ] = '#';
2790 			if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2791 				return( -1 );
2792 			}
2793 			l += 2 * ava->la_value.bv_len;
2794 		} else {
2795 			ber_len_t	vl;
2796 			unsigned	f = flags | ava->la_flags;
2797 
2798 			if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2799 				return( -1 );
2800 			}
2801 			l += vl;
2802 		}
2803 	}
2804 
2805 	*len = l;
2806 
2807 	return( 0 );
2808 }
2809 
2810 /*
2811  * ldap_rdn2str
2812  *
2813  * Returns in str a string representation of rdn based on flags.
2814  * There is some duplication of code between this and ldap_dn2str;
2815  * this is wanted to reduce the allocation of temporary buffers.
2816  */
2817 int
2818 ldap_rdn2str( LDAPRDN rdn, char **str, unsigned flags )
2819 {
2820 	struct berval bv;
2821 	int rc;
2822 
2823 	assert( str != NULL );
2824 
2825 	if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
2826 		return LDAP_PARAM_ERROR;
2827 	}
2828 
2829 	rc = ldap_rdn2bv_x( rdn, &bv, flags, NULL );
2830 	*str = bv.bv_val;
2831 	return rc;
2832 }
2833 
2834 int
2835 ldap_rdn2bv( LDAPRDN rdn, struct berval *bv, unsigned flags )
2836 {
2837 	return ldap_rdn2bv_x( rdn, bv, flags, NULL );
2838 }
2839 
2840 int
2841 ldap_rdn2bv_x( LDAPRDN rdn, struct berval *bv, unsigned flags, void *ctx )
2842 {
2843 	int		rc, back;
2844 	ber_len_t	l;
2845 
2846 	assert( bv != NULL );
2847 
2848 	bv->bv_len = 0;
2849 	bv->bv_val = NULL;
2850 
2851 	if ( rdn == NULL ) {
2852 		bv->bv_val = LDAP_STRDUPX( "", ctx );
2853 		return( LDAP_SUCCESS );
2854 	}
2855 
2856 	/*
2857 	 * This routine wastes "back" bytes at the end of the string
2858 	 */
2859 
2860 	switch ( LDAP_DN_FORMAT( flags ) ) {
2861 	case LDAP_DN_FORMAT_LDAPV3:
2862 		if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2863 			return LDAP_DECODING_ERROR;
2864 		}
2865 		break;
2866 
2867 	case LDAP_DN_FORMAT_LDAPV2:
2868 		if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2869 			return LDAP_DECODING_ERROR;
2870 		}
2871 		break;
2872 
2873 	case LDAP_DN_FORMAT_UFN:
2874 		if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2875 			return LDAP_DECODING_ERROR;
2876 		}
2877 		break;
2878 
2879 	case LDAP_DN_FORMAT_DCE:
2880 		if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2881 			return LDAP_DECODING_ERROR;
2882 		}
2883 		break;
2884 
2885 	case LDAP_DN_FORMAT_AD_CANONICAL:
2886 		if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2887 			return LDAP_DECODING_ERROR;
2888 		}
2889 		break;
2890 
2891 	default:
2892 		return LDAP_PARAM_ERROR;
2893 	}
2894 
2895 	bv->bv_val = LDAP_MALLOCX( l + 1, ctx );
2896 
2897 	switch ( LDAP_DN_FORMAT( flags ) ) {
2898 	case LDAP_DN_FORMAT_LDAPV3:
2899 		rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str );
2900 		back = 1;
2901 		break;
2902 
2903 	case LDAP_DN_FORMAT_LDAPV2:
2904 		rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str );
2905 		back = 1;
2906 		break;
2907 
2908 	case LDAP_DN_FORMAT_UFN:
2909 		rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l );
2910 		back = 2;
2911 		break;
2912 
2913 	case LDAP_DN_FORMAT_DCE:
2914 		rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 );
2915 		back = 0;
2916 		break;
2917 
2918 	case LDAP_DN_FORMAT_AD_CANONICAL:
2919 		rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 );
2920 		back = 0;
2921 		break;
2922 
2923 	default:
2924 		/* need at least one of the previous */
2925 		return LDAP_PARAM_ERROR;
2926 	}
2927 
2928 	if ( rc ) {
2929 		LDAP_FREEX( bv->bv_val, ctx );
2930 		return rc;
2931 	}
2932 
2933 	bv->bv_len = l - back;
2934 	bv->bv_val[ bv->bv_len ] = '\0';
2935 
2936 	return LDAP_SUCCESS;
2937 }
2938 
2939 /*
2940  * Very bulk implementation; many optimizations can be performed
2941  *   - a NULL dn results in an empty string ""
2942  *
2943  * FIXME: doubts
2944  *   a) what do we do if a UTF-8 string must be converted in LDAPv2?
2945  *      we must encode it in binary form ('#' + HEXPAIRs)
2946  *   b) does DCE/AD support UTF-8?
2947  *      no clue; don't think so.
2948  *   c) what do we do when binary values must be converted in UTF/DCE/AD?
2949  *      use binary encoded BER
2950  */
2951 int ldap_dn2str( LDAPDN dn, char **str, unsigned flags )
2952 {
2953 	struct berval bv;
2954 	int rc;
2955 
2956 	assert( str != NULL );
2957 
2958 	if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
2959 		return LDAP_PARAM_ERROR;
2960 	}
2961 
2962 	rc = ldap_dn2bv_x( dn, &bv, flags, NULL );
2963 	*str = bv.bv_val;
2964 	return rc;
2965 }
2966 
2967 int ldap_dn2bv( LDAPDN dn, struct berval *bv, unsigned flags )
2968 {
2969 	return ldap_dn2bv_x( dn, bv, flags, NULL );
2970 }
2971 
2972 int ldap_dn2bv_x( LDAPDN dn, struct berval *bv, unsigned flags, void *ctx )
2973 {
2974 	int		iRDN;
2975 	int		rc = LDAP_ENCODING_ERROR;
2976 	ber_len_t	len, l;
2977 
2978 	/* stringifying helpers for LDAPv3/LDAPv2 */
2979 	int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2980 	int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2981 
2982 	assert( bv != NULL );
2983 	bv->bv_len = 0;
2984 	bv->bv_val = NULL;
2985 
2986 	Debug( LDAP_DEBUG_ARGS, "=> ldap_dn2bv(%u)\n", flags, 0, 0 );
2987 
2988 	/*
2989 	 * a null dn means an empty dn string
2990 	 * FIXME: better raise an error?
2991 	 */
2992 	if ( dn == NULL ) {
2993 		bv->bv_val = LDAP_STRDUPX( "", ctx );
2994 		return( LDAP_SUCCESS );
2995 	}
2996 
2997 	switch ( LDAP_DN_FORMAT( flags ) ) {
2998 	case LDAP_DN_FORMAT_LDAPV3:
2999 		sv2l = strval2strlen;
3000 		sv2s = strval2str;
3001 
3002 		if( 0 ) {
3003 	case LDAP_DN_FORMAT_LDAPV2:
3004 			sv2l = strval2IA5strlen;
3005 			sv2s = strval2IA5str;
3006 		}
3007 
3008 		for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3009 			ber_len_t	rdnl;
3010 			if ( rdn2strlen( dn[ iRDN ], flags, &rdnl, sv2l ) ) {
3011 				goto return_results;
3012 			}
3013 
3014 			len += rdnl;
3015 		}
3016 
3017 		if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) {
3018 			rc = LDAP_NO_MEMORY;
3019 			break;
3020 		}
3021 
3022 		for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3023 			ber_len_t	rdnl;
3024 
3025 			if ( rdn2str( dn[ iRDN ], &bv->bv_val[ l ], flags,
3026 					&rdnl, sv2s ) ) {
3027 				LDAP_FREEX( bv->bv_val, ctx );
3028 				bv->bv_val = NULL;
3029 				goto return_results;
3030 			}
3031 			l += rdnl;
3032 		}
3033 
3034 		assert( l == len );
3035 
3036 		/*
3037 		 * trim the last ',' (the allocated memory
3038 		 * is one byte longer than required)
3039 		 */
3040 		bv->bv_len = len - 1;
3041 		bv->bv_val[ bv->bv_len ] = '\0';
3042 
3043 		rc = LDAP_SUCCESS;
3044 		break;
3045 
3046 	case LDAP_DN_FORMAT_UFN: {
3047 		/*
3048 		 * FIXME: quoting from RFC 1781:
3049 		 *
3050    To take a distinguished name, and generate a name of this format with
3051    attribute types omitted, the following steps are followed.
3052 
3053     1.  If the first attribute is of type CommonName, the type may be
3054 	omitted.
3055 
3056     2.  If the last attribute is of type Country, the type may be
3057         omitted.
3058 
3059     3.  If the last attribute is of type Country, the last
3060         Organisation attribute may have the type omitted.
3061 
3062     4.  All attributes of type OrganisationalUnit may have the type
3063         omitted, unless they are after an Organisation attribute or
3064         the first attribute is of type OrganisationalUnit.
3065 
3066          * this should be the pedantic implementation.
3067 		 *
3068 		 * Here the standard implementation reflects
3069 		 * the one historically provided by OpenLDAP
3070 		 * (and UMIch, I presume), with the variant
3071 		 * of spaces and plusses (' + ') separating
3072 		 * rdn components.
3073 		 *
3074 		 * A non-standard but nice implementation could
3075 		 * be to turn the  final "dc" attributes into a
3076 		 * dot-separated domain.
3077 		 *
3078 		 * Other improvements could involve the use of
3079 		 * friendly country names and so.
3080 		 */
3081 #ifdef DC_IN_UFN
3082 		int	leftmost_dc = -1;
3083 		int	last_iRDN = -1;
3084 #endif /* DC_IN_UFN */
3085 
3086 		for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3087 			ber_len_t	rdnl;
3088 
3089 			if ( rdn2UFNstrlen( dn[ iRDN ], flags, &rdnl ) ) {
3090 				goto return_results;
3091 			}
3092 			len += rdnl;
3093 
3094 #ifdef DC_IN_UFN
3095 			if ( LDAP_DN_IS_RDN_DC( dn[ iRDN ] ) ) {
3096 				if ( leftmost_dc == -1 ) {
3097 					leftmost_dc = iRDN;
3098 				}
3099 			} else {
3100 				leftmost_dc = -1;
3101 			}
3102 #endif /* DC_IN_UFN */
3103 		}
3104 
3105 		if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) {
3106 			rc = LDAP_NO_MEMORY;
3107 			break;
3108 		}
3109 
3110 #ifdef DC_IN_UFN
3111 		if ( leftmost_dc == -1 ) {
3112 #endif /* DC_IN_UFN */
3113 			for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3114 				ber_len_t	vl;
3115 
3116 				if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ],
3117 						flags, &vl ) ) {
3118 					LDAP_FREEX( bv->bv_val, ctx );
3119 					bv->bv_val = NULL;
3120 					goto return_results;
3121 				}
3122 				l += vl;
3123 			}
3124 
3125 			/*
3126 			 * trim the last ', ' (the allocated memory
3127 			 * is two bytes longer than required)
3128 			 */
3129 			bv->bv_len = len - 2;
3130 			bv->bv_val[ bv->bv_len ] = '\0';
3131 #ifdef DC_IN_UFN
3132 		} else {
3133 			last_iRDN = iRDN - 1;
3134 
3135 			for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
3136 				ber_len_t	vl;
3137 
3138 				if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ],
3139 						flags, &vl ) ) {
3140 					LDAP_FREEX( bv->bv_val, ctx );
3141 					bv->bv_val = NULL;
3142 					goto return_results;
3143 				}
3144 				l += vl;
3145 			}
3146 
3147 			if ( !dn2domain( dn, bv, l, &last_iRDN ) ) {
3148 				LDAP_FREEX( bv->bv_val, ctx );
3149 				bv->bv_val = NULL;
3150 				goto return_results;
3151 			}
3152 
3153 			/* the string is correctly terminated by dn2domain */
3154 		}
3155 #endif /* DC_IN_UFN */
3156 
3157 		rc = LDAP_SUCCESS;
3158 
3159 	} break;
3160 
3161 	case LDAP_DN_FORMAT_DCE:
3162 		for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3163 			ber_len_t	rdnl;
3164 			if ( rdn2DCEstrlen( dn[ iRDN ], flags, &rdnl ) ) {
3165 				goto return_results;
3166 			}
3167 
3168 			len += rdnl;
3169 		}
3170 
3171 		if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) {
3172 			rc = LDAP_NO_MEMORY;
3173 			break;
3174 		}
3175 
3176 		for ( l = 0; iRDN--; ) {
3177 			ber_len_t	rdnl;
3178 
3179 			if ( rdn2DCEstr( dn[ iRDN ], &bv->bv_val[ l ], flags,
3180 					&rdnl, 0 ) ) {
3181 				LDAP_FREEX( bv->bv_val, ctx );
3182 				bv->bv_val = NULL;
3183 				goto return_results;
3184 			}
3185 			l += rdnl;
3186 		}
3187 
3188 		assert( l == len );
3189 
3190 		bv->bv_len = len;
3191 		bv->bv_val[ bv->bv_len ] = '\0';
3192 
3193 		rc = LDAP_SUCCESS;
3194 		break;
3195 
3196 	case LDAP_DN_FORMAT_AD_CANONICAL: {
3197 		int	trailing_slash = 1;
3198 
3199 		/*
3200 		 * Sort of UFN for DCE DNs: a slash ('/') separated
3201 		 * global->local DN with no types; strictly speaking,
3202 		 * the naming context should be a domain, which is
3203 		 * written in DNS-style, e.g. dot-deparated.
3204 		 *
3205 		 * Example:
3206 		 *
3207 		 * 	"givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3208 		 *
3209 		 * will read
3210 		 *
3211 		 * 	"microsoft.com/People/Bill,Gates"
3212 		 */
3213 		for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3214 			ber_len_t	rdnl;
3215 
3216 			if ( rdn2ADstrlen( dn[ iRDN ], flags, &rdnl ) ) {
3217 				goto return_results;
3218 			}
3219 
3220 			len += rdnl;
3221 		}
3222 
3223 		/* reserve room for trailing '/' in case the DN
3224 		 * is exactly a domain */
3225 		if ( ( bv->bv_val = LDAP_MALLOCX( len + 1 + 1, ctx ) ) == NULL )
3226 		{
3227 			rc = LDAP_NO_MEMORY;
3228 			break;
3229 		}
3230 
3231 		iRDN--;
3232 		if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) != 0 ) {
3233 			for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) {
3234 				ber_len_t	rdnl;
3235 
3236 				trailing_slash = 0;
3237 
3238 				if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ],
3239 						flags, &rdnl, 0 ) ) {
3240 					LDAP_FREEX( bv->bv_val, ctx );
3241 					bv->bv_val = NULL;
3242 					goto return_results;
3243 				}
3244 				l += rdnl;
3245 			}
3246 
3247 		} else {
3248 			int		first = 1;
3249 
3250 			/*
3251 			 * Strictly speaking, AD canonical requires
3252 			 * a DN to be in the form "..., dc=smtg",
3253 			 * i.e. terminated by a domain component
3254 			 */
3255 			if ( flags & LDAP_DN_PEDANTIC ) {
3256 				LDAP_FREEX( bv->bv_val, ctx );
3257 				bv->bv_val = NULL;
3258 				rc = LDAP_ENCODING_ERROR;
3259 				break;
3260 			}
3261 
3262 			for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3263 				ber_len_t	rdnl;
3264 
3265 				if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ],
3266 						flags, &rdnl, first ) ) {
3267 					LDAP_FREEX( bv->bv_val, ctx );
3268 					bv->bv_val = NULL;
3269 					goto return_results;
3270 				}
3271 				if ( first ) {
3272 					first = 0;
3273 				}
3274 				l += rdnl;
3275 			}
3276 		}
3277 
3278 		if ( trailing_slash ) {
3279 			/* the DN is exactly a domain -- need a trailing
3280 			 * slash; room was reserved in advance */
3281 			bv->bv_val[ len ] = '/';
3282 			len++;
3283 		}
3284 
3285 		bv->bv_len = len;
3286 		bv->bv_val[ bv->bv_len ] = '\0';
3287 
3288 		rc = LDAP_SUCCESS;
3289 	} break;
3290 
3291 	default:
3292 		return LDAP_PARAM_ERROR;
3293 	}
3294 
3295 	Debug( LDAP_DEBUG_ARGS, "<= ldap_dn2bv(%s)=%d %s\n",
3296 		bv->bv_val, rc, rc ? ldap_err2string( rc ) : "" );
3297 
3298 return_results:;
3299 	return( rc );
3300 }
3301 
3302