xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/modrdn.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /* $OpenLDAP: pkg/ldap/servers/slapd/modrdn.c,v 1.170.2.5 2008/02/11 23:26:44 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2008 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /* Portions Copyright 1999, Juan C. Gomez, All rights reserved.
16  * This software is not subject to any license of Silicon Graphics
17  * Inc. or Purdue University.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * without restriction or fee of any kind as long as this notice
21  * is preserved.
22  */
23 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
24  * All rights reserved.
25  *
26  * Redistribution and use in source and binary forms are permitted
27  * provided that this notice is preserved and that due credit is given
28  * to the University of Michigan at Ann Arbor. The name of the University
29  * may not be used to endorse or promote products derived from this
30  * software without specific prior written permission. This software
31  * is provided ``as is'' without express or implied warranty.
32  */
33 
34 #include "portable.h"
35 
36 #include <stdio.h>
37 
38 #include <ac/socket.h>
39 #include <ac/string.h>
40 
41 #include "slap.h"
42 
43 int
44 do_modrdn(
45     Operation	*op,
46     SlapReply	*rs
47 )
48 {
49 	struct berval	dn = BER_BVNULL;
50 	struct berval	newrdn = BER_BVNULL;
51 	struct berval	newSuperior = BER_BVNULL;
52 	ber_int_t	deloldrdn;
53 
54 	struct berval pnewSuperior = BER_BVNULL;
55 
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, 0, 0 );
62 	/*
63 	 * Parse the modrdn request.  It looks like this:
64 	 *
65 	 *	ModifyRDNRequest := SEQUENCE {
66 	 *		entry	DistinguishedName,
67 	 *		newrdn	RelativeDistinguishedName
68 	 *		deleteoldrdn	BOOLEAN,
69 	 *		newSuperior	[0] LDAPDN OPTIONAL (v3 Only!)
70 	 *	}
71 	 */
72 
73 	if ( ber_scanf( op->o_ber, "{mmb", &dn, &newrdn, &deloldrdn )
74 	    == LBER_ERROR )
75 	{
76 		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf failed\n",
77 			op->o_log_prefix, 0, 0 );
78 		send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
79 		return SLAPD_DISCONNECT;
80 	}
81 
82 	/* Check for newSuperior parameter, if present scan it */
83 
84 	if ( ber_peek_tag( op->o_ber, &length ) == LDAP_TAG_NEWSUPERIOR ) {
85 		if ( op->o_protocol < LDAP_VERSION3 ) {
86 			/* Connection record indicates v2 but field
87 			 * newSuperior is present: report error.
88 			 */
89 			Debug( LDAP_DEBUG_ANY,
90 				"%s do_modrdn: newSuperior requires LDAPv3\n",
91 				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;
96 			goto cleanup;
97 		}
98 
99 		if ( ber_scanf( op->o_ber, "m", &newSuperior )
100 		     == LBER_ERROR ) {
101 
102 			Debug( LDAP_DEBUG_ANY, "%s do_modrdn: ber_scanf(\"m\") failed\n",
103 				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;
108 			goto cleanup;
109 		}
110 		op->orr_newSup = &pnewSuperior;
111 		op->orr_nnewSup = &nnewSuperior;
112 	}
113 
114 	Debug( LDAP_DEBUG_ARGS,
115 	    "do_modrdn: dn (%s) newrdn (%s) newsuperior (%s)\n",
116 		dn.bv_val, newrdn.bv_val,
117 		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, 0, 0 );
122 		send_ldap_discon( op, rs,
123 			LDAP_PROTOCOL_ERROR, "decoding error" );
124 		rs->sr_err = SLAPD_DISCONNECT;
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, 0, 0 );
131 		/* get_ctrls has sent results.	Now clean up. */
132 		goto cleanup;
133 	}
134 
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, 0 );
139 		send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
140 		goto cleanup;
141 	}
142 
143 	/* FIXME: should have/use rdnPretty / rdnNormalize routines */
144 
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, 0 );
149 		send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid new RDN" );
150 		goto cleanup;
151 	}
152 
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, 0 );
156 		send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid new RDN" );
157 		goto cleanup;
158 	}
159 
160 	if( op->orr_newSup ) {
161 		rs->sr_err = dnPrettyNormal( NULL, &newSuperior, &pnewSuperior,
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, 0 );
167 			send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid newSuperior" );
168 			goto cleanup;
169 		}
170 	}
171 
172 	Statslog( LDAP_DEBUG_STATS, "%s MODRDN dn=\"%s\"\n",
173 	    op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 );
174 
175 	op->orr_deleteoldrdn = deloldrdn;
176 	op->orr_modlist = NULL;
177 
178 	/* prepare modlist of modifications from old/new RDN */
179 	rs->sr_err = slap_modrdn2mods( op, rs );
180 	if ( rs->sr_err != LDAP_SUCCESS ) {
181 		send_ldap_result( op, rs );
182 		goto cleanup;
183 	}
184 
185 	op->o_bd = frontendDB;
186 	rs->sr_err = frontendDB->be_modrdn( op, rs );
187 
188 #ifdef LDAP_X_TXN
189 	if( rs->sr_err == LDAP_X_TXN_SPECIFY_OKAY ) {
190 		/* skip cleanup */
191 	}
192 #endif
193 
194 cleanup:
195 	op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
196 	op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
197 
198 	op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );
199 	op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );
200 
201 	if ( op->orr_modlist != NULL )
202 		slap_mods_free( op->orr_modlist, 1 );
203 
204 	if ( !BER_BVISNULL( &pnewSuperior ) ) {
205 		op->o_tmpfree( pnewSuperior.bv_val, op->o_tmpmemctx );
206 	}
207 	if ( !BER_BVISNULL( &nnewSuperior ) ) {
208 		op->o_tmpfree( nnewSuperior.bv_val, op->o_tmpmemctx );
209 	}
210 
211 	return rs->sr_err;
212 }
213 
214 int
215 fe_op_modrdn( Operation *op, SlapReply *rs )
216 {
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 		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: root dse!\n",
223 			op->o_log_prefix, 0, 0 );
224 		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
225 			"cannot rename the root DSE" );
226 		goto cleanup;
227 
228 	} else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) {
229 		Debug( LDAP_DEBUG_ANY, "%s do_modrdn: subschema subentry: %s (%ld)\n",
230 			op->o_log_prefix, frontendDB->be_schemandn.bv_val, (long)frontendDB->be_schemandn.bv_len );
231 
232 		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
233 			"cannot rename subschema subentry" );
234 		goto cleanup;
235 	}
236 
237 	if( op->orr_nnewSup ) {
238 		dest_pndn = *op->orr_nnewSup;
239 	} else {
240 		dnParent( &op->o_req_ndn, &dest_pndn );
241 	}
242 	build_new_dn( &dest_ndn, &dest_pndn, &op->orr_nnewrdn, op->o_tmpmemctx );
243 
244 	diff = (ber_slen_t) dest_ndn.bv_len - (ber_slen_t) op->o_req_ndn.bv_len;
245 	if ( diff > 0 ? dnIsSuffix( &dest_ndn, &op->o_req_ndn )
246 		: diff < 0 && dnIsSuffix( &op->o_req_ndn, &dest_ndn ) )
247 	{
248 		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
249 			diff > 0 ? "cannot place an entry below itself"
250 			: "cannot place an entry above itself" );
251 		goto cleanup;
252 	}
253 
254 	/*
255 	 * We could be serving multiple database backends.  Select the
256 	 * appropriate one, or send a referral to our "referral server"
257 	 * if we don't hold it.
258 	 */
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 
266 		if ( rs->sr_ref != NULL ) {
267 			rs->sr_err = LDAP_REFERRAL;
268 			send_ldap_result( op, rs );
269 
270 			if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref );
271 		} else {
272 			send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
273 				"no global superior knowledge" );
274 		}
275 		goto cleanup;
276 	}
277 
278 	/* If we've got a glued backend, check the real backend */
279 	op_be = op->o_bd;
280 	if ( SLAP_GLUE_INSTANCE( op->o_bd )) {
281 		op->o_bd = select_backend( &op->o_req_ndn, 0 );
282 	}
283 
284 	/* check restrictions */
285 	if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
286 		send_ldap_result( op, rs );
287 		goto cleanup;
288 	}
289 
290 	/* check for referrals */
291 	if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
292 		goto cleanup;
293 	}
294 
295 	/* check that destination DN is in the same backend as source DN */
296 	if ( select_backend( &dest_ndn, 0 ) != op->o_bd ) {
297 			send_ldap_error( op, rs, LDAP_AFFECTS_MULTIPLE_DSAS,
298 				"cannot rename between DSAs" );
299 			goto cleanup;
300 	}
301 
302 	/*
303 	 * do the modrdn if 1 && (2 || 3)
304 	 * 1) there is a modrdn function implemented in this backend;
305 	 * 2) this backend is master for what it holds;
306 	 * 3) it's a replica and the dn supplied is the update_ndn.
307 	 */
308 	if ( op->o_bd->be_modrdn ) {
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 			op->o_bd->be_modrdn( op, rs );
315 
316 			if ( op->o_bd->be_delete ) {
317 				struct berval	org_req_dn = BER_BVNULL;
318 				struct berval	org_req_ndn = BER_BVNULL;
319 				struct berval	org_dn = BER_BVNULL;
320 				struct berval	org_ndn = BER_BVNULL;
321 				int		org_managedsait;
322 
323 				org_req_dn = op->o_req_dn;
324 				org_req_ndn = op->o_req_ndn;
325 				org_dn = op->o_dn;
326 				org_ndn = op->o_ndn;
327 				org_managedsait = get_manageDSAit( op );
328 				op->o_dn = op->o_bd->be_rootdn;
329 				op->o_ndn = op->o_bd->be_rootndn;
330 				op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
331 
332 				while ( rs->sr_err == LDAP_SUCCESS &&
333 						op->o_delete_glue_parent ) {
334 					op->o_delete_glue_parent = 0;
335 					if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) {
336 						slap_callback cb = { NULL };
337 						cb.sc_response = slap_null_cb;
338 						dnParent( &op->o_req_ndn, &pdn );
339 						op->o_req_dn = pdn;
340 						op->o_req_ndn = pdn;
341 						op->o_callback = &cb;
342 						op->o_bd->be_delete( op, rs );
343 					} else {
344 						break;
345 					}
346 				}
347 				op->o_managedsait = org_managedsait;
348 				op->o_dn = org_dn;
349 				op->o_ndn = org_ndn;
350 				op->o_req_dn = org_req_dn;
351 				op->o_req_ndn = org_req_ndn;
352 				op->o_delete_glue_parent = 0;
353 			}
354 
355 		} else {
356 			BerVarray defref = op->o_bd->be_update_refs
357 				? op->o_bd->be_update_refs : default_referral;
358 
359 			if ( defref != NULL ) {
360 				rs->sr_ref = referral_rewrite( defref,
361 					NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
362 				if (!rs->sr_ref) rs->sr_ref = defref;
363 
364 				rs->sr_err = LDAP_REFERRAL;
365 				send_ldap_result( op, rs );
366 
367 				if (rs->sr_ref != defref) ber_bvarray_free( rs->sr_ref );
368 			} else {
369 				send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
370 					"shadow context; no update referral" );
371 			}
372 		}
373 	} else {
374 		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
375 			"operation not supported within namingContext" );
376 	}
377 
378 cleanup:;
379 	if ( dest_ndn.bv_val != NULL )
380 		ber_memfree_x( dest_ndn.bv_val, op->o_tmpmemctx );
381 	op->o_bd = bd;
382 	return rs->sr_err;
383 }
384 
385 int
386 slap_modrdn2mods(
387 	Operation	*op,
388 	SlapReply	*rs )
389 {
390 	int		a_cnt, d_cnt;
391 	LDAPRDN		old_rdn = NULL;
392 	LDAPRDN		new_rdn = NULL;
393 
394 	assert( !BER_BVISEMPTY( &op->oq_modrdn.rs_newrdn ) );
395 	assert( !op->orr_deleteoldrdn || !BER_BVISEMPTY( &op->o_req_dn ) );
396 
397 	if ( ldap_bv2rdn_x( &op->oq_modrdn.rs_newrdn, &new_rdn,
398 		(char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) {
399 		Debug( LDAP_DEBUG_TRACE,
400 			"%s slap_modrdn2mods: can't figure out "
401 			"type(s)/value(s) of newrdn\n",
402 			op->o_log_prefix, 0, 0 );
403 		rs->sr_err = LDAP_INVALID_DN_SYNTAX;
404 		rs->sr_text = "unknown type(s) used in RDN";
405 		goto done;
406 	}
407 
408 	if ( op->oq_modrdn.rs_deleteoldrdn ) {
409 		if ( ldap_bv2rdn_x( &op->o_req_dn, &old_rdn,
410 			(char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) {
411 			Debug( LDAP_DEBUG_TRACE,
412 				"%s slap_modrdn2mods: can't figure out "
413 				"type(s)/value(s) of oldrdn\n",
414 				op->o_log_prefix, 0, 0 );
415 			rs->sr_err = LDAP_OTHER;
416 			rs->sr_text = "cannot parse RDN from old DN";
417 			goto done;
418 		}
419 	}
420 	rs->sr_text = NULL;
421 
422 	/* Add new attribute values to the entry */
423 	for ( a_cnt = 0; new_rdn[a_cnt]; a_cnt++ ) {
424 		AttributeDescription	*desc = NULL;
425 		Modifications 		*mod_tmp;
426 
427 		rs->sr_err = slap_bv2ad( &new_rdn[a_cnt]->la_attr, &desc, &rs->sr_text );
428 
429 		if ( rs->sr_err != LDAP_SUCCESS ) {
430 			Debug( LDAP_DEBUG_TRACE,
431 				"%s slap_modrdn2mods: %s: %s (new)\n",
432 				op->o_log_prefix,
433 				rs->sr_text,
434 				new_rdn[ a_cnt ]->la_attr.bv_val );
435 			goto done;
436 		}
437 
438 		/* Apply modification */
439 		mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) );
440 		mod_tmp->sml_desc = desc;
441 		BER_BVZERO( &mod_tmp->sml_type );
442 		mod_tmp->sml_numvals = 1;
443 		mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
444 		ber_dupbv( &mod_tmp->sml_values[0], &new_rdn[a_cnt]->la_value );
445 		mod_tmp->sml_values[1].bv_val = NULL;
446 		if( desc->ad_type->sat_equality->smr_normalize) {
447 			mod_tmp->sml_nvalues = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
448 			(void) (*desc->ad_type->sat_equality->smr_normalize)(
449 				SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
450 				desc->ad_type->sat_syntax,
451 				desc->ad_type->sat_equality,
452 				&mod_tmp->sml_values[0],
453 				&mod_tmp->sml_nvalues[0], NULL );
454 			mod_tmp->sml_nvalues[1].bv_val = NULL;
455 		} else {
456 			mod_tmp->sml_nvalues = NULL;
457 		}
458 		mod_tmp->sml_op = SLAP_MOD_SOFTADD;
459 		mod_tmp->sml_flags = 0;
460 		mod_tmp->sml_next = op->orr_modlist;
461 		op->orr_modlist = mod_tmp;
462 	}
463 
464 	/* Remove old rdn value if required */
465 	if ( op->orr_deleteoldrdn ) {
466 		for ( d_cnt = 0; old_rdn[d_cnt]; d_cnt++ ) {
467 			AttributeDescription	*desc = NULL;
468 			Modifications 		*mod_tmp;
469 
470 			rs->sr_err = slap_bv2ad( &old_rdn[d_cnt]->la_attr, &desc, &rs->sr_text );
471 			if ( rs->sr_err != LDAP_SUCCESS ) {
472 				Debug( LDAP_DEBUG_TRACE,
473 					"%s slap_modrdn2mods: %s: %s (old)\n",
474 					op->o_log_prefix,
475 					rs->sr_text,
476 					old_rdn[d_cnt]->la_attr.bv_val );
477 				goto done;
478 			}
479 
480 			/* Apply modification */
481 			mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) );
482 			mod_tmp->sml_desc = desc;
483 			BER_BVZERO( &mod_tmp->sml_type );
484 			mod_tmp->sml_numvals = 1;
485 			mod_tmp->sml_values = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
486 			ber_dupbv( &mod_tmp->sml_values[0], &old_rdn[d_cnt]->la_value );
487 			mod_tmp->sml_values[1].bv_val = NULL;
488 			if( desc->ad_type->sat_equality->smr_normalize) {
489 				mod_tmp->sml_nvalues = ( BerVarray )ch_malloc( 2 * sizeof( struct berval ) );
490 				(void) (*desc->ad_type->sat_equality->smr_normalize)(
491 					SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
492 					desc->ad_type->sat_syntax,
493 					desc->ad_type->sat_equality,
494 					&mod_tmp->sml_values[0],
495 					&mod_tmp->sml_nvalues[0], NULL );
496 				mod_tmp->sml_nvalues[1].bv_val = NULL;
497 			} else {
498 				mod_tmp->sml_nvalues = NULL;
499 			}
500 			mod_tmp->sml_op = LDAP_MOD_DELETE;
501 			mod_tmp->sml_flags = 0;
502 			mod_tmp->sml_next = op->orr_modlist;
503 			op->orr_modlist = mod_tmp;
504 		}
505 	}
506 
507 done:
508 
509 	/* LDAP v2 supporting correct attribute handling. */
510 	if ( rs->sr_err != LDAP_SUCCESS && op->orr_modlist != NULL ) {
511 		Modifications *tmp;
512 
513 		for ( ; op->orr_modlist != NULL; op->orr_modlist = tmp ) {
514 			tmp = op->orr_modlist->sml_next;
515 			ch_free( op->orr_modlist );
516 		}
517 	}
518 
519 	if ( new_rdn != NULL ) {
520 		ldap_rdnfree_x( new_rdn, op->o_tmpmemctx );
521 	}
522 	if ( old_rdn != NULL ) {
523 		ldap_rdnfree_x( old_rdn, op->o_tmpmemctx );
524 	}
525 
526 	return rs->sr_err;
527 }
528 
529