modrdn.c 16.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
	Debug( LDAP_DEBUG_TRACE, "%s do_modrdn\n",
61
			op->o_log_prefix );
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
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf failed\n",
77
			op->o_log_prefix );
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
				"%s do_modrdn: newSuperior requires LDAPv3\n",
91
				op->o_log_prefix );
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
			Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf(\"m\") failed\n",
103
				op->o_log_prefix );
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
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf failed\n",
121
			op->o_log_prefix );
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
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: get_ctrls failed\n",
130
			op->o_log_prefix );
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
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid dn (%s)\n",
138
			op->o_log_prefix, dn.bv_val );
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
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid newrdn (%s)\n",
148
			op->o_log_prefix, newrdn.bv_val );
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
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: invalid rdn (%s)\n",
155
			op->o_log_prefix, op->orr_newrdn.bv_val );
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
				"%s do_modrdn: invalid newSuperior (%s)\n",
166
				op->o_log_prefix, newSuperior.bv_val );
167
			send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid newSuperior" );
168
169
170
171
			goto cleanup;
		}
	}

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

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
	if ( rs->sr_err == SLAPD_ASYNCOP ) {
		/* skip cleanup */
		return rs->sr_err;
	}
192
	if( rs->sr_err == LDAP_TXN_SPECIFY_OKAY ) {
193
		/* skip cleanup */
194
		return rs->sr_err;
195
196
	}

197
198
199
200
201
202
203
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 );	

204
205
206
	if ( op->orr_modlist != NULL )
		slap_mods_free( op->orr_modlist, 1 );

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

	return rs->sr_err;
}

int
fe_op_modrdn( Operation *op, SlapReply *rs )
{
220
	struct berval	dest_ndn = BER_BVNULL, dest_pndn, pdn = BER_BVNULL;
221
	BackendDB	*op_be, *bd = op->o_bd;
222
	ber_slen_t	diff;
223
224
	
	if( op->o_req_ndn.bv_len == 0 ) {
225
		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: root dse!\n",
226
			op->o_log_prefix );
227
228
229
230
231
		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 ) ) {
232
233
		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 );
234
235
236
237
238
239

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

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
	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
257
258
259
260
261
	/*
	 * 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.
	 */
262
	op->o_bd = select_backend( &op->o_req_ndn, 1 );
263
	if ( op->o_bd == NULL ) {
264
		op->o_bd = bd;
265
		rs->sr_ref = referral_rewrite( default_referral,
266
			NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
267
		if (!rs->sr_ref) rs->sr_ref = default_referral;
268

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

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

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

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

293
	/* check for referrals */
294
	if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
295
296
297
		goto cleanup;
	}

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

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

319
			if ( op->o_bd->be_delete ) {
320
321
322
323
324
325
				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;

326
327
328
329
330
331
332
				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
333
				op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
334
335
336

				while ( rs->sr_err == LDAP_SUCCESS &&
						op->o_delete_glue_parent ) {
337
					op->o_delete_glue_parent = 0;
338
339
340
341
342
343
344
345
346
347
348
349
350
					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;
351
				op->o_dn = org_dn;
352
353
354
355
356
357
				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
358
		} else {
359
			BerVarray defref = op->o_bd->be_update_refs
360
				? op->o_bd->be_update_refs : default_referral;
361

362
363
364
365
366
367
368
369
370
371
			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 {
372
373
				send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
					"shadow context; no update referral" );
374
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
375
376
		}
	} else {
377
378
		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
			"operation not supported within namingContext" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
379
380
	}

381
cleanup:;
382
383
	if ( dest_ndn.bv_val != NULL )
		ber_memfree_x( dest_ndn.bv_val, op->o_tmpmemctx );
384
	op->o_bd = bd;
385
	return rs->sr_err;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
386
}
387
388
389
390

int
slap_modrdn2mods(
	Operation	*op,
391
	SlapReply	*rs )
392
393
{
	int		a_cnt, d_cnt;
394
395
396
397
	LDAPRDN		old_rdn = NULL;
	LDAPRDN		new_rdn = NULL;

	assert( !BER_BVISEMPTY( &op->oq_modrdn.rs_newrdn ) );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
398
399
400

	/* if requestDN is empty, silently reset deleteOldRDN */
	if ( BER_BVISEMPTY( &op->o_req_dn ) ) op->orr_deleteoldrdn = 0;
401
402
403
404

	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,
405
406
			"%s slap_modrdn2mods: can't figure out "
			"type(s)/value(s) of newrdn\n",
407
			op->o_log_prefix );
408
		rs->sr_err = LDAP_INVALID_DN_SYNTAX;
Howard Chu's avatar
Howard Chu committed
409
		rs->sr_text = "unknown type(s)/value(s) used in RDN";
410
411
		goto done;
	}
412

413
414
415
416
	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,
417
418
				"%s slap_modrdn2mods: can't figure out "
				"type(s)/value(s) of oldrdn\n",
419
				op->o_log_prefix );
420
421
422
423
424
			rs->sr_err = LDAP_OTHER;
			rs->sr_text = "cannot parse RDN from old DN";
			goto done;
		}
	}
425
	rs->sr_text = NULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
426

427
	/* Add new attribute values to the entry */
