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