modrdn.c 15.2 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
4
 * Copyright 1998-2020 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
6
 * All rights reserved.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
8
9
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
10
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
11
12
13
14
15
 * 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 1999, Juan C. Gomez, All rights reserved.
16
17
18
19
20
21
 * This software is not subject to any license of Silicon Graphics 
 * Inc. or Purdue University.
 *
 * Redistribution and use in source and binary forms are permitted
 * without restriction or fee of any kind as long as this notice
 * is preserved.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
22
23
24
 */
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
 * All rights reserved.
25
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
26
27
28
29
30
31
 * 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.
32
33
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
35
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
36
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
37
38
39
40

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
41
42
#include "slap.h"

43
int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
44
do_modrdn(
45
46
    Operation	*op,
    SlapReply	*rs
Kurt Zeilenga's avatar
Kurt Zeilenga committed
47
48
)
{
49
50
51
	struct berval	dn = BER_BVNULL;
	struct berval	newrdn = BER_BVNULL;
	struct berval	newSuperior = BER_BVNULL;
52
	ber_int_t	deloldrdn;
53

Kurt Zeilenga's avatar
Kurt Zeilenga committed
54
	struct berval pnewSuperior = BER_BVNULL;
55

Kurt Zeilenga's avatar
Kurt Zeilenga committed
56
	struct berval nnewSuperior = BER_BVNULL;
57

58
	ber_len_t	length;
59

60
61
	Debug( LDAP_DEBUG_TRACE, "%s do_modrdn\n",
			op->o_log_prefix, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
62
63
64
65
66
67
	/*
	 * Parse the modrdn request.  It looks like this:
	 *
	 *	ModifyRDNRequest := SEQUENCE {
	 *		entry	DistinguishedName,
	 *		newrdn	RelativeDistinguishedName
68
69
	 *		deleteoldrdn	BOOLEAN,
	 *		newSuperior	[0] LDAPDN OPTIONAL (v3 Only!)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
70
71
72
	 *	}
	 */

73
	if ( ber_scanf( op->o_ber, "{mmb", &dn, &newrdn, &deloldrdn )
74
75
	    == LBER_ERROR )
	{
76
77
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf failed\n",
			op->o_log_prefix, 0, 0 );
78
		send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
79
		return SLAPD_DISCONNECT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
80
81
	}

82
83
84
	/* Check for newSuperior parameter, if present scan it */

	if ( ber_peek_tag( op->o_ber, &length ) == LDAP_TAG_NEWSUPERIOR ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
85
		if ( op->o_protocol < LDAP_VERSION3 ) {
86
			/* Connection record indicates v2 but field 
87
88
89
			 * newSuperior is present: report error.
			 */
			Debug( LDAP_DEBUG_ANY,
90
91
				"%s do_modrdn: newSuperior requires LDAPv3\n",
				op->o_log_prefix, 0, 0 );
92

93
			send_ldap_discon( op, rs,
94
				LDAP_PROTOCOL_ERROR, "newSuperior requires LDAPv3" );
95
			rs->sr_err = SLAPD_DISCONNECT;
Howard Chu's avatar
Howard Chu committed
96
			goto cleanup;
97
		}
98

99
		if ( ber_scanf( op->o_ber, "m", &newSuperior ) 
100
101
		     == LBER_ERROR ) {

102
103
			Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf(\"m\") failed\n",
				op->o_log_prefix, 0, 0 );
104

105
			send_ldap_discon( op, rs,
106
				LDAP_PROTOCOL_ERROR, "decoding error" );
107
			rs->sr_err = SLAPD_DISCONNECT;
Howard Chu's avatar
Howard Chu committed
108
			goto cleanup;
109
		}
Howard Chu's avatar
Howard Chu committed
110
111
		op->orr_newSup = &pnewSuperior;
		op->orr_nnewSup = &nnewSuperior;
112
	}
113

114
115
	Debug( LDAP_DEBUG_ARGS,
	    "do_modrdn: dn (%s) newrdn (%s) newsuperior (%s)\n",
116
117
		dn.bv_val, newrdn.bv_val,
		newSuperior.bv_len ? newSuperior.bv_val : "" );
118

119
	if ( ber_scanf( op->o_ber, /*{*/ "}") == LBER_ERROR ) {
120
121
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf failed\n",
			op->o_log_prefix, 0, 0 );
122
		send_ldap_discon( op, rs,
123
			LDAP_PROTOCOL_ERROR, "decoding error" );
124
		rs->sr_err = SLAPD_DISCONNECT;
Howard Chu's avatar
Howard Chu committed
125
		goto cleanup;
126
127
	}

