dn.c 26.6 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* dn.c - routines for dealing with distinguished names */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 1998-2020 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to the University of Michigan at Ann Arbor. The name of the University
 * may not be used to endorse or promote products derived from this
 * software without specific prior written permission. This software
 * is provided ``as is'' without express or implied warranty.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
25
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
26
27

#include "portable.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
28
29
30
31
32
33
34
35

#include <stdio.h>

#include <ac/ctype.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
36
#include "slap.h"
37
38
#include "lutil.h"

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
 * The DN syntax-related functions take advantage of the dn representation
 * handling functions ldap_str2dn/ldap_dn2str.  The latter are not schema-
 * aware, so the attributes and their values need be validated (and possibly
 * normalized).  In the current implementation the required validation/nor-
 * malization/"pretty"ing are done on newly created DN structural represen-
 * tations; however the idea is to move towards DN handling in structural
 * representation instead of the current string representation.  To this
 * purpose, we need to do only the required operations and keep track of
 * what has been done to minimize their impact on performances.
 *
 * Developers are strongly encouraged to use this feature, to speed-up
 * its stabilization.
 */

#define	AVA_PRIVATE( ava ) ( ( AttributeDescription * )(ava)->la_private )

56
57
int slap_DN_strict = SLAP_AD_NOINSERT;

58
59
60
61
62
63
static int
LDAPRDN_validate( LDAPRDN rdn )
{
	int		iAVA;
	int 		rc;

64
	assert( rdn != NULL );
65
66
67
68
69
70

	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
		LDAPAVA			*ava = rdn[ iAVA ];
		AttributeDescription	*ad;
		slap_syntax_validate_func *validate = NULL;

71
		assert( ava != NULL );
72
73
74
75
76
77
		
		if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
			const char	*text = NULL;

			rc = slap_bv2ad( &ava->la_attr, &ad, &text );
			if ( rc != LDAP_SUCCESS ) {
78
79
				rc = slap_bv2undef_ad( &ava->la_attr,
					&ad, &text,
80
					SLAP_AD_PROXIED|slap_DN_strict );
81
82
83
				if ( rc != LDAP_SUCCESS ) {
					return LDAP_INVALID_SYNTAX;
				}
84
85
86
87
88
			}

			ava->la_private = ( void * )ad;
		}

89
90
91
92
93
94
95
		/*
		 * Do not allow X-ORDERED 'VALUES' naming attributes
		 */
		if ( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) {
			return LDAP_INVALID_SYNTAX;
		}

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
		/* 
		 * Replace attr oid/name with the canonical name
		 */
		ava->la_attr = ad->ad_cname;

		validate = ad->ad_type->sat_syntax->ssyn_validate;

		if ( validate ) {
			/*
		 	 * validate value by validate function
			 */
			rc = ( *validate )( ad->ad_type->sat_syntax,
				&ava->la_value );
			
			if ( rc != LDAP_SUCCESS ) {
				return LDAP_INVALID_SYNTAX;
			}
		}
	}
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
115
116

	return LDAP_SUCCESS;
117
118
}

119
120
121
122
123
/*
 * In-place, schema-aware validation of the
 * structural representation of a distinguished name.
 */
static int
Howard Chu's avatar
Howard Chu committed
124
LDAPDN_validate( LDAPDN dn )
125
126
127
128
{
	int 		iRDN;
	int 		rc;

129
	assert( dn != NULL );
130

Howard Chu's avatar
Howard Chu committed
131
	for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
132
133
134
		rc = LDAPRDN_validate( dn[ iRDN ] );
		if ( rc != LDAP_SUCCESS ) {
			return rc;
135
136
137
138
139
140
		}
	}

	return LDAP_SUCCESS;
}

141
/*
142
 * dn validate routine
143
 */
144
145
146
147
int
dnValidate(
	Syntax *syntax,
	struct berval *in )
