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/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
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.
19 * Redistribution and use in source and binary forms are permitted
20 * without restriction or fee of any kind as long as this notice
23 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
24 * All rights reserved.
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.
38 #include <ac/socket.h>
39 #include <ac/string.h>
49 struct berval dn
= BER_BVNULL
;
50 struct berval newrdn
= BER_BVNULL
;
51 struct berval newSuperior
= BER_BVNULL
;
54 struct berval pnewSuperior
= BER_BVNULL
;
56 struct berval nnewSuperior
= BER_BVNULL
;
60 Debug( LDAP_DEBUG_TRACE
, "%s do_modrdn\n",
61 op
->o_log_prefix
, 0, 0 );
63 * Parse the modrdn request. It looks like this:
65 * ModifyRDNRequest := SEQUENCE {
66 * entry DistinguishedName,
67 * newrdn RelativeDistinguishedName
68 * deleteoldrdn BOOLEAN,
69 * newSuperior [0] LDAPDN OPTIONAL (v3 Only!)
73 if ( ber_scanf( op
->o_ber
, "{mmb", &dn
, &newrdn
, &deloldrdn
)
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
;
82 /* Check for newSuperior parameter, if present scan it */
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.
89 Debug( LDAP_DEBUG_ANY
,
90 "%s do_modrdn: newSuperior requires LDAPv3\n",
91 op
->o_log_prefix
, 0, 0 );
93 send_ldap_discon( op
, rs
,
94 LDAP_PROTOCOL_ERROR
, "newSuperior requires LDAPv3" );
95 rs
->sr_err
= SLAPD_DISCONNECT
;
99 if ( ber_scanf( op
->o_ber
, "m", &newSuperior
)
102 Debug( LDAP_DEBUG_ANY
, "%s do_modrdn: ber_scanf(\"m\") failed\n",
103 op
->o_log_prefix
, 0, 0 );
105 send_ldap_discon( op
, rs
,
106 LDAP_PROTOCOL_ERROR
, "decoding error" );
107 rs
->sr_err
= SLAPD_DISCONNECT
;
110 op
->orr_newSup
= &pnewSuperior
;
111 op
->orr_nnewSup
= &nnewSuperior
;
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
: "" );
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
;
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. */
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" );
143 /* FIXME: should have/use rdnPretty / rdnNormalize routines */
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" );
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" );
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" );
172 Statslog( LDAP_DEBUG_STATS
, "%s MODRDN dn=\"%s\"\n",
173 op
->o_log_prefix
, op
->o_req_dn
.bv_val
, 0, 0, 0 );
175 op
->orr_deleteoldrdn
= deloldrdn
;
176 op
->orr_modlist
= NULL
;
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
);
185 op
->o_bd
= frontendDB
;
186 rs
->sr_err
= frontendDB
->be_modrdn( op
, rs
);
189 if( rs
->sr_err
== LDAP_X_TXN_SPECIFY_OKAY
) {
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
);
198 op
->o_tmpfree( op
->orr_newrdn
.bv_val
, op
->o_tmpmemctx
);
199 op
->o_tmpfree( op
->orr_nnewrdn
.bv_val
, op
->o_tmpmemctx
);
201 if ( op
->orr_modlist
!= NULL
)
202 slap_mods_free( op
->orr_modlist
, 1 );
204 if ( !BER_BVISNULL( &pnewSuperior
) ) {
205 op
->o_tmpfree( pnewSuperior
.bv_val
, op
->o_tmpmemctx
);
207 if ( !BER_BVISNULL( &nnewSuperior
) ) {
208 op
->o_tmpfree( nnewSuperior
.bv_val
, op
->o_tmpmemctx
);
215 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
;
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" );
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
);
232 send_ldap_error( op
, rs
, LDAP_UNWILLING_TO_PERFORM
,
233 "cannot rename subschema subentry" );
237 if( op
->orr_nnewSup
) {
238 dest_pndn
= *op
->orr_nnewSup
;
240 dnParent( &op
->o_req_ndn
, &dest_pndn
);
242 build_new_dn( &dest_ndn
, &dest_pndn
, &op
->orr_nnewrdn
, op
->o_tmpmemctx
);
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
) )
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" );
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.
259 op
->o_bd
= select_backend( &op
->o_req_ndn
, 1 );
260 if ( op
->o_bd
== NULL
) {
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
;
266 if ( rs
->sr_ref
!= NULL
) {
267 rs
->sr_err
= LDAP_REFERRAL
;
268 send_ldap_result( op
, rs
);
270 if (rs
->sr_ref
!= default_referral
) ber_bvarray_free( rs
->sr_ref
);
272 send_ldap_error( op
, rs
, LDAP_UNWILLING_TO_PERFORM
,
273 "no global superior knowledge" );
278 /* If we've got a glued backend, check the real backend */
280 if ( SLAP_GLUE_INSTANCE( op
->o_bd
)) {
281 op
->o_bd
= select_backend( &op
->o_req_ndn
, 0 );
284 /* check restrictions */
285 if( backend_check_restrictions( op
, rs
, NULL
) != LDAP_SUCCESS
) {
286 send_ldap_result( op
, rs
);
290 /* check for referrals */
291 if ( backend_check_referrals( op
, rs
) != LDAP_SUCCESS
) {
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" );
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.
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
)
314 op
->o_bd
->be_modrdn( op
, rs
);
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
;
323 org_req_dn
= op
->o_req_dn
;
324 org_req_ndn
= op
->o_req_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
;
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
);
341 op
->o_callback
= &cb
;
342 op
->o_bd
->be_delete( op
, rs
);
347 op
->o_managedsait
= org_managedsait
;
350 op
->o_req_dn
= org_req_dn
;
351 op
->o_req_ndn
= org_req_ndn
;
352 op
->o_delete_glue_parent
= 0;
356 BerVarray defref
= op
->o_bd
->be_update_refs
357 ? op
->o_bd
->be_update_refs
: default_referral
;
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
;
364 rs
->sr_err
= LDAP_REFERRAL
;
365 send_ldap_result( op
, rs
);
367 if (rs
->sr_ref
!= defref
) ber_bvarray_free( rs
->sr_ref
);
369 send_ldap_error( op
, rs
, LDAP_UNWILLING_TO_PERFORM
,
370 "shadow context; no update referral" );
374 send_ldap_error( op
, rs
, LDAP_UNWILLING_TO_PERFORM
,
375 "operation not supported within namingContext" );
379 if ( dest_ndn
.bv_val
!= NULL
)
380 ber_memfree_x( dest_ndn
.bv_val
, op
->o_tmpmemctx
);
391 LDAPRDN old_rdn
= NULL
;
392 LDAPRDN new_rdn
= NULL
;
394 assert( !BER_BVISEMPTY( &op
->oq_modrdn
.rs_newrdn
) );
395 assert( !op
->orr_deleteoldrdn
|| !BER_BVISEMPTY( &op
->o_req_dn
) );
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";
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";
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
;
427 rs
->sr_err
= slap_bv2ad( &new_rdn
[a_cnt
]->la_attr
, &desc
, &rs
->sr_text
);
429 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
430 Debug( LDAP_DEBUG_TRACE
,
431 "%s slap_modrdn2mods: %s: %s (new)\n",
434 new_rdn
[ a_cnt
]->la_attr
.bv_val
);
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
;
456 mod_tmp
->sml_nvalues
= NULL
;
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
;
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
;
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",
476 old_rdn
[d_cnt
]->la_attr
.bv_val
);
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
;
498 mod_tmp
->sml_nvalues
= NULL
;
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
;
509 /* LDAP v2 supporting correct attribute handling. */
510 if ( rs
->sr_err
!= LDAP_SUCCESS
&& op
->orr_modlist
!= NULL
) {
513 for ( ; op
->orr_modlist
!= NULL
; op
->orr_modlist
= tmp
) {
514 tmp
= op
->orr_modlist
->sml_next
;
515 ch_free( op
->orr_modlist
);
519 if ( new_rdn
!= NULL
) {
520 ldap_rdnfree_x( new_rdn
, op
->o_tmpmemctx
);
522 if ( old_rdn
!= NULL
) {
523 ldap_rdnfree_x( old_rdn
, op
->o_tmpmemctx
);