Howard Chu's avatar
Howard Chu committed
428
	for ( a_cnt = 0; new_rdn[a_cnt]; a_cnt++ ) {
429
430
431
		AttributeDescription	*desc = NULL;
		Modifications 		*mod_tmp;

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

434
		if ( rs->sr_err != LDAP_SUCCESS ) {
435
			Debug( LDAP_DEBUG_TRACE,
436
437
				"%s slap_modrdn2mods: %s: %s (new)\n",
				op->o_log_prefix,
438
				rs->sr_text,
439
				new_rdn[ a_cnt ]->la_attr.bv_val );
440
441
442
			goto done;		
		}

443
444
445
446
447
448
449
450
451
452
453
		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;
		}

454
		/* Apply modification */
455
		mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) );
456
		mod_tmp->sml_desc = desc;
Luke Howard's avatar
Luke Howard committed
457
		BER_BVZERO( &mod_tmp->sml_type );
458
		mod_tmp->sml_numvals = 1;
459
460
		mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
		ber_dupbv( &mod_tmp->sml_values[0], &new_rdn[a_cnt]->la_value );
461
462
		mod_tmp->sml_values[1].bv_val = NULL;
		if( desc->ad_type->sat_equality->smr_normalize) {
463
			mod_tmp->sml_nvalues = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
Howard Chu's avatar
Howard Chu committed
464
			rs->sr_err = desc->ad_type->sat_equality->smr_normalize(
465
				SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
466
467
468
				desc->ad_type->sat_syntax,
				desc->ad_type->sat_equality,
				&mod_tmp->sml_values[0],
469
				&mod_tmp->sml_nvalues[0], NULL );
Howard Chu's avatar
Howard Chu committed
470
471
472
473
474
475
476
			if (rs->sr_err != 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;
			}
477
478
479
480
			mod_tmp->sml_nvalues[1].bv_val = NULL;
		} else {
			mod_tmp->sml_nvalues = NULL;
		}
481
		mod_tmp->sml_op = SLAP_MOD_SOFTADD;
482
		mod_tmp->sml_flags = 0;
483
484
		mod_tmp->sml_next = op->orr_modlist;
		op->orr_modlist = mod_tmp;
485
486
487
	}

	/* Remove old rdn value if required */
Howard Chu's avatar
Howard Chu committed
488
	if ( op->orr_deleteoldrdn ) {
Howard Chu's avatar
Howard Chu committed
489
		for ( d_cnt = 0; old_rdn[d_cnt]; d_cnt++ ) {
490
491
492
			AttributeDescription	*desc = NULL;
			Modifications 		*mod_tmp;

Howard Chu's avatar
Howard Chu committed
493
			rs->sr_err = slap_bv2ad( &old_rdn[d_cnt]->la_attr, &desc, &rs->sr_text );
494
			if ( rs->sr_err != LDAP_SUCCESS ) {
495
				Debug( LDAP_DEBUG_TRACE,
496
497
					"%s slap_modrdn2mods: %s: %s (old)\n",
					op->o_log_prefix,
498
					rs->sr_text, 
499
					old_rdn[d_cnt]->la_attr.bv_val );
500
501
				goto done;		
			}
502
503
504
505
506
507
508
509
510
511
			if ( !desc->ad_type->sat_equality ) {
				Debug( LDAP_DEBUG_TRACE,
					"%s slap_modrdn2mods: %s: %s (old)\n",
					op->o_log_prefix,
					rs->sr_text,
					old_rdn[ d_cnt ]->la_attr.bv_val );
				rs->sr_text = "naming attribute has no equality matching rule";
				rs->sr_err = LDAP_NAMING_VIOLATION;
				goto done;
			}
512
513

			/* Apply modification */
514
			mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) );
515
			mod_tmp->sml_desc = desc;
Luke Howard's avatar
Luke Howard committed
516
			BER_BVZERO( &mod_tmp->sml_type );
517
			mod_tmp->sml_numvals = 1;
518
519
			mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
			ber_dupbv( &mod_tmp->sml_values[0], &old_rdn[d_cnt]->la_value );
520
521
			mod_tmp->sml_values[1].bv_val = NULL;
			if( desc->ad_type->sat_equality->smr_normalize) {
522
				mod_tmp->sml_nvalues = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
523
				(void) (*desc->ad_type->sat_equality->smr_normalize)(
524
					SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
525
526
527
					desc->ad_type->sat_syntax,
					desc->ad_type->sat_equality,
					&mod_tmp->sml_values[0],
528
					&mod_tmp->sml_nvalues[0], NULL );
529
530
531
532
				mod_tmp->sml_nvalues[1].bv_val = NULL;
			} else {
				mod_tmp->sml_nvalues = NULL;
			}
533
			mod_tmp->sml_op = LDAP_MOD_DELETE;
534
			mod_tmp->sml_flags = 0;
535
536
			mod_tmp->sml_next = op->orr_modlist;
			op->orr_modlist = mod_tmp;
537
538
539
540
		}
	}
	
done:
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
541

542
	/* LDAP v2 supporting correct attribute handling. */
543
	if ( rs->sr_err != LDAP_SUCCESS && op->orr_modlist != NULL ) {
544
		Modifications *tmp;
545

546
547
548
		for ( ; op->orr_modlist != NULL; op->orr_modlist = tmp ) {
			tmp = op->orr_modlist->sml_next;
			ch_free( op->orr_modlist );
549
		}
550
	}
551

552
553
554
555
556
	if ( new_rdn != NULL ) {
		ldap_rdnfree_x( new_rdn, op->o_tmpmemctx );
	}
	if ( old_rdn != NULL ) {
		ldap_rdnfree_x( old_rdn, op->o_tmpmemctx );
557
558
	}

559
	return rs->sr_err;
560
561
}