128
	if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
129
130
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: get_ctrls failed\n",
			op->o_log_prefix, 0, 0 );
Gary Williams's avatar
Gary Williams committed
131
		/* get_ctrls has sent results.	Now clean up. */
Howard Chu's avatar
Howard Chu committed
132
		goto cleanup;
133
134
	} 

Howard Chu's avatar
Howard Chu committed
135
	rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
136
	if( rs->sr_err != LDAP_SUCCESS ) {
137
138
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid dn (%s)\n",
			op->o_log_prefix, dn.bv_val, 0 );
139
		send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
140
141
142
		goto cleanup;
	}

143
144
	/* FIXME: should have/use rdnPretty / rdnNormalize routines */

Howard Chu's avatar
Howard Chu committed
145
	rs->sr_err = dnPrettyNormal( NULL, &newrdn, &op->orr_newrdn, &op->orr_nnewrdn, op->o_tmpmemctx );
146
	if( rs->sr_err != LDAP_SUCCESS ) {
147
148
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid newrdn (%s)\n",
			op->o_log_prefix, newrdn.bv_val, 0 );
149
		send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid new RDN" );
150
151
152
		goto cleanup;
	}

153
	if( rdn_validate( &op->orr_newrdn ) != LDAP_SUCCESS ) {
154
155
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid rdn (%s)\n",
			op->o_log_prefix, op->orr_newrdn.bv_val, 0 );
156
		send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid new RDN" );
157
158
159
		goto cleanup;
	}

Howard Chu's avatar
Howard Chu committed
160
	if( op->orr_newSup ) {
161
		rs->sr_err = dnPrettyNormal( NULL, &newSuperior, &pnewSuperior,
Howard Chu's avatar
Howard Chu committed
162
			&nnewSuperior, op->o_tmpmemctx );
163
		if( rs->sr_err != LDAP_SUCCESS ) {
164
			Debug( LDAP_DEBUG_ANY,
165
166
				"%s do_modrdn: invalid newSuperior (%s)\n",
				op->o_log_prefix, newSuperior.bv_val, 0 );
167
			send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid newSuperior" );
168
169
170
171
			goto cleanup;
		}
	}

172
173
174
	Statslog( LDAP_DEBUG_STATS, "%s MODRDN dn=\"%s\"\n",
	    op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 );

175
	op->orr_deleteoldrdn = deloldrdn;
176
	op->orr_modlist = NULL;
177

178
179
180
181
182
183
184
	/* prepare modlist of modifications from old/new RDN */
	rs->sr_err = slap_modrdn2mods( op, rs );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
		goto cleanup;
	}

185
186
187
	op->o_bd = frontendDB;
	rs->sr_err = frontendDB->be_modrdn( op, rs );

188
189
190
191
192
193
#ifdef LDAP_X_TXN
	if( rs->sr_err == LDAP_X_TXN_SPECIFY_OKAY ) {
		/* skip cleanup */
	}
#endif

194
195
196
197
198
199
200
cleanup:
	op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
	op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );

	op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );	
	op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );	

201
202
203
	if ( op->orr_modlist != NULL )
		slap_mods_free( op->orr_modlist, 1 );

204
	if ( !BER_BVISNULL( &pnewSuperior ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
205
		op->o_tmpfree( pnewSuperior.bv_val, op->o_tmpmemctx );
206
207
	}
	if ( !BER_BVISNULL( &nnewSuperior ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
208
		op->o_tmpfree( nnewSuperior.bv_val, op->o_tmpmemctx );
209
	}
210
211
212
213
214
215
216

	return rs->sr_err;
}

int
fe_op_modrdn( Operation *op, SlapReply *rs )
{
217
	struct berval	dest_ndn = BER_BVNULL, dest_pndn, pdn = BER_BVNULL;
218
	BackendDB	*op_be, *bd = op->o_bd;
219
	ber_slen_t	diff;
220
221
	
	if( op->o_req_ndn.bv_len == 0 ) {
222
223
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: root dse!\n",
			op->o_log_prefix, 0, 0 );
224
225
226
227
228
		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
			"cannot rename the root DSE" );
		goto cleanup;

	} else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) {
229
230
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: subschema subentry: %s (%ld)\n",
			op->o_log_prefix, frontendDB->be_schemandn.bv_val, (long)frontendDB->be_schemandn.bv_len );
