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