148
{
149
	int		rc;
Howard Chu's avatar
Howard Chu committed
150
	LDAPDN		dn = NULL;
151

152
	assert( in != NULL );
153
154

	if ( in->bv_len == 0 ) {
155
156
157
158
		return LDAP_SUCCESS;

	} else if ( in->bv_len > SLAP_LDAPDN_MAXLEN ) {
		return LDAP_INVALID_SYNTAX;
159
160
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
161
	rc = ldap_bv2dn( in, &dn, LDAP_DN_FORMAT_LDAP );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
162
163
164
165
166
	if ( rc != LDAP_SUCCESS ) {
		return LDAP_INVALID_SYNTAX;
	}

	assert( strlen( in->bv_val ) == in->bv_len );
167

168
	/*
169
	 * Schema-aware validate
170
	 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
171
	rc = LDAPDN_validate( dn );
172
173
174
175
	ldap_dnfree( dn );

	if ( rc != LDAP_SUCCESS ) {
		return LDAP_INVALID_SYNTAX;
176
	}
177
178

	return LDAP_SUCCESS;
179
180
}

181
182
183
184
185
186
187
188
189
int
rdnValidate(
	Syntax *syntax,
	struct berval *in )
{
	int		rc;
	LDAPRDN		rdn;
	char*		p;

190
	assert( in != NULL );
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
	if ( in->bv_len == 0 ) {
		return LDAP_SUCCESS;

	} else if ( in->bv_len > SLAP_LDAPDN_MAXLEN ) {
		return LDAP_INVALID_SYNTAX;
	}

	rc = ldap_bv2rdn_x( in , &rdn, (char **) &p,
				LDAP_DN_FORMAT_LDAP, NULL);
	if ( rc != LDAP_SUCCESS ) {
		return LDAP_INVALID_SYNTAX;
	}

	assert( strlen( in->bv_val ) == in->bv_len );

	/*
	 * Schema-aware validate
	 */
	rc = LDAPRDN_validate( rdn );
	ldap_rdnfree( rdn );

	if ( rc != LDAP_SUCCESS ) {
		return LDAP_INVALID_SYNTAX;
	}

	return LDAP_SUCCESS;
}


220
221
222
/*
 * AVA sorting inside a RDN
 *
223
 * Rule: sort attributeTypes in alphabetical order.
224
 *
225
226
227
 * Note: the sorting can be slightly improved by sorting first
 * by attribute type length, then by alphabetical order.
 *
228
 * uses an insertion sort; should be fine since the number of AVAs in
229
230
 * a RDN should be limited.
 */
231
232
static int
AVA_Sort( LDAPRDN rdn, int nAVAs )
233
{
234
	LDAPAVA	*ava_i;
235
	int		i;
236
	int		rc = LDAP_SUCCESS;
237

238
	assert( rdn != NULL );
239

240
241
242
	for ( i = 1; i < nAVAs; i++ ) {
		LDAPAVA *ava_j;
		int j;
243

244
245
246
		ava_i = rdn[ i ];
		for ( j = i-1; j >=0; j-- ) {
			int a;
247

248
249
			ava_j = rdn[ j ];
			a = strcmp( ava_i->la_attr.bv_val, ava_j->la_attr.bv_val );
250

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
251
252
			/* RFC4512 does not allow multiple AVAs
			 * with the same attribute type in RDN (ITS#5968) */
253
			if ( a == 0 )
254
				rc = LDAP_INVALID_DN_SYNTAX;
255

256
			if ( a > 0 )
257
258
				break;

259
			rdn[ j+1 ] = rdn[ j ];
260
		}
261
		rdn[ j+1 ] = ava_i;
262
	}
263
	return rc;
264
265
}

266
267
268
269
static int
LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx )
{

270
271
	int rc, iAVA, do_sort = 0;

272
273
274
275
276
277
278
279
280
	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
		LDAPAVA			*ava = rdn[ iAVA ];
		AttributeDescription	*ad;
		slap_syntax_validate_func *validf = NULL;
		slap_mr_normalize_func *normf = NULL;
		slap_syntax_transform_func *transf = NULL;
		MatchingRule *mr = NULL;
		struct berval		bv = BER_BVNULL;

281
		assert( ava != NULL );
282
283
284
285
286
287

		if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
			const char	*text = NULL;

			rc = slap_bv2ad( &ava->la_attr, &ad, &text );
			if ( rc != LDAP_SUCCESS ) {
288
289
				rc = slap_bv2undef_ad( &ava->la_attr,
					&ad, &text,
290
					SLAP_AD_PROXIED|slap_DN_strict );
291
292
293
				if ( rc != LDAP_SUCCESS ) {
					return LDAP_INVALID_SYNTAX;
				}
294
295
296
297
298
299
300
301
302
303
304
305
			}
			
			ava->la_private = ( void * )ad;
			do_sort = 1;
		}

		/* 
		 * Replace attr oid/name with the canonical name
		 */
		ava->la_attr = ad->ad_cname;

		if( ava->la_flags & LDAP_AVA_BINARY ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
306
307
			/* AVA is binary encoded, not supported */
			return LDAP_INVALID_SYNTAX;
308

309
310
311
312
			/* Do not allow X-ORDERED 'VALUES' naming attributes */
		} else if( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) {
			return LDAP_INVALID_SYNTAX;

313
314
315
316
317
318
319
320
		} else if( flags & SLAP_LDAPDN_PRETTY ) {
			transf = ad->ad_type->sat_syntax->ssyn_pretty;
			if( !transf ) {
				validf = ad->ad_type->sat_syntax->ssyn_validate;
			}
		} else { /* normalization */
			validf = ad->ad_type->sat_syntax->ssyn_validate;
			mr = ad->ad_type->sat_equality;
321
322
323
			if( mr && (!( mr->smr_usage & SLAP_MR_MUTATION_NORMALIZER ))) {
				normf = mr->smr_normalize;
			}
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
		}

		if ( validf ) {
			/* validate value before normalization */
			rc = ( *validf )( ad->ad_type->sat_syntax,
				ava->la_value.bv_len
					? &ava->la_value
					: (struct berval *) &slap_empty_bv );

			if ( rc != LDAP_SUCCESS ) {
				return LDAP_INVALID_SYNTAX;
			}
		}

		if ( transf ) {
			/*
		 	 * transform value by pretty function
			 *	if value is empty, use empty_bv
			 */
			rc = ( *transf )( ad->ad_type->sat_syntax,
				ava->la_value.bv_len
					? &ava->la_value
					: (struct berval *) &slap_empty_bv,
				&bv, ctx );
		
			if ( rc != LDAP_SUCCESS ) {
				return LDAP_INVALID_SYNTAX;
			}
		}

		if ( normf ) {
			/*
		 	 * normalize value
			 *	if value is empty, use empty_bv
			 */
			rc = ( *normf )(
				SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
				ad->ad_type->sat_syntax,
				mr,
				ava->la_value.bv_len
					? &ava->la_value
					: (struct berval *) &slap_empty_bv,
				&bv, ctx );
		
			if ( rc != LDAP_SUCCESS ) {
				return LDAP_INVALID_SYNTAX;
			}
		}


		if( bv.bv_val ) {
			if ( ava->la_flags & LDAP_AVA_FREE_VALUE )
				ber_memfree_x( ava->la_value.bv_val, ctx );
			ava->la_value = bv;
			ava->la_flags |= LDAP_AVA_FREE_VALUE;
		}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
