getdn.c 66.7 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
5
6
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */
/*  Portions
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
8
9
10
11
12
 *  Copyright (c) 1994 Regents of the University of Michigan.
 *  All rights reserved.
 *
 *  getdn.c
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
13
14
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
15
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
16
17

#include <ac/stdlib.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
18
19
20
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
21

22
#include "ldap-int.h"
Howard Chu's avatar
Howard Chu committed
23
#include "ldap_schema.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
24

25
26
27
/* extension to UFN that turns trailing "dc=value" rdns in DNS style,
 * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
#define DC_IN_UFN
28
#define PRETTY_ESCAPE
29

30
/* parsing/printing routines */
31
static int str2strval( const char *str, ber_len_t stoplen, struct berval *val, 
32
		const char **next, unsigned flags, unsigned *retFlags );
33
static int DCE2strval( const char *str, struct berval *val, 
34
		const char **next, unsigned flags );
35
static int IA52strval( const char *str, struct berval *val, 
36
		const char **next, unsigned flags );
37
static int quotedIA52strval( const char *str, struct berval *val, 
38
		const char **next, unsigned flags );
39
static int hexstr2binval( const char *str, struct berval *val, 
40
41
42
43
		const char **next, unsigned flags );
static int hexstr2bin( const char *str, char *c );
static int byte2hexpair( const char *val, char *pair );
static int binval2hexstr( struct berval *val, char *str );
44
45
static int strval2strlen( struct berval *val, unsigned flags, 
		ber_len_t *len );
46
47
static int strval2str( struct berval *val, char *str, unsigned flags, 
		ber_len_t *len );
48
49
static int strval2IA5strlen( struct berval *val, unsigned flags,
		ber_len_t *len );
50
51
static int strval2IA5str( struct berval *val, char *str, unsigned flags, 
		ber_len_t *len );
52
53
static int strval2DCEstrlen( struct berval *val, unsigned flags,
		ber_len_t *len );
54
55
static int strval2DCEstr( struct berval *val, char *str, unsigned flags, 
		ber_len_t *len );
56
57
static int strval2ADstrlen( struct berval *val, unsigned flags,
		ber_len_t *len );
58
59
static int strval2ADstr( struct berval *val, char *str, unsigned flags, 
		ber_len_t *len );
Howard Chu's avatar
Howard Chu committed
60
static int dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN );
61
62

/* AVA helpers */
63
64
static LDAPAVA * ldapava_new(
	const struct berval *attr, const struct berval *val, unsigned flags );
65
66

/* Higher level helpers */
67
static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
68
		int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
69
static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
70
		int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
71
72
73
74
75
76
static int rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len  );
static int rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len );
static int rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
static int rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flag, ber_len_t *len, int first );
static int rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
static int rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first );
77

78
79
80
/*
 * RFC 1823 ldap_get_dn
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
81
82
83
84
85
86
87
88
89
90
91
92
93
94
char *
ldap_get_dn( LDAP *ld, LDAPMessage *entry )
{
	char		*dn;
	BerElement	tmp;

	Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );

	if ( entry == NULL ) {
		ld->ld_errno = LDAP_PARAM_ERROR;
		return( NULL );
	}

	tmp = *entry->lm_ber;	/* struct copy */
95
	if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
96
97
98
99
100
101
102
		ld->ld_errno = LDAP_DECODING_ERROR;
		return( NULL );
	}

	return( dn );
}

