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