380
381
382
383
		/* reject empty values */
		if (!ava->la_value.bv_len) {
			return LDAP_INVALID_SYNTAX;
		}
384
385
	}
	rc = LDAP_SUCCESS;
386

387
388
	if ( do_sort ) {
		rc = AVA_Sort( rdn, iAVA );
389
	}
390
391

	return rc;
392
393
}

394
395
396
397
398
/*
 * In-place, schema-aware normalization / "pretty"ing of the
 * structural representation of a distinguished name.
 */
static int
Howard Chu's avatar
Howard Chu committed
399
LDAPDN_rewrite( LDAPDN dn, unsigned flags, void *ctx )
400
401
402
403
{
	int 		iRDN;
	int 		rc;

404
	assert( dn != NULL );
405

Howard Chu's avatar
Howard Chu committed
406
	for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
407
408
409
		rc = LDAPRDN_rewrite( dn[ iRDN ], flags, ctx );
		if ( rc != LDAP_SUCCESS ) {
			return rc;
410
411
412
413
414
415
416
417
		}
	}

	return LDAP_SUCCESS;
}

int
dnNormalize(
418
419
420
421
    slap_mask_t use,
    Syntax *syntax,
    MatchingRule *mr,
    struct berval *val,
Howard Chu's avatar
Howard Chu committed
422
423
    struct berval *out,
    void *ctx)
424
{
425
426
	assert( val != NULL );
	assert( out != NULL );
427

Howard Chu's avatar
Howard Chu committed
428
	Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val ? val->bv_val : "", 0, 0 );
429

430
	if ( val->bv_len != 0 ) {
Howard Chu's avatar
Howard Chu committed
431
		LDAPDN		dn = NULL;
432
433
434
435
436
		int		rc;

		/*
		 * Go to structural representation
		 */
Howard Chu's avatar
Howard Chu committed
437
		rc = ldap_bv2dn_x( val, &dn, LDAP_DN_FORMAT_LDAP, ctx );
438
439
440
441
		if ( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
442
443
		assert( strlen( val->bv_val ) == val->bv_len );

444
445
446
		/*
		 * Schema-aware rewrite
		 */
Howard Chu's avatar
Howard Chu committed
447
		if ( LDAPDN_rewrite( dn, 0, ctx ) != LDAP_SUCCESS ) {
Howard Chu's avatar
Howard Chu committed
448
			ldap_dnfree_x( dn, ctx );
449
450
451
452
453
454
			return LDAP_INVALID_SYNTAX;
		}

		/*
		 * Back to string representation
		 */
Howard Chu's avatar
Howard Chu committed
455
456
		rc = ldap_dn2bv_x( dn, out,
			LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
457

Howard Chu's avatar
Howard Chu committed
458
		ldap_dnfree_x( dn, ctx );
459
460
461
462
463

		if ( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}
	} else {
Howard Chu's avatar
Howard Chu committed
464
		ber_dupbv_x( out, val, ctx );
465
466
	}

Howard Chu's avatar
Howard Chu committed
467
	Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val ? out->bv_val : "", 0, 0 );
468
469
470
471

	return LDAP_SUCCESS;
}

472
473
474
475
476
477
478
479
480
int
rdnNormalize(
    slap_mask_t use,
    Syntax *syntax,
    MatchingRule *mr,
    struct berval *val,
    struct berval *out,
    void *ctx)
{
481
482
	assert( val != NULL );
	assert( out != NULL );
483

Howard Chu's avatar
Howard Chu committed
484
	Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val ? val->bv_val : "", 0, 0 );
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
	if ( val->bv_len != 0 ) {
		LDAPRDN		rdn = NULL;
		int		rc;
		char*		p;

		/*
		 * Go to structural representation
		 */
		rc = ldap_bv2rdn_x( val , &rdn, (char **) &p,
					LDAP_DN_FORMAT_LDAP, ctx);

		if ( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}

		assert( strlen( val->bv_val ) == val->bv_len );

		/*
		 * Schema-aware rewrite
		 */
		if ( LDAPRDN_rewrite( rdn, 0, ctx ) != LDAP_SUCCESS ) {
			ldap_rdnfree_x( rdn, ctx );
			return LDAP_INVALID_SYNTAX;
		}

		/*
		 * Back to string representation
		 */
		rc = ldap_rdn2bv_x( rdn, out,
			LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );

		ldap_rdnfree_x( rdn, ctx );

		if ( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}
	} else {
		ber_dupbv_x( out, val, ctx );
	}