231
232
233
234
235
236

		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
			"cannot rename subschema subentry" );
		goto cleanup;
	}

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
	if( op->orr_nnewSup ) {
		dest_pndn = *op->orr_nnewSup;
	} else {
		dnParent( &op->o_req_ndn, &dest_pndn );
	}
	build_new_dn( &dest_ndn, &dest_pndn, &op->orr_nnewrdn, op->o_tmpmemctx );

	diff = (ber_slen_t) dest_ndn.bv_len - (ber_slen_t) op->o_req_ndn.bv_len;
	if ( diff > 0 ? dnIsSuffix( &dest_ndn, &op->o_req_ndn )
		: diff < 0 && dnIsSuffix( &op->o_req_ndn, &dest_ndn ) )
	{
		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
			diff > 0 ? "cannot place an entry below itself"
			: "cannot place an entry above itself" );
		goto cleanup;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
254
255
256
257
258
	/*
	 * We could be serving multiple database backends.  Select the
	 * appropriate one, or send a referral to our "referral server"
	 * if we don't hold it.
	 */
259
	op->o_bd = select_backend( &op->o_req_ndn, 1 );
260
	if ( op->o_bd == NULL ) {
261
		op->o_bd = bd;
262
		rs->sr_ref = referral_rewrite( default_referral,
263
			NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
264
		if (!rs->sr_ref) rs->sr_ref = default_referral;
265

Pierangelo Masarati's avatar
Pierangelo Masarati committed
266
267
268
269
		if ( rs->sr_ref != NULL ) {
			rs->sr_err = LDAP_REFERRAL;
			send_ldap_result( op, rs );

270
			if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
271
272
		} else {
			send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
273
				"no global superior knowledge" );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
274
		}
Howard Chu's avatar
Howard Chu committed
275
		goto cleanup;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
276
277
	}

278
279
280
	/* If we've got a glued backend, check the real backend */
	op_be = op->o_bd;
	if ( SLAP_GLUE_INSTANCE( op->o_bd )) {
281
		op->o_bd = select_backend( &op->o_req_ndn, 0 );
282
283
	}

284
	/* check restrictions */
285
286
	if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
287
		goto cleanup;
288
289
	}

290
	/* check for referrals */
291
	if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
292
293
294
		goto cleanup;
	}

295
296
	/* check that destination DN is in the same backend as source DN */
	if ( select_backend( &dest_ndn, 0 ) != op->o_bd ) {
297
298
			send_ldap_error( op, rs, LDAP_AFFECTS_MULTIPLE_DSAS,
				"cannot rename between DSAs" );
Howard Chu's avatar
Howard Chu committed
299
			goto cleanup;
300
	}
301

Kurt Zeilenga's avatar
Kurt Zeilenga committed
302
	/*
303
304
	 * do the modrdn if 1 && (2 || 3)
	 * 1) there is a modrdn function implemented in this backend;
305
	 * 2) this backend is the provider for what it holds;
306
	 * 3) it's a replica and the dn supplied is the update_ndn.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
307
	 */
308
	if ( op->o_bd->be_modrdn ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
309
		/* do the update here */
310
		int repl_user = be_isupdate( op );
311
		if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user )
312
		{
313
			op->o_bd = op_be;
314
315
			op->o_bd->be_modrdn( op, rs );

316
			if ( op->o_bd->be_delete ) {
317
318
319
320
321
322
				struct berval	org_req_dn = BER_BVNULL;
				struct berval	org_req_ndn = BER_BVNULL;
				struct berval	org_dn = BER_BVNULL;
				struct berval	org_ndn = BER_BVNULL;
				int		org_managedsait;

323
324
325
326
327
328
329
				org_req_dn = op->o_req_dn;
				org_req_ndn = op->o_req_ndn;
				org_dn = op->o_dn;
				org_ndn = op->o_ndn;
				org_managedsait = get_manageDSAit( op );
				op->o_dn = op->o_bd->be_rootdn;
				op->o_ndn = op->o_bd->be_rootndn;
Howard Chu's avatar
Howard Chu committed
330
				op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
331
332
333

				while ( rs->sr_err == LDAP_SUCCESS &&
						op->o_delete_glue_parent ) {
334
					op->o_delete_glue_parent = 0;
335
336
337
338
339
340
341
342
343
344
345
346
347
					if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) {
						slap_callback cb = { NULL };
						cb.sc_response = slap_null_cb;
						dnParent( &op->o_req_ndn, &pdn );
						op->o_req_dn = pdn;
						op->o_req_ndn = pdn;
						op->o_callback = &cb;
						op->o_bd->be_delete( op, rs );
					} else {
						break;
					}
				}
				op->o_managedsait = org_managedsait;
348
				op->o_dn = org_dn;
349
350
351
352
353
354
				op->o_ndn = org_ndn;
				op->o_req_dn = org_req_dn;
				op->o_req_ndn = org_req_ndn;
				op->o_delete_glue_parent = 0;
			}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
