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