Howard Chu's avatar
Howard Chu committed
525
	Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val ? out->bv_val : "", 0, 0 );
526
527
528
529

	return LDAP_SUCCESS;
}

530
531
int
dnPretty(
532
533
	Syntax *syntax,
	struct berval *val,
Howard Chu's avatar
Howard Chu committed
534
535
	struct berval *out,
	void *ctx)
536
{
537
538
	assert( val != NULL );
	assert( out != NULL );
539

Howard Chu's avatar
Howard Chu committed
540
	Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val ? val->bv_val : "", 0, 0 );
541

542
	if ( val->bv_len == 0 ) {
Howard Chu's avatar
Howard Chu committed
543
		ber_dupbv_x( out, val, ctx );
544
545
546
547
548

	} else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
		return LDAP_INVALID_SYNTAX;

	} else {
Howard Chu's avatar
Howard Chu committed
549
		LDAPDN		dn = NULL;
550
551
552
		int		rc;

		/* FIXME: should be liberal in what we accept */
Howard Chu's avatar
Howard Chu committed
553
		rc = ldap_bv2dn_x( val, &dn, LDAP_DN_FORMAT_LDAP, ctx );
554
555
556
557
		if ( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
558
559
		assert( strlen( val->bv_val ) == val->bv_len );

560
561
562
		/*
		 * Schema-aware rewrite
		 */
Howard Chu's avatar
Howard Chu committed
563
564
		if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY, ctx ) != LDAP_SUCCESS ) {
			ldap_dnfree_x( dn, ctx );
565
566
567
568
569
570
571
			return LDAP_INVALID_SYNTAX;
		}

		/* FIXME: not sure why the default isn't pretty */
		/* RE: the default is the form that is used as
		 * an internal representation; the pretty form
		 * is a variant */
Howard Chu's avatar
Howard Chu committed
572
573
		rc = ldap_dn2bv_x( dn, out,
			LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
574

Howard Chu's avatar
Howard Chu committed
575
		ldap_dnfree_x( dn, ctx );
576
577
578
579
580
581

		if ( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}
	}

Howard Chu's avatar
Howard Chu committed
582
	Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val ? out->bv_val : "", 0, 0 );
583
584

	return LDAP_SUCCESS;
585
}
586

587
588
589
590
591
592
593
int
rdnPretty(
	Syntax *syntax,
	struct berval *val,
	struct berval *out,
	void *ctx)
{
594
595
	assert( val != NULL );
	assert( out != NULL );
596

Howard Chu's avatar
Howard Chu committed
597
	Debug( LDAP_DEBUG_TRACE, ">>> rdnPretty: <%s>\n", val->bv_val ? val->bv_val : "", 0, 0 );
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640

	if ( val->bv_len == 0 ) {
		ber_dupbv_x( out, val, ctx );

	} else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
		return LDAP_INVALID_SYNTAX;

	} else {
		LDAPRDN		rdn = NULL;
		int		rc;
		char*		p;

		/* FIXME: should be liberal in what we accept */
		rc = ldap_bv2rdn_x( val , &rdn, (char **) &p,
					LDAP_DN_FORMAT_LDAP, ctx);
		if ( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}

		assert( strlen( val->bv_val ) == val->bv_len );

		/*
		 * Schema-aware rewrite
		 */
		if ( LDAPRDN_rewrite( rdn, SLAP_LDAPDN_PRETTY, ctx ) != LDAP_SUCCESS ) {
			ldap_rdnfree_x( rdn, ctx );
			return LDAP_INVALID_SYNTAX;
		}

		/* FIXME: not sure why the default isn't pretty */
		/* RE: the default is the form that is used as
		 * an internal representation; the pretty form
		 * is a variant */
		rc = ldap_rdn2bv_x( rdn, out,
			LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );

		ldap_rdnfree_x( rdn, ctx );

		if ( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}
	}

Howard Chu's avatar
Howard Chu committed
641
	Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val ? out->bv_val : "", 0, 0 );
642
643
644
645
646

	return LDAP_SUCCESS;
}


647
648
649
650
int
dnPrettyNormalDN(
	Syntax *syntax,
	struct berval *val,
Howard Chu's avatar
Howard Chu committed
651
652
653
	LDAPDN *dn,
	int flags,
	void *ctx )
