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