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