654
{
655
656
	assert( val != NULL );
	assert( dn != NULL );
657
658
659

	Debug( LDAP_DEBUG_TRACE, ">>> dn%sDN: <%s>\n", 
			flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal", 
Howard Chu's avatar
Howard Chu committed
660
			val->bv_val ? val->bv_val : "", 0 );
661
662
663
664
665
666
667
668
669
670
671

	if ( val->bv_len == 0 ) {
		return LDAP_SUCCESS;

	} else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
		return LDAP_INVALID_SYNTAX;

	} else {
		int		rc;

		/* FIXME: should be liberal in what we accept */
Howard Chu's avatar
Howard Chu committed
672
		rc = ldap_bv2dn_x( val, dn, LDAP_DN_FORMAT_LDAP, ctx );
673
674
675
676
677
678
679
680
681
		if ( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}

		assert( strlen( val->bv_val ) == val->bv_len );

		/*
		 * Schema-aware rewrite
		 */
Howard Chu's avatar
Howard Chu committed
682
683
		if ( LDAPDN_rewrite( *dn, flags, ctx ) != LDAP_SUCCESS ) {
			ldap_dnfree_x( *dn, ctx );
684
685
686
687
688
689
690
691
692
693
694
695
			*dn = NULL;
			return LDAP_INVALID_SYNTAX;
		}
	}

	Debug( LDAP_DEBUG_TRACE, "<<< dn%sDN\n", 
			flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal",
			0, 0 );

	return LDAP_SUCCESS;
}

696
697
698
699
700
701
702
703
/*
 * Combination of both dnPretty and dnNormalize
 */
int
dnPrettyNormal(
	Syntax *syntax,
	struct berval *val,
	struct berval *pretty,
Howard Chu's avatar
Howard Chu committed
704
705
	struct berval *normal,
	void *ctx)
706
{
707
708
709
	assert( val != NULL );
	assert( pretty != NULL );
	assert( normal != NULL );
710
	Debug( LDAP_DEBUG_TRACE, ">>> dnPrettyNormal: <%s>\n", val->bv_val ? val->bv_val : "", 0, 0 );
711

712
	if ( val->bv_len == 0 ) {
Howard Chu's avatar
Howard Chu committed
713
714
		ber_dupbv_x( pretty, val, ctx );
		ber_dupbv_x( normal, val, ctx );
715
716
717
718
719
720

	} else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
		/* too big */
		return LDAP_INVALID_SYNTAX;

	} else {
Howard Chu's avatar
Howard Chu committed
721
		LDAPDN		dn = NULL;
722
723
724
725
726
727
728
729
		int		rc;

		pretty->bv_val = NULL;
		normal->bv_val = NULL;
		pretty->bv_len = 0;
		normal->bv_len = 0;

		/* FIXME: should be liberal in what we accept */
Howard Chu's avatar
Howard Chu committed
730
		rc = ldap_bv2dn_x( val, &dn, LDAP_DN_FORMAT_LDAP, ctx );
731
732
733
734
		if ( rc != LDAP_SUCCESS ) {
			return LDAP_INVALID_SYNTAX;
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
735
736
		assert( strlen( val->bv_val ) == val->bv_len );

737
738
739
		/*
		 * Schema-aware rewrite
		 */
Howard Chu's avatar
Howard Chu committed
740
741
		if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY, ctx ) != LDAP_SUCCESS ) {
			ldap_dnfree_x( dn, ctx );
742
743
744
			return LDAP_INVALID_SYNTAX;
		}

Howard Chu's avatar
Howard Chu committed
745
746
		rc = ldap_dn2bv_x( dn, pretty,
			LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
747
748

		if ( rc != LDAP_SUCCESS ) {
Howard Chu's avatar
Howard Chu committed
749
			ldap_dnfree_x( dn, ctx );
750
751
752
			return LDAP_INVALID_SYNTAX;
		}

Howard Chu's avatar
Howard Chu committed
753
754
755
		if ( LDAPDN_rewrite( dn, 0, ctx ) != LDAP_SUCCESS ) {
			ldap_dnfree_x( dn, ctx );
			ber_memfree_x( pretty->bv_val, ctx );
756
757
758
759
760
			pretty->bv_val = NULL;
			pretty->bv_len = 0;
			return LDAP_INVALID_SYNTAX;
		}

Howard Chu's avatar
Howard Chu committed
761
762
		rc = ldap_dn2bv_x( dn, normal,
			LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
763

Howard Chu's avatar
Howard Chu committed
764
		ldap_dnfree_x( dn, ctx );
765
		if ( rc != LDAP_SUCCESS ) {
Howard Chu's avatar
Howard Chu committed
766
			ber_memfree_x( pretty->bv_val, ctx );
767
768
769
770
771
772
773
			pretty->bv_val = NULL;
			pretty->bv_len = 0;
			return LDAP_INVALID_SYNTAX;
		}
	}

	Debug( LDAP_DEBUG_TRACE, "<<< dnPrettyNormal: <%s>, <%s>\n",
Howard Chu's avatar
Howard Chu committed
774
775
		pretty->bv_val ? pretty->bv_val : "",
		normal->bv_val ? normal->bv_val : "", 0 );
776
777
778
779

	return LDAP_SUCCESS;
}

780
/*
781
 * dnMatch routine
782
783
784
785
786
787
788
789
790
791
792
793
794
 */
