getdn.c 66.1 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
 * Copyright 1998-2000 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"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
23

24
25
26
/* 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
27
/* #define PRETTY_ESCAPE */
28

Pierangelo Masarati's avatar
Pierangelo Masarati committed
29
static int dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout );
Hallvard Furuseth's avatar
Hallvard Furuseth committed
30

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/* from libraries/libldap/schema.c */
extern char * parse_numericoid(const char **sp, int *code, const int flags);

/* parsing/printing routines */
static int str2strval( const char *str, struct berval **val, 
		const char **next, unsigned flags, unsigned *retFlags );
static int DCE2strval( const char *str, struct berval **val, 
		const char **next, unsigned flags );
static int IA52strval( const char *str, struct berval **val, 
		const char **next, unsigned flags );
static int quotedIA52strval( const char *str, struct berval **val, 
		const char **next, unsigned flags );
static int hexstr2binval( const char *str, struct berval **val, 
		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 );
48
49
static int strval2strlen( struct berval *val, unsigned flags, 
		ber_len_t *len );
50
51
static int strval2str( struct berval *val, char *str, unsigned flags, 
		ber_len_t *len );
52
53
static int strval2IA5strlen( struct berval *val, unsigned flags,
		ber_len_t *len );
54
55
static int strval2IA5str( struct berval *val, char *str, unsigned flags, 
		ber_len_t *len );
56
57
static int strval2DCEstrlen( struct berval *val, unsigned flags,
		ber_len_t *len );
58
59
static int strval2DCEstr( struct berval *val, char *str, unsigned flags, 
		ber_len_t *len );
60
61
static int strval2ADstrlen( struct berval *val, unsigned flags,
		ber_len_t *len );
62
63
static int strval2ADstr( struct berval *val, char *str, unsigned flags, 
		ber_len_t *len );
Howard Chu's avatar
Howard Chu committed
64
static int dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN );
65
66

/* AVA helpers */
67
68
69
70
71
72
73
74
static LDAPAVA * ldapava_new(
	const struct berval *attr, const struct berval *val, unsigned flags );
static LDAPRDN * ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava );
static LDAPRDN * ldapava_insert_into_rdn(
	LDAPRDN *rdn, LDAPAVA *ava, unsigned where );
static LDAPDN * ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn );
static LDAPDN * ldapava_insert_into_dn(
	LDAPDN *dn, LDAPRDN *rdn, unsigned where );
75
76

/* Higher level helpers */
77
static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
78
		int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
79
static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
80
		int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
81
82
83
84
85
86
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 );
87

88
89
90
/*
 * RFC 1823 ldap_get_dn
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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 */
105
	if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
106
107
108
109
110
111
112
		ld->ld_errno = LDAP_DECODING_ERROR;
		return( NULL );
	}

	return( dn );
}