355
		} else {
356
			BerVarray defref = op->o_bd->be_update_refs
357
				? op->o_bd->be_update_refs : default_referral;
358

359
360
361
362
363
364
365
366
367
368
			if ( defref != NULL ) {
				rs->sr_ref = referral_rewrite( defref,
					NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
				if (!rs->sr_ref) rs->sr_ref = defref;

				rs->sr_err = LDAP_REFERRAL;
				send_ldap_result( op, rs );

				if (rs->sr_ref != defref) ber_bvarray_free( rs->sr_ref );
			} else {
369
370
				send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
					"shadow context; no update referral" );
371
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
372
373
		}
	} else {
374
375
		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
			"operation not supported within namingContext" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
376
377
	}

378
cleanup:;
379
380
	if ( dest_ndn.bv_val != NULL )
		ber_memfree_x( dest_ndn.bv_val, op->o_tmpmemctx );
381
	op->o_bd = bd;
382
	return rs->sr_err;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
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
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
/* extracted from slap_modrdn2mods() */
static int
mod_op_add_val(
	Operation *op,
	AttributeDescription * const desc,
	struct berval * const val,
	short const sm_op )
{
	int rv = LDAP_SUCCESS;
	Modifications *mod_tmp;
	mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) );
	mod_tmp->sml_desc = desc;
	BER_BVZERO( &mod_tmp->sml_type );
	mod_tmp->sml_numvals = 1;
	mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
	ber_dupbv( &mod_tmp->sml_values[0], val );
	mod_tmp->sml_values[1].bv_val = NULL;
	if( desc->ad_type->sat_equality && desc->ad_type->sat_equality->smr_normalize) {
		mod_tmp->sml_nvalues = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
		rv = desc->ad_type->sat_equality->smr_normalize(
			SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
			desc->ad_type->sat_syntax,
			desc->ad_type->sat_equality,
			&mod_tmp->sml_values[0],
			&mod_tmp->sml_nvalues[0], NULL );
		if (rv != LDAP_SUCCESS) {
			ch_free(mod_tmp->sml_nvalues);
			ch_free(mod_tmp->sml_values[0].bv_val);
			ch_free(mod_tmp->sml_values);
			ch_free(mod_tmp);
			goto done;
		}
		mod_tmp->sml_nvalues[1].bv_val = NULL;
	} else {
		mod_tmp->sml_nvalues = NULL;
	}
	mod_tmp->sml_op = sm_op;
	mod_tmp->sml_flags = 0;
	mod_tmp->sml_next = op->orr_modlist;
	op->orr_modlist = mod_tmp;
done:
	return rv;
}

429
430
431
int
slap_modrdn2mods(
	Operation	*op,
432
	SlapReply	*rs )