int
dnMatch(
	int *matchp,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *value,
	void *assertedValue )
{
	int match;
	struct berval *asserted = (struct berval *) assertedValue;

795
796
797
	assert( matchp != NULL );
	assert( value != NULL );
	assert( assertedValue != NULL );
798
799
	assert( !BER_BVISNULL( value ) );
	assert( !BER_BVISNULL( asserted ) );
800
801
802
803
	
	match = value->bv_len - asserted->bv_len;

	if ( match == 0 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
804
805
		match = memcmp( value->bv_val, asserted->bv_val, 
				value->bv_len );
806
807
808
809
	}

	Debug( LDAP_DEBUG_ARGS, "dnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
		match, value->bv_val, asserted->bv_val );
810

811
	*matchp = match;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
	return LDAP_SUCCESS;
}

/*
 * dnRelativeMatch routine
 */
int
dnRelativeMatch(
	int *matchp,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *value,
	void *assertedValue )
{
	int match;
	struct berval *asserted = (struct berval *) assertedValue;

830
831
832
	assert( matchp != NULL );
	assert( value != NULL );
	assert( assertedValue != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
	assert( !BER_BVISNULL( value ) );
	assert( !BER_BVISNULL( asserted ) );

	if( mr == slap_schema.si_mr_dnSubtreeMatch ) {
		if( asserted->bv_len > value->bv_len ) {
			match = -1;
		} else if ( asserted->bv_len == value->bv_len ) {
			match = memcmp( value->bv_val, asserted->bv_val, 
				value->bv_len );
		} else {
			if( DN_SEPARATOR(
				value->bv_val[value->bv_len - asserted->bv_len - 1] ))
			{
				match = memcmp(
					&value->bv_val[value->bv_len - asserted->bv_len],
					asserted->bv_val, 
					asserted->bv_len );
			} else {
851
				match = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
852
853
854
			}
		}

855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
		*matchp = match;
		return LDAP_SUCCESS;
	}

	if( mr == slap_schema.si_mr_dnSuperiorMatch ) {
		asserted = value;
		value = (struct berval *) assertedValue;
		mr = slap_schema.si_mr_dnSubordinateMatch;
	}

	if( mr == slap_schema.si_mr_dnSubordinateMatch ) {
		if( asserted->bv_len >= value->bv_len ) {
			match = -1;
		} else {
			if( DN_SEPARATOR(
				value->bv_val[value->bv_len - asserted->bv_len - 1] ))
			{
				match = memcmp(
					&value->bv_val[value->bv_len - asserted->bv_len],
					asserted->bv_val, 
					asserted->bv_len );
			} else {
877
				match = 1;
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
			}
		}

		*matchp = match;
		return LDAP_SUCCESS;
	}

	if( mr == slap_schema.si_mr_dnOneLevelMatch ) {
		if( asserted->bv_len >= value->bv_len ) {
			match = -1;
		} else {
			if( DN_SEPARATOR(
				value->bv_val[value->bv_len - asserted->bv_len - 1] ))
			{
				match = memcmp(
					&value->bv_val[value->bv_len - asserted->bv_len],
					asserted->bv_val, 
					asserted->bv_len );

				if( !match ) {
					struct berval rdn;
					rdn.bv_val = value->bv_val;
					rdn.bv_len = value->bv_len - asserted->bv_len - 1;
					match = dnIsOneLevelRDN( &rdn ) ? 0 : 1;
				}
			} else {
904
				match = 1;
905
906
907
			}
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
908
909
910
911
		*matchp = match;
		return LDAP_SUCCESS;
	}

912
913
	/* should not be reachable */
	assert( 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
914
	return LDAP_OTHER;
915
916
}

917
918
919
920
921
922
923
924
925
926
927
928
int
rdnMatch(
	int *matchp,
	slap_mask_t flags,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *value,
	void *assertedValue )
{
	int match;
	struct berval *asserted = (struct berval *) assertedValue;

929
930
931
	assert( matchp != NULL );
	assert( value != NULL );
	assert( assertedValue != NULL );
932
933
934
935
936
937
938
939
	
	match = value->bv_len - asserted->bv_len;

	if ( match == 0 ) {
		match = memcmp( value->bv_val, asserted->bv_val, 
				value->bv_len );
	}

Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
940
	Debug( LDAP_DEBUG_ARGS, "rdnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
941
942
943
		match, value->bv_val, asserted->bv_val );

	*matchp = match;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
944
	return LDAP_SUCCESS;
945
946
947
}


948
949
950
951
/*
 * dnParent - dn's parent, in-place
 * note: the incoming dn is assumed to be normalized/prettyfied,
 * so that escaped rdn/ava separators are in '\'+hexpair form
952
953
954
955
 *
 * note: "dn" and "pdn" can point to the same berval;
 * beware that, in this case, the pointer to the original buffer
 * will get lost.
956
 */
957
void
958
dnParent( 
959
960
	struct berval	*dn, 
	struct berval	*pdn )
961
{
Howard Chu's avatar
Howard Chu committed
962
	char	*p;
963

964
	p = ber_bvchr( dn, ',' );
965
966
967

	/* one-level dn */
	if ( p == NULL ) {
968
		pdn->bv_val = dn->bv_val + dn->bv_len;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
969
		pdn->bv_len = 0;
970
		return;
971
972
	}

973
	assert( DN_SEPARATOR( p[ 0 ] ) );
974
975
976
	p++;

	assert( ATTR_LEADCHAR( p[ 0 ] ) );
977
	pdn->bv_len = dn->bv_len - (p - dn->bv_val);
978
	pdn->bv_val = p;
979

980
	return;
981
982
}

983
984
985
986
987
988
989
990
991
992
993
994
995
/*
 * dnRdn - dn's rdn, in-place
 * note: the incoming dn is assumed to be normalized/prettyfied,
 * so that escaped rdn/ava separators are in '\'+hexpair form
 */
void
dnRdn( 
	struct berval	*dn, 
	struct berval	*rdn )
{
	char	*p;

	*rdn = *dn;
996
	p = ber_bvchr( dn, ',' );
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009

	/* one-level dn */
	if ( p == NULL ) {
		return;
	}

	assert( DN_SEPARATOR( p[ 0 ] ) );
	assert( ATTR_LEADCHAR( p[ 1 ] ) );
	rdn->bv_len = p - dn->bv_val;

	return;
}

1010
1011
int
dnExtractRdn( 
1012
	struct berval	*dn, 
Howard Chu's avatar
Howard Chu committed
1013
1014
	struct berval 	*rdn,
	void *ctx )
1015
{
Howard Chu's avatar
Howard Chu committed
1016
	LDAPRDN		tmpRDN;
1017
1018
1019
	const char	*p;
	int		rc;

1020
1021
	assert( dn != NULL );
	assert( rdn != NULL );
1022

1023
1024
1025
1026
	if( dn->bv_len == 0 ) {
		return LDAP_OTHER;
	}

Howard Chu's avatar
Howard Chu committed
1027
	rc = ldap_bv2rdn_x( dn, &tmpRDN, (char **)&p, LDAP_DN_FORMAT_LDAP, ctx );
1028
1029
1030
1031
	if ( rc != LDAP_SUCCESS ) {
		return rc;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1032
1033
	rc = ldap_rdn2bv_x( tmpRDN, rdn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY,
		ctx );
1034

Howard Chu's avatar
Howard Chu committed
1035
	ldap_rdnfree_x( tmpRDN, ctx );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1036
	return rc;
1037
1038
1039
}

/*
1040
 * We can assume the input is a prettied or normalized DN
1041
 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1042
ber_len_t
1043
1044
dn_rdnlen(
	Backend		*be,
1045
	struct berval	*dn_in )
1046
{
1047
	const char	*p;
1048

1049
	assert( dn_in != NULL );
1050
1051
1052
1053
1054

	if ( dn_in == NULL ) {
		return 0;
	}

1055
	if ( !dn_in->bv_len ) {
1056
1057
1058
		return 0;
	}

1059
	if ( be != NULL && be_issuffix( be, dn_in ) ) {
1060
1061
1062
		return 0;
	}

1063
	p = ber_bvchr( dn_in, ',' );
1064

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1065
	return p ? (ber_len_t) (p - dn_in->bv_val) : dn_in->bv_len;
1066
1067
}

1068

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1069
/* rdnValidate:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1070
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1071
1072
 * LDAP_SUCCESS if rdn is a legal rdn;
 * LDAP_INVALID_SYNTAX otherwise (including a sequence of rdns)
1073
1074
 */
int
1075
rdn_validate( struct berval *rdn )
1076
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1077
1078
1079
1080
1081
#if 1
	/* Major cheat!
	 * input is a pretty or normalized DN
	 * hence, we can just search for ','
	 */
1082
1083
1084
	if( rdn == NULL || rdn->bv_len == 0 ||
		rdn->bv_len > SLAP_LDAPDN_MAXLEN )
	{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1085
1086
		return LDAP_INVALID_SYNTAX;
	}
1087
	return ber_bvchr( rdn, ',' ) == NULL
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1088
1089
1090
		? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;

#else
1091
1092
1093
	LDAPRDN		*RDN, **DN[ 2 ] = { &RDN, NULL };
	const char	*p;
	int		rc;
1094

1095
1096
1097
1098
1099
	/*
	 * must be non-empty
	 */
	if ( rdn == NULL || rdn == '\0' ) {
		return 0;
1100
1101
	}

1102
1103
1104
	/*
	 * must be parsable
	 */
1105
	rc = ldap_bv2rdn( rdn, &RDN, (char **)&p, LDAP_DN_FORMAT_LDAP );
1106
1107
	if ( rc != LDAP_SUCCESS ) {
		return 0;
1108
1109
	}

1110
1111
1112
1113
1114
	/*
	 * Must be one-level
	 */
	if ( p[ 0 ] != '\0' ) {
		return 0;
1115
1116
	}

1117
1118
1119
1120
1121
	/*
	 * Schema-aware validate
	 */
	if ( rc == LDAP_SUCCESS ) {
		rc = LDAPDN_validate( DN );
1122
	}
1123
	ldap_rdnfree( RDN );
1124

1125
1126
1127
1128
	/*
	 * Must validate (there's a repeated parsing ...)
	 */
	return ( rc == LDAP_SUCCESS );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1129
#endif
1130
}
1131
1132
1133
1134


/* build_new_dn:
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1135
 * Used by back-bdb back_modrdn to create the new dn of entries being
1136
1137
 * renamed.
 *
1138
 * new_dn = parent (p_dn) + separator + rdn (newrdn) + null.
1139
1140
1141
 */

void
1142
1143
build_new_dn( struct berval * new_dn,
	struct berval * parent_dn,
1144
1145
	struct berval * newrdn,
	void *memctx )
1146
{
Howard Chu's avatar
Howard Chu committed
1147
	char *ptr;
Juan Gomez's avatar
Juan Gomez committed
1148

1149
	if ( parent_dn == NULL || parent_dn->bv_len == 0 ) {
Howard Chu's avatar
Howard Chu committed
1150
		ber_dupbv_x( new_dn, newrdn, memctx );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1151
1152
1153
		return;
	}

1154
	new_dn->bv_len = parent_dn->bv_len + newrdn->bv_len + 1;
1155
	new_dn->bv_val = (char *) slap_sl_malloc( new_dn->bv_len + 1, memctx );
1156

1157
	ptr = lutil_strncopy( new_dn->bv_val, newrdn->bv_val, newrdn->bv_len );
Howard Chu's avatar
Howard Chu committed
1158
	*ptr++ = ',';
1159
	strcpy( ptr, parent_dn->bv_val );
1160
}
1161

1162
1163
1164
1165
1166
1167
1168
1169
1170
1171

/*
 * dnIsSuffix - tells whether suffix is a suffix of dn.
 * Both dn and suffix must be normalized.
 */
int
dnIsSuffix(
	const struct berval *dn,
	const struct berval *suffix )
{
1172
	int	d;
1173

1174
1175
	assert( dn != NULL );
	assert( suffix != NULL );
1176

1177
1178
	d = dn->bv_len - suffix->bv_len;

1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
	/* empty suffix matches any dn */
	if ( suffix->bv_len == 0 ) {
		return 1;
	}

	/* suffix longer than dn */
	if ( d < 0 ) {
		return 0;
	}

	/* no rdn separator or escaped rdn separator */
1190
	if ( d > 1 && !DN_SEPARATOR( dn->bv_val[ d - 1 ] ) ) {
1191
1192
1193
1194
1195
1196
1197
1198
1199
		return 0;
	}

	/* no possible match or malformed dn */
	if ( d == 1 ) {
		return 0;
	}

	/* compare */
1200
	return( strncmp( dn->bv_val + d, suffix->bv_val, suffix->bv_len ) == 0 );
1201
}
1202

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
/*
 * In place; assumes:
 * - ndn is normalized
 * - nbase is normalized
 * - dnIsSuffix( ndn, nbase ) == TRUE
 * - LDAP_SCOPE_DEFAULT == LDAP_SCOPE_SUBTREE
 */
int
dnIsWithinScope( struct berval *ndn, struct berval *nbase, int scope )
{
	assert( ndn != NULL );
	assert( nbase != NULL );
	assert( !BER_BVISNULL( ndn ) );
	assert( !BER_BVISNULL( nbase ) );

	switch ( scope ) {
	case LDAP_SCOPE_DEFAULT:
	case LDAP_SCOPE_SUBTREE:
		break;

	case LDAP_SCOPE_BASE:
		if ( ndn->bv_len != nbase->bv_len ) {
			return 0;
		}
		break;

	case LDAP_SCOPE_ONELEVEL: {
		struct berval pndn;
		dnParent( ndn, &pndn );
		if ( pndn.bv_len != nbase->bv_len ) {
			return 0;
		}
		} break;

	case LDAP_SCOPE_SUBORDINATE:
		if ( ndn->bv_len == nbase->bv_len ) {
			return 0;
		}
		break;

	/* unknown scope */
	default:
		return -1;
	}

	return 1;
}

/*
 * In place; assumes:
 * - ndn is normalized
 * - nbase is normalized
 * - LDAP_SCOPE_DEFAULT == LDAP_SCOPE_SUBTREE
 */
int
dnIsSuffixScope( struct berval *ndn, struct berval *nbase, int scope )
{
	if ( !dnIsSuffix( ndn, nbase ) ) {
		return 0;
	}

	return dnIsWithinScope( ndn, nbase, scope );
}

1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
int
dnIsOneLevelRDN( struct berval *rdn )
{
	ber_len_t	len = rdn->bv_len;
	for ( ; len--; ) {
		if ( DN_SEPARATOR( rdn->bv_val[ len ] ) ) {
			return 0;
		}
	}

	return 1;
}

1280
#ifdef HAVE_TLS
1281
static SLAP_CERT_MAP_FN *DNX509PeerNormalizeCertMap = NULL;
1282
#endif
1283
1284
1285
1286
1287
1288
1289
1290
1291