113
114
115
/*
 * RFC 1823 ldap_dn2ufn
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
116
char *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
117
ldap_dn2ufn( LDAP_CONST char *dn )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
118
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
119
120
	char	*out = NULL;

121
122
	Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
123
124
125
	( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_UFN );
	
	return( out );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
126
127
}

128
129
130
/*
 * RFC 1823 ldap_explode_dn
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
131
char **
Kurt Zeilenga's avatar
Kurt Zeilenga committed
132
ldap_explode_dn( LDAP_CONST char *dn, int notypes )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
133
{
134
135
136
137
138
139
140
	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 );

141
	if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP ) 
142
			!= LDAP_SUCCESS ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
143
144
145
146
147
148
149
150
151
		return NULL;
	}

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

		values[0] = NULL;
		return values;
152
153
	}

154
	for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ );
155

156
157
158
159
	values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) );
	if ( values == NULL ) {
		ldap_dnfree( tmpDN );
		return NULL;
160
161
	}

162
163
164
165
	for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
		ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &values[ iRDN ], flag );
	}
	ldap_dnfree( tmpDN );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
166
	values[ iRDN ] = NULL;
167

Kurt Zeilenga's avatar
Kurt Zeilenga committed
168
	return values;
Hallvard Furuseth's avatar
Hallvard Furuseth committed
169
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
170

Hallvard Furuseth's avatar
Hallvard Furuseth committed
171
char **
Kurt Zeilenga's avatar
Kurt Zeilenga committed
172
ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
Hallvard Furuseth's avatar
Hallvard Furuseth committed
173
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
174
175
176
177
	LDAPRDN		*tmpRDN;
	char		**values = NULL;
	const char 	*p;
	int		iAVA;
178
179
180
181
	
	Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );

	/*
Pierangelo Masarati's avatar
Pierangelo Masarati committed
182
183
184
	 * we only parse the first rdn
	 * FIXME: we prefer efficiency over checking if the _ENTIRE_
	 * dn can be parsed
185
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
186
	if ( ldap_str2rdn( rdn, &tmpRDN, &p, LDAP_DN_FORMAT_LDAP ) 
187
188
189
190
			!= LDAP_SUCCESS ) {
		return( NULL );
	}

191
192
193
194
195
196
197
	for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) ;
	values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) );
	if ( values == NULL ) {
		ldap_rdnfree( tmpRDN );
		return( NULL );
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
198
	for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) {
199
		ber_len_t	l = 0, vl, al = 0;
200
		char		*str;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
201
		LDAPAVA		*ava = tmpRDN[ iAVA ][ 0 ];
202
203
204
		
		if ( ava->la_flags == LDAP_AVA_BINARY ) {
			vl = 1 + 2 * ava->la_value->bv_len;
205

206
		} else {
207
208
209
210
			if ( strval2strlen( ava->la_value, 
						ava->la_flags, &vl ) ) {
				goto error_return;
			}
211
212
213
		}
		
		if ( !notypes ) {
214
			al = ava->la_attr->bv_len;
215
			l = vl + ava->la_attr->bv_len + 1;
216
217

			str = LDAP_MALLOC( l + 1 );
218
219
			AC_MEMCPY( str, ava->la_attr->bv_val, 
					ava->la_attr->bv_len );
220
			str[ al++ ] = '=';
221

222
223
224
225
226
227
228
		} else {
			l = vl;
			str = LDAP_MALLOC( l + 1 );
		}
		
		if ( ava->la_flags == LDAP_AVA_BINARY ) {
			str[ al++ ] = '#';
229
230
231
232
			if ( binval2hexstr( ava->la_value, &str[ al ] ) ) {
				goto error_return;
			}

233
		} else {
234
235
236
237
			if ( strval2str( ava->la_value, &str[ al ], 
					ava->la_flags, &vl ) ) {
				goto error_return;
			}
238
239
240
241
242
243
244
		}

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
245
	ldap_rdnfree( tmpRDN );
246

247
	return( values );
248

249
error_return:;
250
	LBER_VFREE( values );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
251
	ldap_rdnfree( tmpRDN );
252
	return( NULL );
253
254
}

255
256
257
char *
ldap_dn2dcedn( LDAP_CONST char *dn )
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
258
259
	char	*out = NULL;

260
261
	Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
262
263
264
	( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE );

	return( out );
265
266
267
268
269
}

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

272
273
	Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
274
275
276
	( void )dn2dn( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );

	return( out );
Hallvard Furuseth's avatar
Hallvard Furuseth committed
277
278
}

279
280
281
char *
ldap_dn2ad_canonical( LDAP_CONST char *dn )
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
282
283
	char	*out = NULL;

284
285
	Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
286
287
288
289
	( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, 
		       &out, LDAP_DN_FORMAT_AD_CANONICAL );

	return( out );
290
291
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
292
293
294
295
296
297
298
299
300
301
int
ldap_dn_normalize( const char *in, unsigned iflags, char **out, unsigned oflags ) 
{
	assert( out );

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

	return dn2dn( in, iflags, out, oflags);
}

302
303
304
305
306
/*
 * helper that changes the string representation of dnin
 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
 * 
 * fin can be one of:
307
308
 * 	LDAP_DN_FORMAT_LDAP		(rfc 2253 and ldapbis liberal, 
 * 					plus some rfc 1779)
309
310
311
312
 * 	LDAP_DN_FORMAT_LDAPV3		(rfc 2253 and ldapbis)
 * 	LDAP_DN_FORMAT_LDAPV2		(rfc 1779)
 * 	LDAP_DN_FORMAT_DCE		(?)
 *
313
314
315
 * fout can be any of the above except
 * 	LDAP_DN_FORMAT_LDAP
 * plus:
316
317
318
 * 	LDAP_DN_FORMAT_UFN		(rfc 1781, partial and with extensions)
 * 	LDAP_DN_FORMAT_AD_CANONICAL	(?)
 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
319
320
static int
dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout )
321
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
322
	int	rc;
323
324
	LDAPDN	*tmpDN = NULL;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
325
326
327
328
329
330
	assert( dnout );

	*dnout = NULL;

	if ( dnin == NULL ) {
		return( LDAP_SUCCESS );
331
332
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
333
334
335
	rc = ldap_str2dn( dnin , &tmpDN, fin );
	if ( rc != LDAP_SUCCESS ) {
		return( rc );
336
337
	}

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

340
	ldap_dnfree( tmpDN );
341

Pierangelo Masarati's avatar
Pierangelo Masarati committed
342
	return( rc );
343
}
344
345
346
347

/* States */
#define B4AVA			0x0000

