xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/getdn.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /* $OpenLDAP: pkg/ldap/libraries/libldap/getdn.c,v 1.130.2.3 2008/02/11 23:26:41 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2008 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /* Portions Copyright (c) 1994 Regents of the University of Michigan.
16  * All rights reserved.
17  */
18 
19 #include "portable.h"
20 
21 #include <stdio.h>
22 
23 #include <ac/stdlib.h>
24 #include <ac/socket.h>
25 #include <ac/string.h>
26 #include <ac/time.h>
27 
28 #include "ldap-int.h"
29 #include "ldap_schema.h"
30 
31 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
32  * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
33 #define DC_IN_UFN
34 
35 /* parsing/printing routines */
36 static int str2strval( const char *str, ber_len_t stoplen, struct berval *val,
37 		const char **next, unsigned flags, int *retFlags, void *ctx );
38 static int DCE2strval( const char *str, struct berval *val,
39 		const char **next, unsigned flags, void *ctx );
40 static int IA52strval( const char *str, struct berval *val,
41 		const char **next, unsigned flags, void *ctx );
42 static int quotedIA52strval( const char *str, struct berval *val,
43 		const char **next, unsigned flags, void *ctx );
44 static int hexstr2binval( const char *str, struct berval *val,
45 		const char **next, unsigned flags, void *ctx );
46 static int hexstr2bin( const char *str, char *c );
47 static int byte2hexpair( const char *val, char *pair );
48 static int binval2hexstr( struct berval *val, char *str );
49 static int strval2strlen( struct berval *val, unsigned flags,
50 		ber_len_t *len );
51 static int strval2str( struct berval *val, char *str, unsigned flags,
52 		ber_len_t *len );
53 static int strval2IA5strlen( struct berval *val, unsigned flags,
54 		ber_len_t *len );
55 static int strval2IA5str( struct berval *val, char *str, unsigned flags,
56 		ber_len_t *len );
57 static int strval2DCEstrlen( struct berval *val, unsigned flags,
58 		ber_len_t *len );
59 static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
60 		ber_len_t *len );
61 static int strval2ADstrlen( struct berval *val, unsigned flags,
62 		ber_len_t *len );
63 static int strval2ADstr( struct berval *val, char *str, unsigned flags,
64 		ber_len_t *len );
65 static int dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN );
66 
67 /* AVA helpers */
68 static LDAPAVA * ldapava_new(
69 	const struct berval *attr, const struct berval *val, unsigned flags, void *ctx );
70 
71 /* Higher level helpers */
72 static int rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len,
73 		int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
74 static int rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len,
75 		int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
76 static int rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len  );
77 static int rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len );
78 static int rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len );
79 static int rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flag, ber_len_t *len, int first );
80 static int rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len );
81 static int rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first );
82 
83 /*
84  * RFC 1823 ldap_get_dn
85  */
86 char *
87 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
88 {
89 	char		*dn;
90 	BerElement	tmp;
91 
92 	Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
93 
94 	assert( ld != NULL );
95 	assert( LDAP_VALID(ld) );
96 	assert( entry != NULL );
97 
98 	tmp = *entry->lm_ber;	/* struct copy */
99 	if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
100 		ld->ld_errno = LDAP_DECODING_ERROR;
101 		return( NULL );
102 	}
103 
104 	return( dn );
105 }
106 
107 int
108 ldap_get_dn_ber( LDAP *ld, LDAPMessage *entry, BerElement **berout,
109 	BerValue *dn )
110 {
111 	BerElement	tmp, *ber;
112 	ber_len_t	len = 0;
113 	int rc = LDAP_SUCCESS;
114 
115 	Debug( LDAP_DEBUG_TRACE, "ldap_get_dn_ber\n", 0, 0, 0 );
116 
117 	assert( ld != NULL );
118 	assert( LDAP_VALID(ld) );
119 	assert( entry != NULL );
120 	assert( dn != NULL );
121 
122 	dn->bv_val = NULL;
123 	dn->bv_len = 0;
124 
125 	if ( berout ) {
126 		*berout = NULL;
127 		ber = ldap_alloc_ber_with_options( ld );
128 		if( ber == NULL ) {
129 			return LDAP_NO_MEMORY;
130 		}
131 		*berout = ber;
132 	} else {
133 		ber = &tmp;
134 	}
135 
136 	*ber = *entry->lm_ber;	/* struct copy */
137 	if ( ber_scanf( ber, "{ml{" /*}*/, dn, &len ) == LBER_ERROR ) {
138 		rc = ld->ld_errno = LDAP_DECODING_ERROR;
139 	}
140 	if ( rc == LDAP_SUCCESS ) {
141 		/* set the length to avoid overrun */
142 		rc = ber_set_option( ber, LBER_OPT_REMAINING_BYTES, &len );
143 		if( rc != LBER_OPT_SUCCESS ) {
144 			rc = ld->ld_errno = LDAP_LOCAL_ERROR;
145 		}
146 	}
147 	if ( rc != LDAP_SUCCESS && berout ) {
148 		ber_free( ber, 0 );
149 		*berout = NULL;
150 	}
151 	return rc;
152 }
153 
154 /*
155  * RFC 1823 ldap_dn2ufn
156  */
157 char *
158 ldap_dn2ufn( LDAP_CONST char *dn )
159 {
160 	char	*out = NULL;
161 
162 	Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
163 
164 	( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
165 		&out, LDAP_DN_FORMAT_UFN );
166 
167 	return( out );
168 }
169 
170 /*
171  * RFC 1823 ldap_explode_dn
172  */
173 char **
174 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
175 {
176 	LDAPDN	tmpDN;
177 	char	**values = NULL;
178 	int	iRDN;
179 	unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
180 
181 	Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
182 
183 	if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP )
184 			!= LDAP_SUCCESS ) {
185 		return NULL;
186 	}
187 
188 	if( tmpDN == NULL ) {
189 		values = LDAP_MALLOC( sizeof( char * ) );
190 		if( values == NULL ) return NULL;
191 
192 		values[0] = NULL;
193 		return values;
194 	}
195 
196 	for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ );
197 
198 	values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) );
199 	if ( values == NULL ) {
200 		ldap_dnfree( tmpDN );
201 		return NULL;
202 	}
203 
204 	for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
205 		ldap_rdn2str( tmpDN[ iRDN ], &values[ iRDN ], flag );
206 	}
207 	ldap_dnfree( tmpDN );
208 	values[ iRDN ] = NULL;
209 
210 	return values;
211 }
212 
213 char **
214 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
215 {
216 	LDAPRDN		tmpRDN;
217 	char		**values = NULL;
218 	const char 	*p;
219 	int		iAVA;
220 
221 	Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
222 
223 	/*
224 	 * we only parse the first rdn
225 	 * FIXME: we prefer efficiency over checking if the _ENTIRE_
226 	 * dn can be parsed
227 	 */
228 	if ( ldap_str2rdn( rdn, &tmpRDN, (char **) &p, LDAP_DN_FORMAT_LDAP )
229 			!= LDAP_SUCCESS ) {
230 		return( NULL );
231 	}
232 
233 	for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) ;
234 	values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) );
235 	if ( values == NULL ) {
236 		ldap_rdnfree( tmpRDN );
237 		return( NULL );
238 	}
239 
240 	for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) {
241 		ber_len_t	l = 0, vl, al = 0;
242 		char		*str;
243 		LDAPAVA		*ava = tmpRDN[ iAVA ];
244 
245 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
246 			vl = 1 + 2 * ava->la_value.bv_len;
247 
248 		} else {
249 			if ( strval2strlen( &ava->la_value,
250 						ava->la_flags, &vl ) ) {
251 				goto error_return;
252 			}
253 		}
254 
255 		if ( !notypes ) {
256 			al = ava->la_attr.bv_len;
257 			l = vl + ava->la_attr.bv_len + 1;
258 
259 			str = LDAP_MALLOC( l + 1 );
260 			AC_MEMCPY( str, ava->la_attr.bv_val,
261 					ava->la_attr.bv_len );
262 			str[ al++ ] = '=';
263 
264 		} else {
265 			l = vl;
266 			str = LDAP_MALLOC( l + 1 );
267 		}
268 
269 		if ( ava->la_flags & LDAP_AVA_BINARY ) {
270 			str[ al++ ] = '#';
271 			if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) {
272 				goto error_return;
273 			}
274 
275 		} else {
276 			if ( strval2str( &ava->la_value, &str[ al ],
277 					ava->la_flags, &vl ) ) {
278 				goto error_return;
279 			}
280 		}
281 
282 		str[ l ] = '\0';
283 		values[ iAVA ] = str;
284 	}
285 	values[ iAVA ] = NULL;
286 
287 	ldap_rdnfree( tmpRDN );
288 
289 	return( values );
290 
291 error_return:;
292 	LBER_VFREE( values );
293 	ldap_rdnfree( tmpRDN );
294 	return( NULL );
295 }
296 
297 char *
298 ldap_dn2dcedn( LDAP_CONST char *dn )
299 {
300 	char	*out = NULL;
301 
302 	Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
303 
304 	( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
305 				   &out, LDAP_DN_FORMAT_DCE );
306 
307 	return( out );
308 }
309 
310 char *
311 ldap_dcedn2dn( LDAP_CONST char *dce )
312 {
313 	char	*out = NULL;
314 
315 	Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
316 
317 	( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
318 
319 	return( out );
320 }
321 
322 char *
323 ldap_dn2ad_canonical( LDAP_CONST char *dn )
324 {
325 	char	*out = NULL;
326 
327 	Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
328 
329 	( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
330 		       &out, LDAP_DN_FORMAT_AD_CANONICAL );
331 
332 	return( out );
333 }
334 
335 /*
336  * function that changes the string representation of dnin
337  * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
338  *
339  * fin can be one of:
340  * 	LDAP_DN_FORMAT_LDAP		(RFC 4514 liberal, plus some RFC 1779)
341  * 	LDAP_DN_FORMAT_LDAPV3	(RFC 4514)
342  * 	LDAP_DN_FORMAT_LDAPV2	(RFC 1779)
343  * 	LDAP_DN_FORMAT_DCE		(?)
344  *
345  * fout can be any of the above except
346  * 	LDAP_DN_FORMAT_LDAP
347  * plus:
348  * 	LDAP_DN_FORMAT_UFN		(RFC 1781, partial and with extensions)
349  * 	LDAP_DN_FORMAT_AD_CANONICAL	(?)
350  */
351 int
352 ldap_dn_normalize( LDAP_CONST char *dnin,
353 	unsigned fin, char **dnout, unsigned fout )
354 {
355 	int	rc;
356 	LDAPDN	tmpDN = NULL;
357 
358 	Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
359 
360 	assert( dnout != NULL );
361 
362 	*dnout = NULL;
363 
364 	if ( dnin == NULL ) {
365 		return( LDAP_SUCCESS );
366 	}
367 
368 	rc = ldap_str2dn( dnin , &tmpDN, fin );
369 	if ( rc != LDAP_SUCCESS ) {
370 		return( rc );
371 	}
372 
373 	rc = ldap_dn2str( tmpDN, dnout, fout );
374 
375 	ldap_dnfree( tmpDN );
376 
377 	return( rc );
378 }
379 
380 /* States */
381 #define B4AVA			0x0000
382 
383 /* #define	B4ATTRTYPE		0x0001 */
384 #define B4OIDATTRTYPE		0x0002
385 #define B4STRINGATTRTYPE	0x0003
386 
387 #define B4AVAEQUALS		0x0100
388 #define B4AVASEP		0x0200
389 #define B4RDNSEP		0x0300
390 #define GOTAVA			0x0400
391 
392 #define B4ATTRVALUE		0x0010
393 #define B4STRINGVALUE		0x0020
394 #define B4IA5VALUEQUOTED	0x0030
395 #define B4IA5VALUE		0x0040
396 #define B4BINARYVALUE		0x0050
397 
398 /*
399  * Helpers (mostly from slap.h)
400  * c is assumed to Unicode in an ASCII compatible format (UTF-8)
401  * Macros assume "C" Locale (ASCII)
402  */
403 #define LDAP_DN_ASCII_SPACE(c) \
404 	( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
405 #define LDAP_DN_ASCII_LOWER(c)		LDAP_LOWER(c)
406 #define LDAP_DN_ASCII_UPPER(c)		LDAP_UPPER(c)
407 #define LDAP_DN_ASCII_ALPHA(c)		LDAP_ALPHA(c)
408 
409 #define LDAP_DN_ASCII_DIGIT(c)		LDAP_DIGIT(c)
410 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c)	LDAP_HEXLOWER(c)
411 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c)	LDAP_HEXUPPER(c)
412 #define LDAP_DN_ASCII_HEXDIGIT(c)	LDAP_HEX(c)
413 #define LDAP_DN_ASCII_ALNUM(c)		LDAP_ALNUM(c)
414 #define LDAP_DN_ASCII_PRINTABLE(c)	( (c) >= ' ' && (c) <= '~' )
415 
416 /* attribute type */
417 #define LDAP_DN_OID_LEADCHAR(c)		LDAP_DIGIT(c)
418 #define LDAP_DN_DESC_LEADCHAR(c)	LDAP_ALPHA(c)
419 #define LDAP_DN_DESC_CHAR(c)		LDAP_LDH(c)
420 #define LDAP_DN_LANG_SEP(c)		( (c) == ';' )
421 #define LDAP_DN_ATTRDESC_CHAR(c) \
422 	( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
423 
424 /* special symbols */
425 #define LDAP_DN_AVA_EQUALS(c)		( (c) == '=' )
426 #define LDAP_DN_AVA_SEP(c)		( (c) == '+' )
427 #define LDAP_DN_RDN_SEP(c)		( (c) == ',' )
428 #define LDAP_DN_RDN_SEP_V2(c)		( LDAP_DN_RDN_SEP(c) || (c) == ';' )
429 #define LDAP_DN_OCTOTHORPE(c)		( (c) == '#' )
430 #define LDAP_DN_QUOTES(c)		( (c) == '\"' )
431 #define LDAP_DN_ESCAPE(c)		( (c) == '\\' )
432 #define LDAP_DN_VALUE_END(c) \
433 	( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
434 
435 /* NOTE: according to RFC 4514, '=' can be escaped and treated as special,
436  * i.e. escaped both as "\<hexpair>" and * as "\=", but it is treated as
437  * a regular char, i.e. it can also appear as '='.
438  *
439  * As such, in 2.2 we used to allow reading unescaped '=', but we always
440  * produced escaped '\3D'; this changes since 2.3, if compatibility issues
441  * do not arise
442  */
443 #define LDAP_DN_NE(c) \
444 	( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
445 	  || LDAP_DN_QUOTES(c) \
446 	  || (c) == '<' || (c) == '>' )
447 #define LDAP_DN_MAYESCAPE(c) \
448 	( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \
449 	  || LDAP_DN_AVA_EQUALS(c) \
450 	  || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) )
451 #define LDAP_DN_SHOULDESCAPE(c)		( LDAP_DN_AVA_EQUALS(c) )
452 
453 #define LDAP_DN_NEEDESCAPE(c) \
454 	( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
455 #define LDAP_DN_NEEDESCAPE_LEAD(c) 	LDAP_DN_MAYESCAPE(c)
456 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
457 	( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
458 #define LDAP_DN_WILLESCAPE_CHAR(c) \
459 	( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) )
460 #define LDAP_DN_IS_PRETTY(f)		( (f) & LDAP_DN_PRETTY )
461 #define LDAP_DN_WILLESCAPE_HEX(f, c) \
462 	( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
463 
464 /* LDAPv2 */
465 #define	LDAP_DN_VALUE_END_V2(c) \
466 	( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
467 /* RFC 1779 */
468 #define	LDAP_DN_V2_SPECIAL(c) \
469 	  ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
470 	    || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
471 	    || LDAP_DN_OCTOTHORPE(c) )
472 #define LDAP_DN_V2_PAIR(c) \
473 	  ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
474 
475 /*
476  * DCE (mostly from Luke Howard and IBM implementation for AIX)
477  *
478  * From: "Application Development Guide - Directory Services" (FIXME: add link?)
479  * Here escapes and valid chars for GDS are considered; as soon as more
480  * specific info is found, the macros will be updated.
481  *
482  * Chars:	'a'-'z', 'A'-'Z', '0'-'9',
483  *		'.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
484  *
485  * Metachars:	'/', ',', '=', '\'.
486  *
487  * the '\' is used to escape other metachars.
488  *
489  * Assertion:		'='
490  * RDN separator:	'/'
491  * AVA separator:	','
492  *
493  * Attribute types must start with alphabetic chars and can contain
494  * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
495  */
496 #define LDAP_DN_RDN_SEP_DCE(c)		( (c) == '/' )
497 #define LDAP_DN_AVA_SEP_DCE(c)		( (c) == ',' )
498 #define LDAP_DN_ESCAPE_DCE(c)		( LDAP_DN_ESCAPE(c) )
499 #define	LDAP_DN_VALUE_END_DCE(c) \
500 	( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
501 #define LDAP_DN_NEEDESCAPE_DCE(c) \
502 	( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
503 
504 /* AD Canonical */
505 #define LDAP_DN_RDN_SEP_AD(c)		( (c) == '/' )
506 #define LDAP_DN_ESCAPE_AD(c)		( LDAP_DN_ESCAPE(c) )
507 #define LDAP_DN_AVA_SEP_AD(c)		( (c) == ',' )	/* assume same as DCE */
508 #define	LDAP_DN_VALUE_END_AD(c) \
509 	( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
510 #define LDAP_DN_NEEDESCAPE_AD(c) \
511 	( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
512 
513 /* generics */
514 #define LDAP_DN_HEXPAIR(s) \
515 	( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
516 /* better look at the AttributeDescription? */
517 
518 /* FIXME: no composite rdn or non-"dc" types, right?
519  * (what about "dc" in OID form?) */
520 /* FIXME: we do not allow binary values in domain, right? */
521 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
522 /* NOTE: don't use strcasecmp() as it is locale specific! */
523 #define	LDAP_DC_ATTR	"dc"
524 #define	LDAP_DC_ATTRU	"DC"
525 #define LDAP_DN_IS_RDN_DC( r ) \
526 	( (r) && (r)[0] && !(r)[1] \
527 	  && ((r)[0]->la_flags & LDAP_AVA_STRING) \
528 	  && ((r)[0]->la_attr.bv_len == 2) \
529 	  && (((r)[0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \
530 		|| ((r)[0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \
531 	  && (((r)[0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \
532 		|| ((r)[0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1])))
533 
534 /* Composite rules */
535 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
536 	( LDAP_DN_LDAPV2(f) \
537 	  || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
538 #define LDAP_DN_ALLOW_SPACES(f) \
539 	( LDAP_DN_LDAPV2(f) \
540 	  || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
541 #define LDAP_DN_LDAP(f) \
542 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
543 #define LDAP_DN_LDAPV3(f) \
544 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
545 #define LDAP_DN_LDAPV2(f) \
546 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
547 #define LDAP_DN_DCE(f) \
548 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
549 #define LDAP_DN_UFN(f) \
550 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
551 #define LDAP_DN_ADC(f) \
552 	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
553 #define LDAP_DN_FORMAT(f)		( (f) & LDAP_DN_FORMAT_MASK )
554 
555 /*
556  * LDAPAVA helpers (will become part of the API for operations
557  * on structural representations of DNs).
558  */
559 static LDAPAVA *
560 ldapava_new( const struct berval *attr, const struct berval *val,
561 		unsigned flags, void *ctx )
562 {
563 	LDAPAVA *ava;
564 
565 	assert( attr != NULL );
566 	assert( val != NULL );
567 
568 	ava = LDAP_MALLOCX( sizeof( LDAPAVA ) + attr->bv_len + 1, ctx );
569 
570 	if ( ava ) {
571 		ava->la_attr.bv_len = attr->bv_len;
572 		ava->la_attr.bv_val = (char *)(ava+1);
573 		AC_MEMCPY( ava->la_attr.bv_val, attr->bv_val, attr->bv_len );
574 		ava->la_attr.bv_val[attr->bv_len] = '\0';
575 
576 		ava->la_value = *val;
577 		ava->la_flags = flags | LDAP_AVA_FREE_VALUE;
578 
579 		ava->la_private = NULL;
580 	}
581 
582 	return( ava );
583 }
584 
585 void
586 ldapava_free( LDAPAVA *ava, void *ctx )
587 {
588 	assert( ava != NULL );
589 
590 #if 0
591 	/* ava's private must be freed by caller
592 	 * (at present let's skip this check because la_private
593 	 * basically holds static data) */
594 	assert( ava->la_private == NULL );
595 #endif
596 
597 	if (ava->la_flags & LDAP_AVA_FREE_VALUE)
598 		LDAP_FREEX( ava->la_value.bv_val, ctx );
599 
600 	LDAP_FREEX( ava, ctx );
601 }
602 
603 void
604 ldap_rdnfree( LDAPRDN rdn )
605 {
606 	ldap_rdnfree_x( rdn, NULL );
607 }
608 
609 void
610 ldap_rdnfree_x( LDAPRDN rdn, void *ctx )
611 {
612 	int iAVA;
613 
614 	if ( rdn == NULL ) {
615 		return;
616 	}
617 
618 	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
619 		ldapava_free( rdn[ iAVA ], ctx );
620 	}
621 
622 	LDAP_FREEX( rdn, ctx );
623 }
624 
625 void
626 ldap_dnfree( LDAPDN dn )
627 {
628 	ldap_dnfree_x( dn, NULL );
629 }
630 
631 void
632 ldap_dnfree_x( LDAPDN dn, void *ctx )
633 {
634 	int iRDN;
635 
636 	if ( dn == NULL ) {
637 		return;
638 	}
639 
640 	for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
641 		ldap_rdnfree_x( dn[ iRDN ], ctx );
642 	}
643 
644 	LDAP_FREEX( dn, ctx );
645 }
646 
647 /*
648  * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
649  * into a structural representation of the DN, by separating attribute
650  * types and values encoded in the more appropriate form, which is
651  * string or OID for attribute types and binary form of the BER encoded
652  * value or Unicode string. Formats different from LDAPv3 are parsed
653  * according to their own rules and turned into the more appropriate
654  * form according to LDAPv3.
655  *
656  * NOTE: I realize the code is getting spaghettish; it is rather
657  * experimental and will hopefully turn into something more simple
658  * and readable as soon as it works as expected.
659  */
660 
661 /*
662  * Default sizes of AVA and RDN static working arrays; if required
663  * the are dynamically resized.  The values can be tuned in case
664  * of special requirements (e.g. very deep DN trees or high number
665  * of AVAs per RDN).
666  */
667 #define	TMP_AVA_SLOTS	8
668 #define	TMP_RDN_SLOTS	32
669 
670 int
671 ldap_str2dn( LDAP_CONST char *str, LDAPDN *dn, unsigned flags )
672 {
673 	struct berval	bv;
674 
675 	assert( str != NULL );
676 
677 	bv.bv_len = strlen( str );
678 	bv.bv_val = (char *) str;
679 
680 	return ldap_bv2dn_x( &bv, dn, flags, NULL );
681 }
682 
683 int
684 ldap_bv2dn( struct berval *bv, LDAPDN *dn, unsigned flags )
685 {
686 	return ldap_bv2dn_x( bv, dn, flags, NULL );
687 }
688 
689 int
690 ldap_bv2dn_x( struct berval *bvin, LDAPDN *dn, unsigned flags, void *ctx )
691 {
692 	const char 	*p;
693 	int		rc = LDAP_DECODING_ERROR;
694 	int		nrdns = 0;
695 
696 	LDAPDN		newDN = NULL;
697 	LDAPRDN		newRDN = NULL, tmpDN_[TMP_RDN_SLOTS], *tmpDN = tmpDN_;
698 	int		num_slots = TMP_RDN_SLOTS;
699 	char		*str, *end;
700 	struct berval	bvtmp, *bv = &bvtmp;
701 
702 	assert( bvin != NULL );
703 	assert( bvin->bv_val != NULL );
704 	assert( dn != NULL );
705 
706 	*bv = *bvin;
707 	str = bv->bv_val;
708 	end = str + bv->bv_len;
709 
710 	Debug( LDAP_DEBUG_ARGS, "=> ldap_bv2dn(%s,%u)\n", str, flags, 0 );
711 
712 	*dn = NULL;
713 
714 	switch ( LDAP_DN_FORMAT( flags ) ) {
715 	case LDAP_DN_FORMAT_LDAP:
716 	case LDAP_DN_FORMAT_LDAPV3:
717 	case LDAP_DN_FORMAT_DCE:
718 		break;
719 
720 		/* allow DN enclosed in brackets */
721 	case LDAP_DN_FORMAT_LDAPV2:
722 		if ( str[0] == '<' ) {
723 			if ( bv->bv_len < 2 || end[ -1 ] != '>' ) {
724 				rc = LDAP_DECODING_ERROR;
725 				goto parsing_error;
726 			}
727 			bv->bv_val++;
728 			bv->bv_len -= 2;
729 			str++;
730 			end--;
731 		}
732 		break;
733 
734 	/* unsupported in str2dn */
735 	case LDAP_DN_FORMAT_UFN:
736 	case LDAP_DN_FORMAT_AD_CANONICAL:
737 		return LDAP_PARAM_ERROR;
738 
739 	case LDAP_DN_FORMAT_LBER:
740 	default:
741 		return LDAP_PARAM_ERROR;
742 	}
743 
744 	if ( bv->bv_len == 0 ) {
745 		return LDAP_SUCCESS;
746 	}
747 
748 	if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) {
749 		/* value must have embedded NULs */
750 		return LDAP_DECODING_ERROR;
751 	}
752 
753 	p = str;
754 	if ( LDAP_DN_DCE( flags ) ) {
755 
756 		/*
757 		 * (from Luke Howard: thnx) A RDN separator is required
758 		 * at the beginning of an (absolute) DN.
759 		 */
760 		if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
761 			goto parsing_error;
762 		}
763 		p++;
764 
765 	/*
766 	 * actually we do not want to accept by default the DCE form,
767 	 * we do not want to auto-detect it
768 	 */
769 #if 0
770 	} else if ( LDAP_DN_LDAP( flags ) ) {
771 		/*
772 		 * if dn starts with '/' let's make it a DCE dn
773 		 */
774 		if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
775 			flags |= LDAP_DN_FORMAT_DCE;
776 			p++;
777 		}
778 #endif
779 	}
780 
781 	for ( ; p < end; p++ ) {
782 		int		err;
783 		struct berval 	tmpbv;
784 		tmpbv.bv_len = bv->bv_len - ( p - str );
785 		tmpbv.bv_val = (char *)p;
786 
787 		err = ldap_bv2rdn_x( &tmpbv, &newRDN, (char **) &p, flags,ctx);
788 		if ( err != LDAP_SUCCESS ) {
789 			goto parsing_error;
790 		}
791 
792 		/*
793 		 * We expect a rdn separator
794 		 */
795 		if ( p < end && p[ 0 ] ) {
796 			switch ( LDAP_DN_FORMAT( flags ) ) {
797 			case LDAP_DN_FORMAT_LDAPV3:
798 				if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
799 					rc = LDAP_DECODING_ERROR;
800 					goto parsing_error;
801 				}
802 				break;
803 
804 			case LDAP_DN_FORMAT_LDAP:
805 			case LDAP_DN_FORMAT_LDAPV2:
806 				if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
807 					rc = LDAP_DECODING_ERROR;
808 					goto parsing_error;
809 				}
810 				break;
811 
812 			case LDAP_DN_FORMAT_DCE:
813 				if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
814 					rc = LDAP_DECODING_ERROR;
815 					goto parsing_error;
816 				}
817 				break;
818 			}
819 		}
820 
821 
822 		tmpDN[nrdns++] = newRDN;
823 		newRDN = NULL;
824 
825 		/*
826 		 * make the static RDN array dynamically rescalable
827 		 */
828 		if ( nrdns == num_slots ) {
829 			LDAPRDN	*tmp;
830 
831 			if ( tmpDN == tmpDN_ ) {
832 				tmp = LDAP_MALLOCX( num_slots * 2 * sizeof( LDAPRDN * ), ctx );
833 				if ( tmp == NULL ) {
834 					rc = LDAP_NO_MEMORY;
835 					goto parsing_error;
836 				}
837 				AC_MEMCPY( tmp, tmpDN, num_slots * sizeof( LDAPRDN * ) );
838 
839 			} else {
840 				tmp = LDAP_REALLOCX( tmpDN, num_slots * 2 * sizeof( LDAPRDN * ), ctx );
841 				if ( tmp == NULL ) {
842 					rc = LDAP_NO_MEMORY;
843 					goto parsing_error;
844 				}
845 			}
846 
847 			tmpDN = tmp;
848 			num_slots *= 2;
849 		}
850 
851 		if ( p >= end || p[ 0 ] == '\0' ) {
852 			/*
853 			 * the DN is over, phew
854 			 */
855 			newDN = (LDAPDN)LDAP_MALLOCX( sizeof(LDAPRDN *) * (nrdns+1), ctx );
856 			if ( newDN == NULL ) {
857 				rc = LDAP_NO_MEMORY;
858 				goto parsing_error;
859 			} else {
860 				int i;
861 
862 				if ( LDAP_DN_DCE( flags ) ) {
863 					/* add in reversed order */
864 					for ( i=0; i<nrdns; i++ )
865 						newDN[i] = tmpDN[nrdns-1-i];
866 				} else {
867 					for ( i=0; i<nrdns; i++ )
868 						newDN[i] = tmpDN[i];
869 				}
870 				newDN[nrdns] = NULL;
871 				rc = LDAP_SUCCESS;
872 			}
873 			goto return_result;
874 		}
875 	}
876 
877 parsing_error:;
878 	if ( newRDN ) {
879 		ldap_rdnfree_x( newRDN, ctx );
880 	}
881 
882 	for ( nrdns-- ;nrdns >= 0; nrdns-- ) {
883 		ldap_rdnfree_x( tmpDN[nrdns], ctx );
884 	}
885 
886 return_result:;
887 
888 	if ( tmpDN != tmpDN_ ) {
889 		LDAP_FREEX( tmpDN, ctx );
890 	}
891 
892 	Debug( LDAP_DEBUG_ARGS, "<= ldap_bv2dn(%s)=%d %s\n", str, rc,
893 			rc ? ldap_err2string( rc ) : "" );
894 	*dn = newDN;
895 
896 	return( rc );
897 }
898 
899 /*
900  * ldap_str2rdn
901  *
902  * Parses a relative DN according to flags up to a rdn separator
903  * or to the end of str.
904  * Returns the rdn and a pointer to the string continuation, which
905  * corresponds to the rdn separator or to '\0' in case the string is over.
906  */
907 int
908 ldap_str2rdn( LDAP_CONST char *str, LDAPRDN *rdn,
909 	char **n_in, unsigned flags )
910 {
911 	struct berval	bv;
912 
913 	assert( str != NULL );
914 	assert( str[ 0 ] != '\0' );	/* FIXME: is this required? */
915 
916 	bv.bv_len = strlen( str );
917 	bv.bv_val = (char *) str;
918 
919 	return ldap_bv2rdn_x( &bv, rdn, n_in, flags, NULL );
920 }
921 
922 int
923 ldap_bv2rdn( struct berval *bv, LDAPRDN *rdn,
924 	char **n_in, unsigned flags )
925 {
926 	return ldap_bv2rdn_x( bv, rdn, n_in, flags, NULL );
927 }
928 
929 int
930 ldap_bv2rdn_x( struct berval *bv, LDAPRDN *rdn,
931 	char **n_in, unsigned flags, void *ctx )
932 {
933 	const char  	**n = (const char **) n_in;
934 	const char 	*p;
935 	int		navas = 0;
936 	int 		state = B4AVA;
937 	int		rc = LDAP_DECODING_ERROR;
938 	int		attrTypeEncoding = LDAP_AVA_STRING,
939 			attrValueEncoding = LDAP_AVA_STRING;
940 
941 	struct berval	attrType = BER_BVNULL;
942 	struct berval 	attrValue = BER_BVNULL;
943 
944 	LDAPRDN		newRDN = NULL;
945 	LDAPAVA		*tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_;
946 	int		num_slots = TMP_AVA_SLOTS;
947 
948 	char		*str;
949 	ber_len_t	stoplen;
950 
951 	assert( bv != NULL );
952 	assert( bv->bv_len != 0 );
953 	assert( bv->bv_val != NULL );
954 	assert( rdn || flags & LDAP_DN_SKIP );
955 	assert( n != NULL );
956 
957 	str = bv->bv_val;
958 	stoplen = bv->bv_len;
959 
960 	if ( rdn ) {
961 		*rdn = NULL;
962 	}
963 	*n = NULL;
964 
965 	switch ( LDAP_DN_FORMAT( flags ) ) {
966 	case LDAP_DN_FORMAT_LDAP:
967 	case LDAP_DN_FORMAT_LDAPV3:
968 	case LDAP_DN_FORMAT_LDAPV2:
969 	case LDAP_DN_FORMAT_DCE:
970 		break;
971 
972 	/* unsupported in str2dn */
973 	case LDAP_DN_FORMAT_UFN:
974 	case LDAP_DN_FORMAT_AD_CANONICAL:
975 		return LDAP_PARAM_ERROR;
976 
977 	case LDAP_DN_FORMAT_LBER:
978 	default:
979 		return LDAP_PARAM_ERROR;
980 	}
981 
982 	if ( bv->bv_len == 0 ) {
983 		return LDAP_SUCCESS;
984 
985 	}
986 
987 	if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) {
988 		/* value must have embedded NULs */
989 		return LDAP_DECODING_ERROR;
990 	}
991 
992 	p = str;
993 	for ( ; p[ 0 ] || state == GOTAVA; ) {
994 
995 		/*
996 		 * The parser in principle advances one token a time,
997 		 * or toggles state if preferable.
998 		 */
999 		switch (state) {
1000 
1001 		/*
1002 		 * an AttributeType can be encoded as:
1003 		 * - its string representation; in detail, implementations
1004 		 *   MUST recognize AttributeType string type names listed
1005 		 *   in Section 3 of RFC 4514, and MAY recognize other names.
1006 		 * - its numeric OID (a dotted decimal string)
1007 		 */
1008 		case B4AVA:
1009 			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1010 				if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
1011 					/* error */
1012 					goto parsing_error;
1013 				}
1014 				p++;
1015 			}
1016 
1017 			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1018 				if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1019 					/* error */
1020 					goto parsing_error;
1021 				}
1022 
1023 				/* whitespace is allowed (and trimmed) */
1024 				p++;
1025 				while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1026 					p++;
1027 				}
1028 
1029 				if ( !p[ 0 ] ) {
1030 					/* error: we expected an AVA */
1031 					goto parsing_error;
1032 				}
1033 			}
1034 
1035 			/* oid */
1036 			if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
1037 				state = B4OIDATTRTYPE;
1038 				break;
1039 			}
1040 
1041 			/* else must be alpha */
1042 			if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
1043 				goto parsing_error;
1044 			}
1045 
1046 			/* LDAPv2 "oid." prefix */
1047 			if ( LDAP_DN_LDAPV2( flags ) ) {
1048 				/*
1049 				 * to be overly pedantic, we only accept
1050 				 * "OID." or "oid."
1051 				 */
1052 				if ( flags & LDAP_DN_PEDANTIC ) {
1053 					if ( !strncmp( p, "OID.", 4 )
1054 						|| !strncmp( p, "oid.", 4 ) ) {
1055 						p += 4;
1056 						state = B4OIDATTRTYPE;
1057 						break;
1058 					}
1059 				} else {
1060 				       if ( !strncasecmp( p, "oid.", 4 ) ) {
1061 					       p += 4;
1062 					       state = B4OIDATTRTYPE;
1063 					       break;
1064 				       }
1065 				}
1066 			}
1067 
1068 			state = B4STRINGATTRTYPE;
1069 			break;
1070 
1071 		case B4OIDATTRTYPE: {
1072 			int 		err = LDAP_SUCCESS;
1073 
1074 			attrType.bv_val = ldap_int_parse_numericoid( &p, &err,
1075 				LDAP_SCHEMA_SKIP);
1076 
1077 			if ( err != LDAP_SUCCESS ) {
1078 				goto parsing_error;
1079 			}
1080 			attrType.bv_len = p - attrType.bv_val;
1081 
1082 			attrTypeEncoding = LDAP_AVA_BINARY;
1083 
1084 			state = B4AVAEQUALS;
1085 			break;
1086 		}
1087 
1088 		case B4STRINGATTRTYPE: {
1089 			const char 	*startPos, *endPos = NULL;
1090 			ber_len_t 	len;
1091 
1092 			/*
1093 			 * the starting char has been found to be
1094 			 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1095 			 * FIXME: DCE attr types seem to have a more
1096 			 * restrictive syntax (no '-' ...)
1097 			 */
1098 			for ( startPos = p++; p[ 0 ]; p++ ) {
1099 				if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1100 					continue;
1101 				}
1102 
1103 				if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1104 
1105 					/*
1106 					 * RFC 4514 explicitly does not allow attribute
1107 					 * description options, such as language tags.
1108 					 */
1109 					if ( flags & LDAP_DN_PEDANTIC ) {
1110 						goto parsing_error;
1111 					}
1112 
1113 					/*
1114 					 * we trim ';' and following lang
1115 					 * and so from attribute types
1116 					 */
1117 					endPos = p;
1118 					for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1119 							|| LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1120 						/* no op */ ;
1121 					}
1122 					break;
1123 				}
1124 				break;
1125 			}
1126 
1127 			len = ( endPos ? endPos : p ) - startPos;
1128 			if ( len == 0 ) {
1129 				goto parsing_error;
1130 			}
1131 
1132 			attrTypeEncoding = LDAP_AVA_STRING;
1133 
1134 			/*
1135 			 * here we need to decide whether to use it as is
1136 			 * or turn it in OID form; as a consequence, we
1137 			 * need to decide whether to binary encode the value
1138 			 */
1139 
1140 			state = B4AVAEQUALS;
1141 
1142 			if ( flags & LDAP_DN_SKIP ) {
1143 				break;
1144 			}
1145 
1146 			attrType.bv_val = (char *)startPos;
1147 			attrType.bv_len = len;
1148 
1149 			break;
1150 		}
1151 
1152 		case B4AVAEQUALS:
1153 			/* spaces may not be allowed */
1154 			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1155 				if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1156 					goto parsing_error;
1157 				}
1158 
1159 				/* trim spaces */
1160 				for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1161 					/* no op */
1162 				}
1163 			}
1164 
1165 			/* need equal sign */
1166 			if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1167 				goto parsing_error;
1168 			}
1169 			p++;
1170 
1171 			/* spaces may not be allowed */
1172 			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1173 				if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1174 					goto parsing_error;
1175 				}
1176 
1177 				/* trim spaces */
1178 				for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1179 					/* no op */
1180 				}
1181 			}
1182 
1183 			/*
1184 			 * octothorpe means a BER encoded value will follow
1185 			 * FIXME: I don't think DCE will allow it
1186 			 */
1187 			if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1188 				p++;
1189 				attrValueEncoding = LDAP_AVA_BINARY;
1190 				state = B4BINARYVALUE;
1191 				break;
1192 			}
1193 
1194 			/* STRING value expected */
1195 
1196 			/*
1197 			 * if we're pedantic, an attribute type in OID form
1198 			 * SHOULD imply a BER encoded attribute value; we
1199 			 * should at least issue a warning
1200 			 */
1201 			if ( ( flags & LDAP_DN_PEDANTIC )
1202 				&& ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1203 				/* OID attrType SHOULD use binary encoding */
1204 				goto parsing_error;
1205 			}
1206 
1207 			attrValueEncoding = LDAP_AVA_STRING;
1208 
1209 			/*
1210 			 * LDAPv2 allows the attribute value to be quoted;
1211 			 * also, IA5 values are expected, in principle
1212 			 */
1213 			if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1214 				if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1215 					p++;
1216 					state = B4IA5VALUEQUOTED;
1217 					break;
1218 				}
1219 
1220 				if ( LDAP_DN_LDAPV2( flags ) ) {
1221 					state = B4IA5VALUE;
1222 					break;
1223 				}
1224 			}
1225 
1226 			/*
1227 			 * here STRING means RFC 4514 string
1228 			 * FIXME: what about DCE strings?
1229 			 */
1230 			if ( !p[ 0 ] ) {
1231 				/* empty value */
1232 				state = GOTAVA;
1233 			} else {
1234 				state = B4STRINGVALUE;
1235 			}
1236 			break;
1237 
1238 		case B4BINARYVALUE:
1239 			if ( hexstr2binval( p, &attrValue, &p, flags, ctx ) ) {
1240 				goto parsing_error;
1241 			}
1242 
1243 			state = GOTAVA;
1244 			break;
1245 
1246 		case B4STRINGVALUE:
1247 			switch ( LDAP_DN_FORMAT( flags ) ) {
1248 			case LDAP_DN_FORMAT_LDAP:
1249 			case LDAP_DN_FORMAT_LDAPV3:
1250 				if ( str2strval( p, stoplen - ( p - str ),
1251 							&attrValue, &p, flags,
1252 							&attrValueEncoding, ctx ) ) {
1253 					goto parsing_error;
1254 				}
1255 				break;
1256 
1257 			case LDAP_DN_FORMAT_DCE:
1258 				if ( DCE2strval( p, &attrValue, &p, flags, ctx ) ) {
1259 					goto parsing_error;
1260 				}
1261 				break;
1262 
1263 			default:
1264 				assert( 0 );
1265 			}
1266 
1267 			state = GOTAVA;
1268 			break;
1269 
1270 		case B4IA5VALUE:
1271 			if ( IA52strval( p, &attrValue, &p, flags, ctx ) ) {
1272 				goto parsing_error;
1273 			}
1274 
1275 			state = GOTAVA;
1276 			break;
1277 
1278 		case B4IA5VALUEQUOTED:
1279 
1280 			/* lead quote already stripped */
1281 			if ( quotedIA52strval( p, &attrValue,
1282 						&p, flags, ctx ) ) {
1283 				goto parsing_error;
1284 			}
1285 
1286 			state = GOTAVA;
1287 			break;
1288 
1289 		case GOTAVA: {
1290 			int	rdnsep = 0;
1291 
1292 			if ( !( flags & LDAP_DN_SKIP ) ) {
1293 				LDAPAVA *ava;
1294 
1295 				/*
1296 				 * we accept empty values
1297 				 */
1298 				ava = ldapava_new( &attrType, &attrValue,
1299 						attrValueEncoding, ctx );
1300 				if ( ava == NULL ) {
1301 					rc = LDAP_NO_MEMORY;
1302 					goto parsing_error;
1303 				}
1304 				tmpRDN[navas++] = ava;
1305 
1306 				attrValue.bv_val = NULL;
1307 				attrValue.bv_len = 0;
1308 
1309 				/*
1310 				 * prepare room for new AVAs if needed
1311 				 */
1312 				if (navas == num_slots) {
1313 					LDAPAVA **tmp;
1314 
1315 					if ( tmpRDN == tmpRDN_ ) {
1316 						tmp = LDAP_MALLOCX( num_slots * 2 * sizeof( LDAPAVA * ), ctx );
1317 						if ( tmp == NULL ) {
1318 							rc = LDAP_NO_MEMORY;
1319 							goto parsing_error;
1320 						}
1321 						AC_MEMCPY( tmp, tmpRDN, num_slots * sizeof( LDAPAVA * ) );
1322 
1323 					} else {
1324 						tmp = LDAP_REALLOCX( tmpRDN, num_slots * 2 * sizeof( LDAPAVA * ), ctx );
1325 						if ( tmp == NULL ) {
1326 							rc = LDAP_NO_MEMORY;
1327 							goto parsing_error;
1328 						}
1329 					}
1330 
1331 					tmpRDN = tmp;
1332 					num_slots *= 2;
1333 				}
1334 			}
1335 
1336 			/*
1337 			 * if we got an AVA separator ('+', or ',' for DCE )
1338 			 * we expect a new AVA for this RDN; otherwise
1339 			 * we add the RDN to the DN
1340 			 */
1341 			switch ( LDAP_DN_FORMAT( flags ) ) {
1342 			case LDAP_DN_FORMAT_LDAP:
1343 			case LDAP_DN_FORMAT_LDAPV3:
1344 			case LDAP_DN_FORMAT_LDAPV2:
1345 				if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1346 					rdnsep = 1;
1347 				}
1348 				break;
1349 
1350 			case LDAP_DN_FORMAT_DCE:
1351 				if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1352 					rdnsep = 1;
1353 				}
1354 				break;
1355 			}
1356 
1357 			if ( rdnsep ) {
1358 				/*
1359 				 * the RDN is over, phew
1360 				 */
1361 				*n = p;
1362 				if ( !( flags & LDAP_DN_SKIP ) ) {
1363 					newRDN = (LDAPRDN)LDAP_MALLOCX(
1364 						sizeof(LDAPAVA) * (navas+1), ctx );
1365 					if ( newRDN == NULL ) {
1366 						rc = LDAP_NO_MEMORY;
1367 						goto parsing_error;
1368 					} else {
1369 						AC_MEMCPY( newRDN, tmpRDN, sizeof(LDAPAVA *) * navas);
1370 						newRDN[navas] = NULL;
1371 					}
1372 
1373 				}
1374 				rc = LDAP_SUCCESS;
1375 				goto return_result;
1376 			}
1377 
1378 			/* they should have been used in an AVA */
1379 			attrType.bv_val = NULL;
1380 			attrValue.bv_val = NULL;
1381 
1382 			p++;
1383 			state = B4AVA;
1384 			break;
1385 		}
1386 
1387 		default:
1388 			assert( 0 );
1389 			goto parsing_error;
1390 		}
1391 	}
1392 	*n = p;
1393 
1394 parsing_error:;
1395 	/* They are set to NULL after they're used in an AVA */
1396 
1397 	if ( attrValue.bv_val ) {
1398 		LDAP_FREEX( attrValue.bv_val, ctx );
1399 	}
1400 
1401 	for ( navas-- ; navas >= 0; navas-- ) {
1402 		ldapava_free( tmpRDN[navas], ctx );
1403 	}
1404 
1405 return_result:;
1406 
1407 	if ( tmpRDN != tmpRDN_ ) {
1408 		LDAP_FREEX( tmpRDN, ctx );
1409 	}
1410 
1411 	if ( rdn ) {
1412 		*rdn = newRDN;
1413 	}
1414 
1415 	return( rc );
1416 }
1417 
1418 /*
1419  * reads in a UTF-8 string value, unescaping stuff:
1420  * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1421  * '\' + HEXPAIR(p) -> unhex(p)
1422  */
1423 static int
1424 str2strval( const char *str, ber_len_t stoplen, struct berval *val, const char **next, unsigned flags, int *retFlags, void *ctx )
1425 {
1426 	const char 	*p, *end, *startPos, *endPos = NULL;
1427 	ber_len_t	len, escapes;
1428 
1429 	assert( str != NULL );
1430 	assert( val != NULL );
1431 	assert( next != NULL );
1432 
1433 	*next = NULL;
1434 	end = str + stoplen;
1435 	for ( startPos = p = str, escapes = 0; p < end; p++ ) {
1436 		if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1437 			p++;
1438 			if ( p[ 0 ] == '\0' ) {
1439 				return( 1 );
1440 			}
1441 			if ( LDAP_DN_MAYESCAPE( p[ 0 ] ) ) {
1442 				escapes++;
1443 				continue;
1444 			}
1445 
1446 			if ( LDAP_DN_HEXPAIR( p ) ) {
1447 				char c;
1448 
1449 				hexstr2bin( p, &c );
1450 				escapes += 2;
1451 
1452 				if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1453 
1454 					/*
1455 					 * we assume the string is UTF-8
1456 					 */
1457 					*retFlags = LDAP_AVA_NONPRINTABLE;
1458 				}
1459 				p++;
1460 
1461 				continue;
1462 			}
1463 
1464 			if ( LDAP_DN_PEDANTIC & flags ) {
1465 				return( 1 );
1466 			}
1467 			/*
1468 			 * we do not allow escaping
1469 			 * of chars that don't need
1470 			 * to and do not belong to
1471 			 * HEXDIGITS
1472 			 */
1473 			return( 1 );
1474 
1475 		} else if ( !LDAP_DN_ASCII_PRINTABLE( p[ 0 ] ) ) {
1476 			if ( p[ 0 ] == '\0' ) {
1477 				return( 1 );
1478 			}
1479 			*retFlags = LDAP_AVA_NONPRINTABLE;
1480 
1481 		} else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1482 				|| ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1483 			break;
1484 
1485 		} else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1486 			/*
1487 			 * FIXME: maybe we can add
1488 			 * escapes if not pedantic?
1489 			 */
1490 			return( 1 );
1491 		}
1492 	}
1493 
1494 	/*
1495 	 * we do allow unescaped spaces at the end
1496 	 * of the value only in non-pedantic mode
1497 	 */
1498 	if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1499 			!LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1500 		if ( flags & LDAP_DN_PEDANTIC ) {
1501 			return( 1 );
1502 		}
1503 
1504 		/* strip trailing (unescaped) spaces */
1505 		for ( endPos = p - 1;
1506 				endPos > startPos + 1 &&
1507 				LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1508 				!LDAP_DN_ESCAPE( endPos[ -2 ] );
1509 				endPos-- ) {
1510 			/* no op */
1511 		}
1512 	}
1513 
1514 	*next = p;
1515 	if ( flags & LDAP_DN_SKIP ) {
1516 		return( 0 );
1517 	}
1518 
1519 	/*
1520 	 * FIXME: test memory?
1521 	 */
1522 	len = ( endPos ? endPos : p ) - startPos - escapes;
1523 	val->bv_len = len;
1524 
1525 	if ( escapes == 0 ) {
1526 		if ( *retFlags & LDAP_AVA_NONPRINTABLE ) {
1527 			val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1528 			AC_MEMCPY( val->bv_val, startPos, len );
1529 			val->bv_val[ len ] = '\0';
1530 		} else {
1531 			val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1532 		}
1533 
1534 	} else {
1535 		ber_len_t	s, d;
1536 
1537 		val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1538 		for ( s = 0, d = 0; d < len; ) {
1539 			if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1540 				s++;
1541 				if ( LDAP_DN_MAYESCAPE( startPos[ s ] ) ) {
1542 					val->bv_val[ d++ ] =
1543 						startPos[ s++ ];
1544 
1545 				} else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1546 					char 	c;
1547 
1548 					hexstr2bin( &startPos[ s ], &c );
1549 					val->bv_val[ d++ ] = c;
1550 					s += 2;
1551 
1552 				} else {
1553 					/* we should never get here */
1554 					assert( 0 );
1555 				}
1556 
1557 			} else {
1558 				val->bv_val[ d++ ] = startPos[ s++ ];
1559 			}
1560 		}
1561 
1562 		val->bv_val[ d ] = '\0';
1563 		assert( d == len );
1564 	}
1565 
1566 	return( 0 );
1567 }
1568 
1569 static int
1570 DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1571 {
1572 	const char 	*p, *startPos, *endPos = NULL;
1573 	ber_len_t	len, escapes;
1574 
1575 	assert( str != NULL );
1576 	assert( val != NULL );
1577 	assert( next != NULL );
1578 
1579 	*next = NULL;
1580 
1581 	for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1582 		if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1583 			p++;
1584 			if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1585 				escapes++;
1586 
1587 			} else {
1588 				return( 1 );
1589 			}
1590 
1591 		} else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1592 			break;
1593 		}
1594 
1595 		/*
1596 		 * FIXME: can we accept anything else? I guess we need
1597 		 * to stop if a value is not legal
1598 		 */
1599 	}
1600 
1601 	/*
1602 	 * (unescaped) trailing spaces are trimmed must be silently ignored;
1603 	 * so we eat them
1604 	 */
1605 	if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1606 			!LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1607 		if ( flags & LDAP_DN_PEDANTIC ) {
1608 			return( 1 );
1609 		}
1610 
1611 		/* strip trailing (unescaped) spaces */
1612 		for ( endPos = p - 1;
1613 				endPos > startPos + 1 &&
1614 				LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1615 				!LDAP_DN_ESCAPE( endPos[ -2 ] );
1616 				endPos-- ) {
1617 			/* no op */
1618 		}
1619 	}
1620 
1621 	*next = p;
1622 	if ( flags & LDAP_DN_SKIP ) {
1623 		return( 0 );
1624 	}
1625 
1626 	len = ( endPos ? endPos : p ) - startPos - escapes;
1627 	val->bv_len = len;
1628 	if ( escapes == 0 ){
1629 		val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1630 
1631 	} else {
1632 		ber_len_t	s, d;
1633 
1634 		val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1635 		for ( s = 0, d = 0; d < len; ) {
1636 			/*
1637 			 * This point is reached only if escapes
1638 			 * are properly used, so all we need to
1639 			 * do is eat them
1640 			 */
1641 			if (  LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1642 				s++;
1643 
1644 			}
1645 			val->bv_val[ d++ ] = startPos[ s++ ];
1646 		}
1647 		val->bv_val[ d ] = '\0';
1648 		assert( strlen( val->bv_val ) == len );
1649 	}
1650 
1651 	return( 0 );
1652 }
1653 
1654 static int
1655 IA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1656 {
1657 	const char 	*p, *startPos, *endPos = NULL;
1658 	ber_len_t	len, escapes;
1659 
1660 	assert( str != NULL );
1661 	assert( val != NULL );
1662 	assert( next != NULL );
1663 
1664 	*next = NULL;
1665 
1666 	/*
1667 	 * LDAPv2 (RFC 1779)
1668 	 */
1669 
1670 	for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1671 		if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1672 			p++;
1673 			if ( p[ 0 ] == '\0' ) {
1674 				return( 1 );
1675 			}
1676 
1677 			if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1678 					&& ( LDAP_DN_PEDANTIC & flags ) ) {
1679 				return( 1 );
1680 			}
1681 			escapes++;
1682 
1683 		} else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1684 			break;
1685 		}
1686 
1687 		/*
1688 		 * FIXME: can we accept anything else? I guess we need
1689 		 * to stop if a value is not legal
1690 		 */
1691 	}
1692 
1693 	/* strip trailing (unescaped) spaces */
1694 	for ( endPos = p;
1695 			endPos > startPos + 1 &&
1696 			LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1697 			!LDAP_DN_ESCAPE( endPos[ -2 ] );
1698 			endPos-- ) {
1699 		/* no op */
1700 	}
1701 
1702 	*next = p;
1703 	if ( flags & LDAP_DN_SKIP ) {
1704 		return( 0 );
1705 	}
1706 
1707 	len = ( endPos ? endPos : p ) - startPos - escapes;
1708 	val->bv_len = len;
1709 	if ( escapes == 0 ) {
1710 		val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1711 
1712 	} else {
1713 		ber_len_t	s, d;
1714 
1715 		val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1716 		for ( s = 0, d = 0; d < len; ) {
1717 			if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1718 				s++;
1719 			}
1720 			val->bv_val[ d++ ] = startPos[ s++ ];
1721 		}
1722 		val->bv_val[ d ] = '\0';
1723 		assert( strlen( val->bv_val ) == len );
1724 	}
1725 
1726 	return( 0 );
1727 }
1728 
1729 static int
1730 quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1731 {
1732 	const char 	*p, *startPos, *endPos = NULL;
1733 	ber_len_t	len;
1734 	unsigned	escapes = 0;
1735 
1736 	assert( str != NULL );
1737 	assert( val != NULL );
1738 	assert( next != NULL );
1739 
1740 	*next = NULL;
1741 
1742 	/* initial quote already eaten */
1743 	for ( startPos = p = str; p[ 0 ]; p++ ) {
1744 		/*
1745 		 * According to RFC 1779, the quoted value can
1746 		 * contain escaped as well as unescaped special values;
1747 		 * as a consequence we tolerate escaped values
1748 		 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1749 		 * (e.g. '","' -> '\,').
1750 		 */
1751 		if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1752 			if ( p[ 1 ] == '\0' ) {
1753 				return( 1 );
1754 			}
1755 			p++;
1756 
1757 			if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1758 					&& ( LDAP_DN_PEDANTIC & flags ) ) {
1759 				/*
1760 				 * do we allow to escape normal chars?
1761 				 * LDAPv2 does not allow any mechanism
1762 				 * for escaping chars with '\' and hex
1763 				 * pair
1764 				 */
1765 				return( 1 );
1766 			}
1767 			escapes++;
1768 
1769 		} else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1770 			endPos = p;
1771 			/* eat closing quotes */
1772 			p++;
1773 			break;
1774 		}
1775 
1776 		/*
1777 		 * FIXME: can we accept anything else? I guess we need
1778 		 * to stop if a value is not legal
1779 		 */
1780 	}
1781 
1782 	if ( endPos == NULL ) {
1783 		return( 1 );
1784 	}
1785 
1786 	/* Strip trailing (unescaped) spaces */
1787 	for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1788 		/* no op */
1789 	}
1790 
1791 	*next = p;
1792 	if ( flags & LDAP_DN_SKIP ) {
1793 		return( 0 );
1794 	}
1795 
1796 	len = endPos - startPos - escapes;
1797 	assert( endPos >= startPos + escapes );
1798 	val->bv_len = len;
1799 	if ( escapes == 0 ) {
1800 		val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
1801 
1802 	} else {
1803 		ber_len_t	s, d;
1804 
1805 		val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1806 		val->bv_len = len;
1807 
1808 		for ( s = d = 0; d < len; ) {
1809 			if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1810 				s++;
1811 			}
1812 			val->bv_val[ d++ ] = str[ s++ ];
1813 		}
1814 		val->bv_val[ d ] = '\0';
1815 		assert( strlen( val->bv_val ) == len );
1816 	}
1817 
1818 	return( 0 );
1819 }
1820 
1821 static int
1822 hexstr2bin( const char *str, char *c )
1823 {
1824 	char	c1, c2;
1825 
1826 	assert( str != NULL );
1827 	assert( c != NULL );
1828 
1829 	c1 = str[ 0 ];
1830 	c2 = str[ 1 ];
1831 
1832 	if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1833 		*c = c1 - '0';
1834 
1835 	} else {
1836 		if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) {
1837 			*c = c1 - 'A' + 10;
1838 		} else {
1839 			assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) );
1840 			*c = c1 - 'a' + 10;
1841 		}
1842 	}
1843 
1844 	*c <<= 4;
1845 
1846 	if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1847 		*c += c2 - '0';
1848 
1849 	} else {
1850 		if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) {
1851 			*c += c2 - 'A' + 10;
1852 		} else {
1853 			assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) );
1854 			*c += c2 - 'a' + 10;
1855 		}
1856 	}
1857 
1858 	return( 0 );
1859 }
1860 
1861 static int
1862 hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
1863 {
1864 	const char 	*p, *startPos, *endPos = NULL;
1865 	ber_len_t	len;
1866 	ber_len_t	s, d;
1867 
1868 	assert( str != NULL );
1869 	assert( val != NULL );
1870 	assert( next != NULL );
1871 
1872 	*next = NULL;
1873 
1874 	for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1875 		switch ( LDAP_DN_FORMAT( flags ) ) {
1876 		case LDAP_DN_FORMAT_LDAPV3:
1877 			if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1878 				goto end_of_value;
1879 			}
1880 			break;
1881 
1882 		case LDAP_DN_FORMAT_LDAP:
1883 		case LDAP_DN_FORMAT_LDAPV2:
1884 			if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1885 				goto end_of_value;
1886 			}
1887 			break;
1888 
1889 		case LDAP_DN_FORMAT_DCE:
1890 			if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1891 				goto end_of_value;
1892 			}
1893 			break;
1894 		}
1895 
1896 		if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1897 			if ( flags & LDAP_DN_PEDANTIC ) {
1898 				return( 1 );
1899 			}
1900 			endPos = p;
1901 
1902 			for ( ; p[ 0 ]; p++ ) {
1903 				switch ( LDAP_DN_FORMAT( flags ) ) {
1904 				case LDAP_DN_FORMAT_LDAPV3:
1905 					if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1906 						goto end_of_value;
1907 					}
1908 					break;
1909 
1910 				case LDAP_DN_FORMAT_LDAP:
1911 				case LDAP_DN_FORMAT_LDAPV2:
1912 					if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1913 						goto end_of_value;
1914 					}
1915 					break;
1916 
1917 				case LDAP_DN_FORMAT_DCE:
1918 					if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1919 						goto end_of_value;
1920 					}
1921 					break;
1922 				}
1923 			}
1924 			break;
1925 		}
1926 
1927 		if ( !LDAP_DN_HEXPAIR( p ) ) {
1928 			return( 1 );
1929 		}
1930 	}
1931 
1932 end_of_value:;
1933 
1934 	*next = p;
1935 	if ( flags & LDAP_DN_SKIP ) {
1936 		return( 0 );
1937 	}
1938 
1939 	len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1940 	/* must be even! */
1941 	assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1942 
1943 	val->bv_len = len;
1944 	val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1945 	if ( val->bv_val == NULL ) {
1946 		return( LDAP_NO_MEMORY );
1947 	}
1948 
1949 	for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1950 		char 	c;
1951 
1952 		hexstr2bin( &startPos[ s ], &c );
1953 
1954 		val->bv_val[ d ] = c;
1955 	}
1956 
1957 	val->bv_val[ d ] = '\0';
1958 
1959 	return( 0 );
1960 }
1961 
1962 /*
1963  * convert a byte in a hexadecimal pair
1964  */
1965 static int
1966 byte2hexpair( const char *val, char *pair )
1967 {
1968 	static const char	hexdig[] = "0123456789ABCDEF";
1969 
1970 	assert( val != NULL );
1971 	assert( pair != NULL );
1972 
1973 	/*
1974 	 * we assume the string has enough room for the hex encoding
1975 	 * of the value
1976 	 */
1977 
1978 	pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1979 	pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1980 
1981 	return( 0 );
1982 }
1983 
1984 /*
1985  * convert a binary value in hexadecimal pairs
1986  */
1987 static int
1988 binval2hexstr( struct berval *val, char *str )
1989 {
1990 	ber_len_t	s, d;
1991 
1992 	assert( val != NULL );
1993 	assert( str != NULL );
1994 
1995 	if ( val->bv_len == 0 ) {
1996 		return( 0 );
1997 	}
1998 
1999 	/*
2000 	 * we assume the string has enough room for the hex encoding
2001 	 * of the value
2002 	 */
2003 
2004 	for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
2005 		byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2006 	}
2007 
2008 	return( 0 );
2009 }
2010 
2011 /*
2012  * Length of the string representation, accounting for escaped hex
2013  * of UTF-8 chars
2014  */
2015 static int
2016 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
2017 {
2018 	ber_len_t	l, cl = 1;
2019 	char		*p, *end;
2020 	int		escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
2021 #ifdef PRETTY_ESCAPE
2022 	int		escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
2023 #endif /* PRETTY_ESCAPE */
2024 
2025 	assert( val != NULL );
2026 	assert( len != NULL );
2027 
2028 	*len = 0;
2029 	if ( val->bv_len == 0 ) {
2030 		return( 0 );
2031 	}
2032 
2033 	end = val->bv_val + val->bv_len - 1;
2034 	for ( l = 0, p = val->bv_val; p <= end; p += cl ) {
2035 
2036 		/*
2037 		 * escape '%x00'
2038 		 */
2039 		if ( p[ 0 ] == '\0' ) {
2040 			cl = 1;
2041 			l += 3;
2042 			continue;
2043 		}
2044 
2045 		cl = LDAP_UTF8_CHARLEN2( p, cl );
2046 		if ( cl == 0 ) {
2047 			/* illegal utf-8 char! */
2048 			return( -1 );
2049 
2050 		} else if ( cl > 1 ) {
2051 			ber_len_t cnt;
2052 
2053 			for ( cnt = 1; cnt < cl; cnt++ ) {
2054 				if ( ( p[ cnt ] & 0xc0 ) != 0x80 ) {
2055 					return( -1 );
2056 				}
2057 			}
2058 			l += escaped_byte_len * cl;
2059 
2060 		} else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2061 				|| LDAP_DN_SHOULDESCAPE( p[ 0 ] )
2062 				|| ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2063 				|| ( p == end && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2064 #ifdef PRETTY_ESCAPE
2065 #if 0
2066 			if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
2067 #else
2068 			if ( LDAP_DN_WILLESCAPE_CHAR( p[ 0 ] ) ) {
2069 #endif
2070 
2071 				/*
2072 				 * there might be some chars we want
2073 				 * to escape in form of a couple
2074 				 * of hexdigits for optimization purposes
2075 				 */
2076 				l += 3;
2077 
2078 			} else {
2079 				l += escaped_ascii_len;
2080 			}
2081 #else /* ! PRETTY_ESCAPE */
2082 			l += 3;
2083 #endif /* ! PRETTY_ESCAPE */
2084 
2085 		} else {
2086 			l++;
2087 		}
2088 	}
2089 
2090 	*len = l;
2091 
2092 	return( 0 );
2093 }
2094 
2095 /*
2096  * convert to string representation, escaping with hex the UTF-8 stuff;
2097  * assume the destination has enough room for escaping
2098  */
2099 static int
2100 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2101 {
2102 	ber_len_t	s, d, end;
2103 
2104 	assert( val != NULL );
2105 	assert( str != NULL );
2106 	assert( len != NULL );
2107 
2108 	if ( val->bv_len == 0 ) {
2109 		*len = 0;
2110 		return( 0 );
2111 	}
2112 
2113 	/*
2114 	 * we assume the string has enough room for the hex encoding
2115 	 * of the value
2116 	 */
2117 	for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2118 		ber_len_t	cl;
2119 
2120 		/*
2121 		 * escape '%x00'
2122 		 */
2123 		if ( val->bv_val[ s ] == '\0' ) {
2124 			cl = 1;
2125 			str[ d++ ] = '\\';
2126 			str[ d++ ] = '0';
2127 			str[ d++ ] = '0';
2128 			s++;
2129 			continue;
2130 		}
2131 
2132 		/*
2133 		 * The length was checked in strval2strlen();
2134 		 * LDAP_UTF8_CHARLEN() should suffice
2135 		 */
2136 		cl = LDAP_UTF8_CHARLEN2( &val->bv_val[ s ], cl );
2137 		assert( cl > 0 );
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