103
104
105
/*
 * RFC 1823 ldap_dn2ufn
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
106
char *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
107
ldap_dn2ufn( LDAP_CONST char *dn )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
108
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
109
110
	char	*out = NULL;

111
112
	Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
113
	( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
114
		&out, LDAP_DN_FORMAT_UFN );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
115
116
	
	return( out );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
117
118
}

119
120
121
/*
 * RFC 1823 ldap_explode_dn
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
122
char **
Kurt Zeilenga's avatar
Kurt Zeilenga committed
123
ldap_explode_dn( LDAP_CONST char *dn, int notypes )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
124
{
125
126
127
128
129
130
131
	LDAPDN	*tmpDN;
	char	**values = NULL;
	int	iRDN;
	unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
	
	Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );

132
	if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP ) 
133
			!= LDAP_SUCCESS ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
134
135
136
137
138
139
140
141
142
		return NULL;
	}

	if( tmpDN == NULL ) {
		values = LDAP_MALLOC( sizeof( char * ) );
		if( values == NULL ) return NULL;

		values[0] = NULL;
		return values;
143
144
	}

145
	for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ );
146

147
148
149
150
	values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) );
	if ( values == NULL ) {
		ldap_dnfree( tmpDN );
		return NULL;
151
152
	}

153
154
	for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ ) {
		ldap_rdn2str( tmpDN[ 0 ][ iRDN ], &values[ iRDN ], flag );
155
156
	}
	ldap_dnfree( tmpDN );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
157
	values[ iRDN ] = NULL;
158

Kurt Zeilenga's avatar
Kurt Zeilenga committed
159
	return values;
Hallvard Furuseth's avatar
Hallvard Furuseth committed
160
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
161

Hallvard Furuseth's avatar
Hallvard Furuseth committed
162
char **
Kurt Zeilenga's avatar
Kurt Zeilenga committed
163
ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
Hallvard Furuseth's avatar
Hallvard Furuseth committed
164
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
165
166
167
168
	LDAPRDN		*tmpRDN;
	char		**values = NULL;
	const char 	*p;
	int		iAVA;
169
170
171
172
	
	Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );

	/*
Pierangelo Masarati's avatar
Pierangelo Masarati committed
173
174
175
	 * we only parse the first rdn
	 * FIXME: we prefer efficiency over checking if the _ENTIRE_
	 * dn can be parsed
176
	 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
177
	if ( ldap_str2rdn( rdn, &tmpRDN, (char **) &p, LDAP_DN_FORMAT_LDAP ) 
178
179
180
181
			!= LDAP_SUCCESS ) {
		return( NULL );
	}

182
	for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) ;
183
184
185
186
187
188
	values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) );
	if ( values == NULL ) {
		ldap_rdnfree( tmpRDN );
		return( NULL );
	}

189
	for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) {
190
		ber_len_t	l = 0, vl, al = 0;
191
		char		*str;
192
		LDAPAVA		*ava = tmpRDN[ 0 ][ iAVA ];
193
194
		
		if ( ava->la_flags == LDAP_AVA_BINARY ) {
195
			vl = 1 + 2 * ava->la_value.bv_len;
196

197
		} else {
198
			if ( strval2strlen( &ava->la_value, 
199
200
201
						ava->la_flags, &vl ) ) {
				goto error_return;
			}
202
203
204
		}
		
		if ( !notypes ) {
205
206
			al = ava->la_attr.bv_len;
			l = vl + ava->la_attr.bv_len + 1;
207
208

			str = LDAP_MALLOC( l + 1 );
209
210
			AC_MEMCPY( str, ava->la_attr.bv_val, 
					ava->la_attr.bv_len );
211
			str[ al++ ] = '=';
212

213
214
215
216
217
218
219
		} else {
			l = vl;
			str = LDAP_MALLOC( l + 1 );
		}
		
		if ( ava->la_flags == LDAP_AVA_BINARY ) {
			str[ al++ ] = '#';
220
			if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) {
221
222
223
				goto error_return;
			}

224
		} else {
225
			if ( strval2str( &ava->la_value, &str[ al ], 
226
227
228
					ava->la_flags, &vl ) ) {
				goto error_return;
			}
229
230
231
232
233
234
235
		}

		str[ l ] = '\0';
		values[ iAVA ] = str;
	}
	values[ iAVA ] = NULL;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
236
	ldap_rdnfree( tmpRDN );
237

238
	return( values );
239

240
error_return:;
241
	LBER_VFREE( values );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
242
	ldap_rdnfree( tmpRDN );
243
	return( NULL );
244
245
}

246
247
248
char *
ldap_dn2dcedn( LDAP_CONST char *dn )
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
249
250
	char	*out = NULL;

251
252
	Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
253
254
	( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
				   &out, LDAP_DN_FORMAT_DCE );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
255
256

	return( out );
257
258
259
260
261
}

char *
ldap_dcedn2dn( LDAP_CONST char *dce )
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
262
263
	char	*out = NULL;

264
265
	Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
266
	( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
267
268

	return( out );
Hallvard Furuseth's avatar
Hallvard Furuseth committed
269
270
}

271
272
273
char *
ldap_dn2ad_canonical( LDAP_CONST char *dn )
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
274
275
	char	*out = NULL;

276
277
	Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
278
	( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP, 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
279
280
281
		       &out, LDAP_DN_FORMAT_AD_CANONICAL );

	return( out );
282
283
284
}

/*
Pierangelo Masarati's avatar
Pierangelo Masarati committed
285
 * function that changes the string representation of dnin
286
287
288
 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
 * 
 * fin can be one of:
289
290
 * 	LDAP_DN_FORMAT_LDAP		(rfc 2253 and ldapbis liberal, 
 * 					plus some rfc 1779)
291
292
293
294
 * 	LDAP_DN_FORMAT_LDAPV3		(rfc 2253 and ldapbis)
 * 	LDAP_DN_FORMAT_LDAPV2		(rfc 1779)
 * 	LDAP_DN_FORMAT_DCE		(?)
 *
295
296
297
 * fout can be any of the above except
 * 	LDAP_DN_FORMAT_LDAP
 * plus:
298
299
300
 * 	LDAP_DN_FORMAT_UFN		(rfc 1781, partial and with extensions)
 * 	LDAP_DN_FORMAT_AD_CANONICAL	(?)
 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
301
int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
302
303
ldap_dn_normalize( LDAP_CONST char *dnin,
	unsigned fin, char **dnout, unsigned fout )
304
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
305
	int	rc;
306
307
	LDAPDN	*tmpDN = NULL;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
308
309
	Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
310
311
312
313
314
315
	assert( dnout );

	*dnout = NULL;

	if ( dnin == NULL ) {
		return( LDAP_SUCCESS );
316
317
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
318
319
320
	rc = ldap_str2dn( dnin , &tmpDN, fin );
	if ( rc != LDAP_SUCCESS ) {
		return( rc );
321
322
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
323
	rc = ldap_dn2str( tmpDN, dnout, fout );
324

325
	ldap_dnfree( tmpDN );
326

Pierangelo Masarati's avatar
Pierangelo Masarati committed
327
	return( rc );
328
}
329
330
331
332

/* States */
#define B4AVA			0x0000