348
/* #define	B4ATTRTYPE		0x0001 */
349
350
351
352
353
354
355
356
357
358
359
360
361
362
#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
363
364
365
366
367
/*
 * Helpers (mostly from slap.h)
 * c is assumed to Unicode in an ASCII compatible format (UTF-8)
 * Macros assume "C" Locale (ASCII)
 */
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
#define LDAP_DN_ASCII_SPACE(c) \
	( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
#define LDAP_DN_ASCII_LOWER(c)		( (c) >= 'a' && (c) <= 'z' )
#define LDAP_DN_ASCII_UPPER(c)		( (c) >= 'A' && (c) <= 'Z' )
#define LDAP_DN_ASCII_ALPHA(c) \
	( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
#define LDAP_DN_ASCII_DIGIT(c)		( (c) >= '0' && (c) <= '9' )
#define LDAP_DN_ASCII_LCASE_HEXALPHA(c)	( (c) >= 'a' && (c) <= 'f' )
#define LDAP_DN_ASCII_UCASE_HEXALPHA(c)	( (c) >= 'A' && (c) <= 'F' )
#define LDAP_DN_ASCII_HEXDIGIT(c) \
	( LDAP_DN_ASCII_DIGIT(c) \
	  || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
	  || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
#define LDAP_DN_ASCII_ALNUM(c) \
	( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
#define LDAP_DN_ASCII_PRINTABLE(c)	( (c) >= ' ' && (c) <= '~' )

/* attribute type */
#define LDAP_DN_OID_LEADCHAR(c)		( LDAP_DN_ASCII_DIGIT(c) )
#define LDAP_DN_DESC_LEADCHAR(c)	( LDAP_DN_ASCII_ALPHA(c) )
#define LDAP_DN_DESC_CHAR(c)		( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
#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) == '>' )
#define LDAP_DN_NEEDESCAPE(c) \
	( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
#define LDAP_DN_NEEDESCAPE_LEAD(c) \
	( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
#define LDAP_DN_NEEDESCAPE_TRAIL(c) \
411
	( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
412
413
414
415
#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) \
416
	( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441

/* 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.
442
443
444
445
 *
 * Assertion:		'='
 * RDN separator:	'/'
 * AVA separator:	','
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
 * 
 * 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]) )
470
471
/* better look at the AttributeDescription? */

472
473
/* FIXME: no composite rdn or non-"dc" types, right?
 * (what about "dc" in OID form?) */
474
/* FIXME: we do not allow binary values in domain, right? */
475
/* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
476
477
478
479
480
481
482
483
484
485
486
/* 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 ) \
	( (r) && (r)[0][0] && !(r)[1] \
	  && ((r)[0][0]->la_flags == LDAP_AVA_STRING) \
	  && ((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])))
487

488
/* Composite rules */
489
#define LDAP_DN_ALLOW_ONE_SPACE(f) \
490
	( LDAP_DN_LDAPV2(f) \
491
	  || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
492
#define LDAP_DN_ALLOW_SPACES(f) \
493
	( LDAP_DN_LDAPV2(f) \
494
	  || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
495
496
#define LDAP_DN_LDAP(f) \
	( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
497
498
499
500
501
502
503
504
505
506
507
508
509
#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 )

/*
510
511
 * LDAPAVA helpers (will become part of the API for operations 
 * on structural representations of DNs).
512
 */
513
LDAPAVA *
514
515
ldapava_new( const struct berval *attr, const struct berval *val, 
		unsigned flags )
516
517
518
519
520
521
522
523
524
525
{
	LDAPAVA	*ava;

	assert( attr );
	assert( val );

	ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
	
	/* should we test it? */
	if ( ava == NULL ) {
526
		return( NULL );
527
528
	}

529
	ava->la_attr = ( struct berval * )attr;
530
531
532
	ava->la_value = ( struct berval * )val;
	ava->la_flags = flags;

533
534
	ava->la_private = NULL;

535
	return( ava );
536
537
}

538
void
539
ldap_avafree( LDAPAVA *ava )
540
541
542
{
	assert( ava );

543
#if 0
544
545
546
547
	/* 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 );
548
#endif
549

550
	ber_bvfree( ava->la_attr );
551
552
553
554
555
	ber_bvfree( ava->la_value );

	LDAP_FREE( ava );
}

556
LDAPRDN *
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
{
	LDAPRDN 	*newRDN;
	unsigned	i = 0U;

	assert( ava );

	if ( rdn != NULL ) {
		for ( i = 0U; rdn[ i ]; i++ ) {
			/* no op */
		}
	}
	newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
	newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
	newRDN[ i ][ 0 ] = ava;
	newRDN[ i + 1 ] = NULL;

574
	return( newRDN );
575
576
}

577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
LDAPRDN *
ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
{
	LDAPRDN 	*newRDN;
	unsigned	i = 0U;

	assert( ava );

	if ( rdn != NULL ) {
		for ( i = 0U; rdn[ i ]; i++ ) {
			/* no op */
		}
	}
	if ( where > i ) {
		where = i;
		/* assume "at end", which corresponds to
		 * ldapava_append_to_rdn */
	}
	
	newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
	
	/* data after insert point */
	AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
			( i - where ) * sizeof( LDAPRDN * ) );

	newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
	newRDN[ where ][ 0 ] = ava;
	newRDN[ i + 1 ] = NULL;

	return( newRDN );
}

void
610
ldap_rdnfree( LDAPRDN *rdn )
611
612
613
614
615
616
617
618
619
620
{
	int iAVA;
	
	if ( rdn == NULL ) {
		return;
	}

	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
		assert( rdn[ iAVA ][ 0 ] );

621
		ldap_avafree( rdn[ iAVA ][ 0 ] );
622
623
624
625
626
	}

	LDAP_VFREE( rdn );
}

627
LDAPDN *
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
{
	LDAPDN 		*newDN;
	unsigned	i = 0U;

	assert( rdn );

	if ( dn != NULL ) {
		for ( i = 0U; dn[ i ]; i++ ) {
			/* no op */
		}
	}
	newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
	newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
	newDN[ i ][ 0 ] = rdn;
	newDN[ i + 1 ] = NULL;

645
	return( newDN );
646
647
}

648
649
LDAPDN *
ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
650
651
652
653
654
655
656
657
658
659
660
{
	LDAPDN 		*newDN;
	unsigned	i = 0U;

	assert( rdn );

	if ( dn != NULL ) {
		for ( i = 0U; dn[ i ]; i++ ) {
			/* no op */
		}
	}
661
662
663
664
665
666
667
668
669
670
671
	if ( where > i ) {
		where = i;
		/* assume "at end", which corresponds to
		 * ldapava_append_to_dn */
	}
	
	newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
	
	/* data after insert point */
	AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
			( i - where ) * sizeof( LDAPDN * ) );
672

673
674
	newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
	newDN[ where ][ 0 ] = rdn;
675
676
	newDN[ i + 1 ] = NULL;

677
	return( newDN );
678
679
}

680
void
681
ldap_dnfree( LDAPDN *dn )
682
683
684
685
686
687
688
689
690
691
{
	int iRDN;
	
	if ( dn == NULL ) {
		return;
	}

	for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
		assert( dn[ iRDN ][ 0 ] );

692
		ldap_rdnfree( dn[ iRDN ][ 0 ] );
693
694
695
696
697
698
699
	}

	LDAP_VFREE( dn );
}

/*
 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
700
 * into a structural representation of the DN, by separating attribute
701
702
703
704
705
706
707
708
709
710
 * 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.
 */
711

712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
int
ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
{
	const char 	*p;
	int		rc = LDAP_INVALID_DN_SYNTAX;

	LDAPDN		*newDN = NULL;
	LDAPRDN		*newRDN = NULL;
	
	assert( str );
	assert( dn );

	Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );

	*dn = NULL;

	switch ( LDAP_DN_FORMAT( flags ) ) {
729
	case LDAP_DN_FORMAT_LDAP:
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
	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:
		return( LDAP_INVALID_DN_SYNTAX );

	default:
		return( LDAP_OTHER );
	}

	if ( str[ 0 ] == '\0' ) {
		return( LDAP_SUCCESS );
	}

	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++;
759
760
761
762
763
764
765
766
767
		
	} 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++;
		}
768
769
	}

770
771
	for ( ; p[ 0 ]; p++ ) {
		LDAPDN 		*dn;
772
		int		err;
773
		
774
775
		err = ldap_str2rdn( p, &newRDN, &p, flags );
		if ( err != LDAP_SUCCESS ) {
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
			goto parsing_error;
		}

		/* 
		 * We expect a rdn separator
		 */
		if ( p[ 0 ] ) {
			switch ( LDAP_DN_FORMAT( flags ) ) {
			case LDAP_DN_FORMAT_LDAPV3:
				if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
					rc = LDAP_OTHER;
					goto parsing_error;
				}
				break;
	
791
			case LDAP_DN_FORMAT_LDAP:
792
793
794
795
796
797
798
			case LDAP_DN_FORMAT_LDAPV2:
				if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
					rc = LDAP_OTHER;
					goto parsing_error;
				}
				break;
	
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
			case LDAP_DN_FORMAT_DCE:
				if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
					rc = LDAP_OTHER;
					goto parsing_error;
				}
				break;
			}
		}


		if ( LDAP_DN_DCE( flags ) ) {
			/* add in reversed order */
			dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
		} else {
			dn = ldapava_append_to_dn( newDN, newRDN );
		}

		if ( dn == NULL ) {
			rc = LDAP_NO_MEMORY;
			goto parsing_error;
		}

		newDN = dn;
		newRDN = NULL;
				
		if ( p[ 0 ] == '\0' ) {
					
			/* 
			 * the DN is over, phew
			 */
			rc = LDAP_SUCCESS;
			goto return_result;
		}
	}
	