433
434
{
	int		a_cnt, d_cnt;
435
436
437
438
	LDAPRDN		old_rdn = NULL;
	LDAPRDN		new_rdn = NULL;

	assert( !BER_BVISEMPTY( &op->oq_modrdn.rs_newrdn ) );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
439
440
441

	/* if requestDN is empty, silently reset deleteOldRDN */
	if ( BER_BVISEMPTY( &op->o_req_dn ) ) op->orr_deleteoldrdn = 0;
442
443
444
445

	if ( ldap_bv2rdn_x( &op->oq_modrdn.rs_newrdn, &new_rdn,
		(char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) {
		Debug( LDAP_DEBUG_TRACE,
446
447
448
			"%s slap_modrdn2mods: can't figure out "
			"type(s)/value(s) of newrdn\n",
			op->o_log_prefix, 0, 0 );
449
		rs->sr_err = LDAP_INVALID_DN_SYNTAX;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
450
		rs->sr_text = "unknown type(s)/value(s) used in RDN";
451
452
		goto done;
	}
453

454
455
456
457
	if ( op->oq_modrdn.rs_deleteoldrdn ) {
		if ( ldap_bv2rdn_x( &op->o_req_dn, &old_rdn,
			(char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) {
			Debug( LDAP_DEBUG_TRACE,
458
459
460
				"%s slap_modrdn2mods: can't figure out "
				"type(s)/value(s) of oldrdn\n",
				op->o_log_prefix, 0, 0 );
461
462
463
464
465
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "cannot parse RDN from old DN";
			goto done;
		}
	}
466
	rs->sr_text = NULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
467

468
	/* Add new attribute values to the entry */
Howard Chu's avatar
Howard Chu committed
469
	for ( a_cnt = 0; new_rdn[a_cnt]; a_cnt++ ) {
470
471
		AttributeDescription	*desc = NULL;

Howard Chu's avatar
Howard Chu committed
472
		rs->sr_err = slap_bv2ad( &new_rdn[a_cnt]->la_attr, &desc, &rs->sr_text );
473

474
		if ( rs->sr_err != LDAP_SUCCESS ) {
475
			Debug( LDAP_DEBUG_TRACE,
476
477
				"%s slap_modrdn2mods: %s: %s (new)\n",
				op->o_log_prefix,
478
				rs->sr_text,
479
				new_rdn[ a_cnt ]->la_attr.bv_val );
480
481
482
			goto done;		
		}

483
484
485
486
487
488
489
490
491
492
493
		if ( !desc->ad_type->sat_equality ) {
			Debug( LDAP_DEBUG_TRACE,
				"%s slap_modrdn2mods: %s: %s (new)\n",
				op->o_log_prefix,
				rs->sr_text,
				new_rdn[ a_cnt ]->la_attr.bv_val );
			rs->sr_text = "naming attribute has no equality matching rule";
			rs->sr_err = LDAP_NAMING_VIOLATION;
			goto done;
		}

494
		/* Apply modification */
495
496
497
		rs->sr_err = mod_op_add_val( op, desc, &new_rdn[a_cnt]->la_value, SLAP_MOD_SOFTADD );
		if (rs->sr_err != LDAP_SUCCESS)
			goto done;
498
499
500
	}

	/* Remove old rdn value if required */
Howard Chu's avatar
Howard Chu committed
501
	if ( op->orr_deleteoldrdn ) {
Howard Chu's avatar
Howard Chu committed
502
		for ( d_cnt = 0; old_rdn[d_cnt]; d_cnt++ ) {
503
504
			AttributeDescription	*desc = NULL;

Howard Chu's avatar
Howard Chu committed
505
			rs->sr_err = slap_bv2ad( &old_rdn[d_cnt]->la_attr, &desc, &rs->sr_text );
506
			if ( rs->sr_err != LDAP_SUCCESS ) {
507
				Debug( LDAP_DEBUG_TRACE,
508
509
					"%s slap_modrdn2mods: %s: %s (old)\n",
					op->o_log_prefix,
510
					rs->sr_text, 
511
					old_rdn[d_cnt]->la_attr.bv_val );
512
513
514
515
				goto done;		
			}

			/* Apply modification */
516
517
518
			rs->sr_err = mod_op_add_val( op, desc, &old_rdn[d_cnt]->la_value, LDAP_MOD_DELETE );
			if (rs->sr_err != LDAP_SUCCESS)
				goto done;
519
520
521
522
		}
	}
	
done:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
523

524
	/* LDAP v2 supporting correct attribute handling. */
525
	if ( rs->sr_err != LDAP_SUCCESS && op->orr_modlist != NULL ) {
526
527
		slap_mods_free( op->orr_modlist, 1 );
		op->orr_modlist = NULL;
528
	}
529

530
531
532
533
534
	if ( new_rdn != NULL ) {
		ldap_rdnfree_x( new_rdn, op->o_tmpmemctx );
	}
	if ( old_rdn != NULL ) {
		ldap_rdnfree_x( old_rdn, op->o_tmpmemctx );
535
536
	}

537
	return rs->sr_err;
538
539
}