333
/* #define	B4ATTRTYPE		0x0001 */
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#define B4OIDATTRTYPE		0x0002
#define B4STRINGATTRTYPE	0x0003

#define B4AVAEQUALS		0x0100
#define B4AVASEP		0x0200
#define B4RDNSEP		0x0300
#define GOTAVA			0x0400

#define B4ATTRVALUE		0x0010
#define B4STRINGVALUE		0x0020
#define B4IA5VALUEQUOTED	0x0030
#define B4IA5VALUE		0x0040
#define B4BINARYVALUE		0x0050

Kurt Zeilenga's avatar
Kurt Zeilenga committed
348
349
350
351
352
/*
 * Helpers (mostly from slap.h)
 * c is assumed to Unicode in an ASCII compatible format (UTF-8)
 * Macros assume "C" Locale (ASCII)
 */
353
354
#define LDAP_DN_ASCII_SPACE(c) \
	( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
355
356
357
358
359
360
361
362
363
#define LDAP_DN_ASCII_LOWER(c)		LDAP_LOWER(c)
#define LDAP_DN_ASCII_UPPER(c)		LDAP_UPPER(c)
#define LDAP_DN_ASCII_ALPHA(c)		LDAP_ALPHA(c)

#define LDAP_DN_ASCII_DIGIT(c)		LDAP_DIGIT(c)
#define LDAP_DN_ASCII_LCASE_HEXALPHA(c)	LDAP_HEXLOWER(c)
#define LDAP_DN_ASCII_UCASE_HEXALPHA(c)	LDAP_HEXUPPER(c)
#define LDAP_DN_ASCII_HEXDIGIT(c)	LDAP_HEX(c)
#define LDAP_DN_ASCII_ALNUM(c)		LDAP_ALNUM(c)
364
365
366
#define LDAP_DN_ASCII_PRINTABLE(c)	( (c) >= ' ' && (c) <= '~' )

/* attribute type */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
367
368
369
#define LDAP_DN_OID_LEADCHAR(c)		LDAP_DIGIT(c)
#define LDAP_DN_DESC_LEADCHAR(c)	LDAP_ALPHA(c)
#define LDAP_DN_DESC_CHAR(c)		LDAP_LDH(c)
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
#define LDAP_DN_LANG_SEP(c)		( (c) == ';' )
#define LDAP_DN_ATTRDESC_CHAR(c) \
	( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )

/* special symbols */
#define LDAP_DN_AVA_EQUALS(c)		( (c) == '=' )
#define LDAP_DN_AVA_SEP(c)		( (c) == '+' )
#define LDAP_DN_RDN_SEP(c)		( (c) == ',' )
#define LDAP_DN_RDN_SEP_V2(c)		( LDAP_DN_RDN_SEP(c) || (c) == ';' )
#define LDAP_DN_OCTOTHORPE(c)		( (c) == '#' )
#define LDAP_DN_QUOTES(c)		( (c) == '\"' )
#define LDAP_DN_ESCAPE(c)		( (c) == '\\' )
#define LDAP_DN_VALUE_END(c) \
	( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
#define LDAP_DN_NE(c) \
	( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
	  || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
387
388
389
#define LDAP_DN_MAYESCAPE(c) \
	( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \
	  || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) )
390
391
#define LDAP_DN_NEEDESCAPE(c) \
	( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
392
#define LDAP_DN_NEEDESCAPE_LEAD(c) 	LDAP_DN_MAYESCAPE(c)
393
#define LDAP_DN_NEEDESCAPE_TRAIL(c) \
394
	( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
395
396
397
398
#define LDAP_DN_WILLESCAPE_CHAR(c) \
	( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) )
#define LDAP_DN_IS_PRETTY(f)		( (f) & LDAP_DN_PRETTY )
#define LDAP_DN_WILLESCAPE_HEX(f, c) \
399
	( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424

/* LDAPv2 */
#define	LDAP_DN_VALUE_END_V2(c) \
	( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
/* RFC 1779 */
#define	LDAP_DN_V2_SPECIAL(c) \
	  ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
	    || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
	    || LDAP_DN_OCTOTHORPE(c) )
#define LDAP_DN_V2_PAIR(c) \
	  ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )

/*
 * DCE (mostly from Luke Howard and IBM implementation for AIX)
 *
 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
 * Here escapes and valid chars for GDS are considered; as soon as more
 * specific info is found, the macros will be updated.
 *
 * Chars:	'a'-'z', 'A'-'Z', '0'-'9', 
 *		'.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
 *
 * Metachars:	'/', ',', '=', '\'.
 *
 * the '\' is used to escape other metachars.
425
426
427
428
 *
 * Assertion:		'='
 * RDN separator:	'/'
 * AVA separator:	','
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
 * 
 * Attribute types must start with alphabetic chars and can contain 
 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
 */
#define LDAP_DN_RDN_SEP_DCE(c)		( (c) == '/' )
#define LDAP_DN_AVA_SEP_DCE(c)		( (c) == ',' )
#define LDAP_DN_ESCAPE_DCE(c)		( LDAP_DN_ESCAPE(c) )
#define	LDAP_DN_VALUE_END_DCE(c) \
	( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
#define LDAP_DN_NEEDESCAPE_DCE(c) \
	( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )

/* AD Canonical */
#define LDAP_DN_RDN_SEP_AD(c)		( (c) == '/' )
#define LDAP_DN_ESCAPE_AD(c)		( LDAP_DN_ESCAPE(c) )
#define LDAP_DN_AVA_SEP_AD(c)		( (c) == ',' )	/* assume same as DCE */
#define	LDAP_DN_VALUE_END_AD(c) \
	( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
#define LDAP_DN_NEEDESCAPE_AD(c) \
	( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )

/* generics */
#define LDAP_DN_HEXPAIR(s) \
	( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
453
454
/* better look at the AttributeDescription? */

455
456
/* FIXME: no composite rdn or non-"dc" types, right?
 * (what about "dc" in OID form?) */
457
/* FIXME: we do not allow binary values in domain, right? */
458
/* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
459
460
461
462
/* NOTE: don't use strcasecmp() as it is locale specific! */
#define	LDAP_DC_ATTR	"dc"
#define	LDAP_DC_ATTRU	"DC"
#define LDAP_DN_IS_RDN_DC( r ) \
463
	( (r) && (r)[0][0] && !(r)[0][1] \
Kurt Zeilenga's avatar
Kurt Zeilenga committed
464
	  && ((r)[0][0]->la_flags == LDAP_AVA_STRING) \
465
466
467
468
469
	  && ((r)[0][0]->la_attr.bv_len == 2) \
	  && (((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \
		|| ((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \
	  && (((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \
		|| ((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1])))
470

471
/* Composite rules */
472
#define LDAP_DN_ALLOW_ONE_SPACE(f) \
473
	( LDAP_DN_LDAPV2(f) \
474
	  || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
475
#define LDAP_DN_ALLOW_SPACES(f) \
476
	( LDAP_DN_LDAPV2(f) \
477
	  || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
478
479
#define LDAP_DN_LDAP(f) \
	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
480
481
482
483
484
485
486
487
488
489
490
491
492
#define LDAP_DN_LDAPV3(f) \
	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
#define LDAP_DN_LDAPV2(f) \
	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
#define LDAP_DN_DCE(f) \
	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
#define LDAP_DN_UFN(f) \
	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
#define LDAP_DN_ADC(f) \
	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
#define LDAP_DN_FORMAT(f)		( (f) & LDAP_DN_FORMAT_MASK )

/*
493
494
 * LDAPAVA helpers (will become part of the API for operations 
 * on structural representations of DNs).
495
 */
496
LDAPAVA *
497
498
ldapava_new( const struct berval *attr, const struct berval *val, 
		unsigned flags )
499
500
501
502
503
504
{
	LDAPAVA	*ava;

	assert( attr );
	assert( val );

Howard Chu's avatar
Howard Chu committed
505
	ava = LDAP_MALLOC( sizeof( LDAPAVA ) + attr->bv_len + 1 );
506
507
508
	
	/* should we test it? */
	if ( ava == NULL ) {
509
		return( NULL );
510
511
	}

Howard Chu's avatar
Howard Chu committed
512
513
514
515
516
	ava->la_attr.bv_len = attr->bv_len;
	ava->la_attr.bv_val = (char *)(ava+1);
	AC_MEMCPY( ava->la_attr.bv_val, attr->bv_val, attr->bv_len );
	ava->la_attr.bv_val[attr->bv_len] = '\0';

517
	ava->la_value = *val;
518
519
	ava->la_flags = flags;

520
521
	ava->la_private = NULL;

522
	return( ava );
523
524
}

525
void
526
ldap_avafree( LDAPAVA *ava )
527
528
529
{
	assert( ava );

530
#if 0
531
532
533
534
	/* ava's private must be freed by caller
	 * (at present let's skip this check because la_private
	 * basically holds static data) */
	assert( ava->la_private == NULL );
535
#endif
536

Howard Chu's avatar
Howard Chu committed
537
538
#if 0
	/* la_attr is now contiguous with ava, not freed separately */
Howard Chu's avatar
Howard Chu committed
539
	LDAP_FREE( ava->la_attr.bv_val );
Howard Chu's avatar
Howard Chu committed
540
#endif
Howard Chu's avatar
Howard Chu committed
541
	LDAP_FREE( ava->la_value.bv_val );
542
543
544
545

	LDAP_FREE( ava );
}

546
void
547
ldap_rdnfree( LDAPRDN *rdn )
548
549
550
551
552
553
554
{
	int iAVA;
	
	if ( rdn == NULL ) {
		return;
	}

555
556
	for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
		ldap_avafree( rdn[ 0 ][ iAVA ] );
557
558
	}

559
	LDAP_FREE( rdn );
560
561
}

562
void
563
ldap_dnfree( LDAPDN *dn )
564
565
566
567
568
569
570
{
	int iRDN;
	
	if ( dn == NULL ) {
		return;
	}

571
572
	for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
		ldap_rdnfree( dn[ 0 ][ iRDN ] );
573
574
	}

575
	LDAP_FREE( dn );
576
577
578
579
}

/*
 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
580
 * into a structural representation of the DN, by separating attribute
581
582
583
584
585
586
587
588
589
590
 * types and values encoded in the more appropriate form, which is
 * string or OID for attribute types and binary form of the BER encoded
 * value or Unicode string. Formats different from LDAPv3 are parsed
 * according to their own rules and turned into the more appropriate
 * form according to LDAPv3.
 *
 * NOTE: I realize the code is getting spaghettish; it is rather
 * experimental and will hopefully turn into something more simple
 * and readable as soon as it works as expected.
 */
591

592
593
594
595
596
597
598
599
/*
 * Default sizes of AVA and RDN static working arrays; if required
 * the are dynamically resized.  The values can be tuned in case
 * of special requirements (e.g. very deep DN trees or high number 
 * of AVAs per RDN).
 */
#define	TMP_AVA_SLOTS	8
#define	TMP_RDN_SLOTS	32
600

Pierangelo Masarati's avatar
Pierangelo Masarati committed
601
int
602
ldap_str2dn( LDAP_CONST char *str, LDAPDN **dn, unsigned flags )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
603
{
604
	struct berval	bv;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
605

606
607
608
	assert( str );

	bv.bv_len = strlen( str );
609
	bv.bv_val = (char *) str;
610
611
	
	return ldap_bv2dn( &bv, dn, flags );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
612
613
}

614
int
615
ldap_bv2dn( struct berval *bv, LDAPDN **dn, unsigned flags )
616
617
{
	const char 	*p;
618
	int		rc = LDAP_DECODING_ERROR;
619
	int		nrdns = 0;
620
621

	LDAPDN		*newDN = NULL;
622
623
	LDAPRDN		*newRDN = NULL, *tmpDN_[TMP_RDN_SLOTS], **tmpDN = tmpDN_;
	int		num_slots = TMP_RDN_SLOTS;
624
	char		*str = bv->bv_val;
625
	char		*end = str + bv->bv_len;
626
	
627
628
	assert( bv );
	assert( bv->bv_val );
629
630
	assert( dn );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
631
	Debug( LDAP_DEBUG_TRACE, "=> ldap_bv2dn(%s,%u)\n%s", str, flags, "" );
632
633
634
635

	*dn = NULL;

	switch ( LDAP_DN_FORMAT( flags ) ) {
636
	case LDAP_DN_FORMAT_LDAP:
637
638
639
640
641
642
643
644
	case LDAP_DN_FORMAT_LDAPV3:
	case LDAP_DN_FORMAT_LDAPV2:
	case LDAP_DN_FORMAT_DCE:
		break;

	/* unsupported in str2dn */
	case LDAP_DN_FORMAT_UFN:
	case LDAP_DN_FORMAT_AD_CANONICAL:
645
		return LDAP_PARAM_ERROR;
646

647
	case LDAP_DN_FORMAT_LBER:
648
	default:
649
		return LDAP_PARAM_ERROR;
650
651
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
652
	if ( bv->bv_len == 0 ) {
653
		return LDAP_SUCCESS;
654
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
655

656
	if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) {
657
		/* value must have embedded NULs */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
658
		return LDAP_DECODING_ERROR;
659
660
661
662
663
664
665
666
667
668
669
670
671
	}

	p = str;
	if ( LDAP_DN_DCE( flags ) ) {
		
		/* 
		 * (from Luke Howard: thnx) A RDN separator is required
		 * at the beginning of an (absolute) DN.
		 */
		if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
			goto parsing_error;
		}
		p++;
672
673
674
675
676
677

	/*
	 * actually we do not want to accept by default the DCE form,
	 * we do not want to auto-detect it
	 */
#if 0
678
679
680
681
682
683
684
685
	} else if ( LDAP_DN_LDAP( flags ) ) {
		/*
		 * if dn starts with '/' let's make it a DCE dn
		 */
		if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
			flags |= LDAP_DN_FORMAT_DCE;
			p++;
		}
686
#endif
687
688
	}

689
	for ( ; p < end; p++ ) {
690
		int		err;
691
692
693
		struct berval 	tmpbv;
		tmpbv.bv_len = bv->bv_len - ( p - str );
		tmpbv.bv_val = (char *)p;
694
		
695
		err = ldap_bv2rdn( &tmpbv, &newRDN, (char **) &p, flags );
696
		if ( err != LDAP_SUCCESS ) {
697
698
699
700
701
702
			goto parsing_error;
		}

		/* 
		 * We expect a rdn separator
		 */
703
		if ( p < end && p[ 0 ] ) {
704
705
706
			switch ( LDAP_DN_FORMAT( flags ) ) {
			case LDAP_DN_FORMAT_LDAPV3:
				if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
707
					rc = LDAP_DECODING_ERROR;
708
709
710
711
					goto parsing_error;
				}
				break;
	
712
			case LDAP_DN_FORMAT_LDAP:
713
714
			case LDAP_DN_FORMAT_LDAPV2:
				if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
715
					rc = LDAP_DECODING_ERROR;
716
717
718
719
					goto parsing_error;
				}
				break;
	
720
721
			case LDAP_DN_FORMAT_DCE:
				if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
722
					rc = LDAP_DECODING_ERROR;
723
724
725
726
727
728
729
					goto parsing_error;
				}
				break;
			}
		}


730
		tmpDN[nrdns++] = newRDN;
731
		newRDN = NULL;
732

733
		/*
734
		 * make the static RDN array dynamically rescalable
735
		 */
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
		if ( nrdns == num_slots ) {
			LDAPRDN	**tmp;

			if ( tmpDN == tmpDN_ ) {
				tmp = LDAP_MALLOC( num_slots * 2 * sizeof( LDAPRDN * ) );
				if ( tmp == NULL ) {
					rc = LDAP_NO_MEMORY;
					goto parsing_error;
				}
				AC_MEMCPY( tmp, tmpDN, num_slots * sizeof( LDAPRDN * ) );

			} else {
				tmp = LDAP_REALLOC( tmpDN, num_slots * 2 * sizeof( LDAPRDN * ) );
				if ( tmp == NULL ) {
					rc = LDAP_NO_MEMORY;
					goto parsing_error;
				}
			}

			tmpDN = tmp;
			num_slots *= 2;
757
		}
758
				
759
		if ( p >= end || p[ 0 ] == '\0' ) {
760
761
762
			/* 
			 * the DN is over, phew
			 */
763
764
765
766
767
768
769
770
			newDN = (LDAPDN *)LDAP_MALLOC( sizeof(LDAPDN) +
				sizeof(LDAPRDN *) * (nrdns+1));
			if ( newDN == NULL ) {
				rc = LDAP_NO_MEMORY;
				goto parsing_error;
			} else {
				int i;

Howard Chu's avatar
Howard Chu committed
771
				newDN[0] = (LDAPRDN **)(newDN+1);
772
773
774
775
776
777
778
779
780
781
782
783

				if ( LDAP_DN_DCE( flags ) ) {
					/* add in reversed order */
					for ( i=0; i<nrdns; i++ )
						newDN[0][i] = tmpDN[nrdns-1-i];
				} else {
					for ( i=0; i<nrdns; i++ )
						newDN[0][i] = tmpDN[i];
				}
				newDN[0][nrdns] = NULL;
				rc = LDAP_SUCCESS;
			}
784
785
786
787
788
789
			goto return_result;
		}
	}
	
parsing_error:;
	if ( newRDN ) {
790
		ldap_rdnfree( newRDN );
791
792
	}

793
	for ( nrdns-- ;nrdns >= 0; nrdns-- ) {
794
		ldap_rdnfree( tmpDN[nrdns] );
795
	}
796
797

return_result:;
798
799
800
801
802

	if ( tmpDN != tmpDN_ ) {
		LDAP_FREE( tmpDN );
	}

803
	Debug( LDAP_DEBUG_TRACE, "<= ldap_bv2dn(%s,%u)=%d\n", str, flags, rc );
804
805
806
807
808
809
810
811
812
813
814
815
816
817
	*dn = newDN;
	
	return( rc );
}

/*
 * ldap_str2rdn
 *
 * Parses a relative DN according to flags up to a rdn separator 
 * or to the end of str.
 * Returns the rdn and a pointer to the string continuation, which
 * corresponds to the rdn separator or to '\0' in case the string is over.
 */
int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
818
819
ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn,
	char **n_in, unsigned flags )
820
{
821
	struct berval	bv;
822
823
824
825
826

	assert( str );
	assert( str[ 0 ] != '\0' );	/* FIXME: is this required? */

	bv.bv_len = strlen( str );
827
	bv.bv_val = (char *) str;
828
829
830
831
832
833
834
835
836

	return ldap_bv2rdn( &bv, rdn, n_in, flags );
}

int
ldap_bv2rdn( struct berval *bv, LDAPRDN **rdn,
	char **n_in, unsigned flags )
{
	const char  	**n = (const char **) n_in;
837
	const char 	*p;
838
	int		navas = 0;
839
	int 		state = B4AVA;
840
	int		rc = LDAP_DECODING_ERROR;
841
842
	int		attrTypeEncoding = LDAP_AVA_STRING, 
			attrValueEncoding = LDAP_AVA_STRING;
843

844
845
	struct berval	attrType = { 0, NULL };
	struct berval 	attrValue = { 0, NULL };
846
847

	LDAPRDN		*newRDN = NULL;
848
849
	LDAPAVA		*tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_;
	int		num_slots = TMP_AVA_SLOTS;
850
851
852

	char		*str;
	ber_len_t	stoplen;
853
	
854
855
856
	assert( bv );
	assert( bv->bv_len );
	assert( bv->bv_val );
857
	assert( rdn || flags & LDAP_DN_SKIP );
858
859
	assert( n );

860
861
862
	str = bv->bv_val;
	stoplen = bv->bv_len;

863
864
865
	if ( rdn ) {
		*rdn = NULL;
	}
866
867
868
	*n = NULL;

	switch ( LDAP_DN_FORMAT( flags ) ) {
869
	case LDAP_DN_FORMAT_LDAP:
870
871
872
873
874
875
876
877
	case LDAP_DN_FORMAT_LDAPV3:
	case LDAP_DN_FORMAT_LDAPV2:
	case LDAP_DN_FORMAT_DCE:
		break;

	/* unsupported in str2dn */
	case LDAP_DN_FORMAT_UFN:
	case LDAP_DN_FORMAT_AD_CANONICAL:
878
		return LDAP_PARAM_ERROR;
879

880
	case LDAP_DN_FORMAT_LBER:
881
	default:
882
		return LDAP_PARAM_ERROR;
883
884
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
885
	if ( bv->bv_len == 0 ) {
886
		return LDAP_SUCCESS;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
887

888
889
	}

890
	if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) {
891
		/* value must have embedded NULs */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
892
		return LDAP_DECODING_ERROR;
893
894
895
	}

	p = str;
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
	for ( ; p[ 0 ] || state == GOTAVA; ) {
		
		/*
		 * The parser in principle advances one token a time,
		 * or toggles state if preferable.
		 */
		switch (state) {

		/*
		 * an AttributeType can be encoded as:
		 * - its string representation; in detail, implementations
		 *   MUST recognize AttributeType string type names listed 
		 *   in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
		 *   MAY recognize other names.
		 * - its numeric OID (a dotted decimal string); in detail
		 *   RFC 2253 asserts that ``Implementations MUST allow 
		 *   an oid in the attribute type to be prefixed by one 
		 *   of the character strings "oid." or "OID."''.  As soon
		 *   as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253 
		 *   I'm not sure whether this is required or not any 
		 *   longer; to be liberal, we still implement it.
		 */
		case B4AVA:
919
920
921
922
923
924
925
926
			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
				if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
					/* error */
					goto parsing_error;
				}
				p++;
			}

927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
				if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
					/* error */
					goto parsing_error;
				}

				/* whitespace is allowed (and trimmed) */
				p++;
				while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
					p++;
				}

				if ( !p[ 0 ] ) {
					/* error: we expected an AVA */
					goto parsing_error;
				}
			}

			/* oid */
			if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
				state = B4OIDATTRTYPE;
				break;
			}
			
			/* else must be alpha */
			if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
				goto parsing_error;
			}
			
			/* LDAPv2 "oid." prefix */
			if ( LDAP_DN_LDAPV2( flags ) ) {
				/*
				 * to be overly pedantic, we only accept
				 * "OID." or "oid."
				 */
				if ( flags & LDAP_DN_PEDANTIC ) {
963
964
					if ( !strncmp( p, "OID.", 4 )
						|| !strncmp( p, "oid.", 4 ) ) {
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
						p += 4;
						state = B4OIDATTRTYPE;
						break;
					}
				} else {
				       if ( !strncasecmp( p, "oid.", 4 ) ) {
					       p += 4;
					       state = B4OIDATTRTYPE;
					       break;
				       }
				}
			}

			state = B4STRINGATTRTYPE;
			break;
		
		case B4OIDATTRTYPE: {
			int 		err = LDAP_SUCCESS;
			
984
			attrType.bv_val = ldap_int_parse_numericoid( &p, &err,
Howard Chu's avatar
Howard Chu committed
985
				LDAP_SCHEMA_SKIP);
986

Howard Chu's avatar
Howard Chu committed
987
988
			if ( err != LDAP_SUCCESS ) {
				goto parsing_error;
989
			}
Howard Chu's avatar
Howard Chu committed
990
			attrType.bv_len = p - attrType.bv_val;
991

992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
			attrTypeEncoding = LDAP_AVA_BINARY;

			state = B4AVAEQUALS;
			break;
		}

		case B4STRINGATTRTYPE: {
			const char 	*startPos, *endPos = NULL;
			ber_len_t 	len;
			
			/* 
			 * the starting char has been found to be
			 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
			 * FIXME: DCE attr types seem to have a more
1006
			 * restrictive syntax (no '-' ...) 
1007
1008
1009
1010
1011
1012
1013
1014
1015
			 */
			for ( startPos = p++; p[ 0 ]; p++ ) {
				if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
					continue;
				}

				if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
					
					/*
1016
					 * RFC 2253 does not explicitly
1017
1018
1019
1020
1021
1022
1023
1024
					 * allow lang extensions to attribute 
					 * types in DNs ... 
					 */
					if ( flags & LDAP_DN_PEDANTIC ) {
						goto parsing_error;
					}

					/*
1025
1026
					 * we trim ';' and following lang 
					 * and so from attribute types
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
					 */
					endPos = p;
					for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
							|| LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
						/* no op */ ;
					}
					break;
				}
				break;
			}

			len = ( endPos ? endPos : p ) - startPos;
			if ( len == 0 ) {
				goto parsing_error;
			}
			
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
			attrTypeEncoding = LDAP_AVA_STRING;

			/*
			 * here we need to decide whether to use it as is 
			 * or turn it in OID form; as a consequence, we
			 * need to decide whether to binary encode the value
			 */
			
			state = B4AVAEQUALS;

			if ( flags & LDAP_DN_SKIP ) {
				break;
			}

Howard Chu's avatar
Howard Chu committed
1057
			attrType.bv_val = (char *)startPos;
1058
			attrType.bv_len = len;
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123

			break;
		}
				
		case B4AVAEQUALS:
			/* spaces may not be allowed */
			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
				if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
					goto parsing_error;
				}
			
				/* trim spaces */
				for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
					/* no op */
				}
			}

			/* need equal sign */
			if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
				goto parsing_error;
			}
			p++;

			/* spaces may not be allowed */
			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
				if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
					goto parsing_error;
				}

				/* trim spaces */
				for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
					/* no op */
				}
			}

			/*
			 * octothorpe means a BER encoded value will follow
			 * FIXME: I don't think DCE will allow it
			 */
			if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
				p++;
				attrValueEncoding = LDAP_AVA_BINARY;
				state = B4BINARYVALUE;
				break;
			}

			/* STRING value expected */

			/* 
			 * if we're pedantic, an attribute type in OID form
			 * SHOULD imply a BER encoded attribute value; we
			 * should at least issue a warning
			 */
			if ( ( flags & LDAP_DN_PEDANTIC )
				&& ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
				/* OID attrType SHOULD use binary encoding */
				goto parsing_error;
			}

			attrValueEncoding = LDAP_AVA_STRING;

			/* 
			 * LDAPv2 allows the attribute value to be quoted;
			 * also, IA5 values are expected, in principle
			 */