parsing_error:;
	if ( newRDN ) {
836
		ldap_rdnfree( newRDN );
837
838
839
	}

	if ( newDN ) {
840
		ldap_dnfree( newDN );
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
		newDN = NULL;
	}

return_result:;

	Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
	*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
ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
{
	const char 	*p;
	int 		state = B4AVA;
	int		rc = LDAP_INVALID_DN_SYNTAX;
866
867
	int		attrTypeEncoding = LDAP_AVA_STRING, 
			attrValueEncoding = LDAP_AVA_STRING;
868

869
	struct berval	*attrType = NULL;
870
871
872
873
874
	struct berval 	*attrValue = NULL;

	LDAPRDN		*newRDN = NULL;
	
	assert( str );
875
	assert( rdn || flags & LDAP_DN_SKIP );
876
877
878
879
	assert( n );

	Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );

880
881
882
	if ( rdn ) {
		*rdn = NULL;
	}
883
884
885
	*n = NULL;

	switch ( LDAP_DN_FORMAT( flags ) ) {
886
	case LDAP_DN_FORMAT_LDAP:
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
	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:
		return( LDAP_INVALID_DN_SYNTAX );

	default:
		return( LDAP_OTHER );
	}

	if ( str[ 0 ] == '\0' ) {
		return( LDAP_SUCCESS );
	}

	p = str;
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
	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:
929
930
931
932
933
934
935
936
			if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
				if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
					/* error */
					goto parsing_error;
				}
				p++;
			}

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
963
964
965
966
967
968
969
970
971
972
			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 ) {
973
974
					if ( !strncmp( p, "OID.", 4 )
						|| !strncmp( p, "oid.", 4 ) ) {
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
						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;
993
			char		*type;
994
			
995
996
			type = parse_numericoid( &p, &err, 0 );
			if ( type == NULL ) {
997
998
				goto parsing_error;
			}
999
1000

			if ( flags & LDAP_DN_SKIP ) {
For faster browsing, not all history is shown. View entire blame