1124
			if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1125
1126
1127
1128
1129
1130
				if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
					p++;
					state = B4IA5VALUEQUOTED;
					break;
				}

1131
1132
1133
1134
				if ( LDAP_DN_LDAPV2( flags ) ) {
					state = B4IA5VALUE;
					break;
				}
1135
1136
			}

1137
1138
1139
1140
			/*
			 * here STRING means RFC 2253 string
			 * FIXME: what about DCE strings? 
			 */
1141
1142
1143
1144
1145
1146
			if ( !p[ 0 ] ) {
				/* empty value */
				state = GOTAVA;
			} else {
				state = B4STRINGVALUE;
			}
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
			break;

		case B4BINARYVALUE:
			if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
				goto parsing_error;
			}

			state = GOTAVA;
			break;

		case B4STRINGVALUE:
			switch ( LDAP_DN_FORMAT( flags ) ) {
1159
			case LDAP_DN_FORMAT_LDAP:
1160
			case LDAP_DN_FORMAT_LDAPV3:
1161
1162
				if ( str2strval( p, stoplen - ( p - str ),
							&attrValue, &p, flags, 
1163
1164
1165
1166
1167
1168
							&attrValueEncoding ) ) {
					goto parsing_error;
				}
				break;

			case LDAP_DN_FORMAT_DCE:
1169
				if ( DCE2strval( p, &attrValue, &p, flags ) ) {