1 1.1 christos /* $NetBSD: modrdn.c,v 1.2 2025/09/05 21:16:32 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* OpenLDAP WiredTiger backend */ 4 1.1 christos /* $OpenLDAP$ */ 5 1.1 christos /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 1.1 christos * 7 1.1 christos * Copyright 2002-2024 The OpenLDAP Foundation. 8 1.1 christos * All rights reserved. 9 1.1 christos * 10 1.1 christos * Redistribution and use in source and binary forms, with or without 11 1.1 christos * modification, are permitted only as authorized by the OpenLDAP 12 1.1 christos * Public License. 13 1.1 christos * 14 1.1 christos * A copy of this license is available in the file LICENSE in the 15 1.1 christos * top-level directory of the distribution or, alternatively, at 16 1.1 christos * <http://www.OpenLDAP.org/license.html>. 17 1.1 christos */ 18 1.1 christos /* ACKNOWLEDGEMENTS: 19 1.1 christos * This work was developed by HAMANO Tsukasa <hamano (at) osstech.co.jp> 20 1.1 christos * based on back-bdb for inclusion in OpenLDAP Software. 21 1.1 christos * WiredTiger is a product of MongoDB Inc. 22 1.1 christos */ 23 1.1 christos 24 1.1 christos #include <sys/cdefs.h> 25 1.1 christos __RCSID("$NetBSD: modrdn.c,v 1.2 2025/09/05 21:16:32 christos Exp $"); 26 1.1 christos 27 1.1 christos #include "portable.h" 28 1.1 christos 29 1.1 christos #include <stdio.h> 30 1.1 christos #include "back-wt.h" 31 1.1 christos #include "slap-config.h" 32 1.1 christos 33 1.1 christos int 34 1.1 christos wt_modrdn( Operation *op, SlapReply *rs ) 35 1.1 christos { 36 1.1 christos struct wt_info *wi = (struct wt_info *) op->o_bd->be_private; 37 1.1 christos AttributeDescription *children = slap_schema.si_ad_children; 38 1.1 christos AttributeDescription *entry = slap_schema.si_ad_entry; 39 1.1 christos wt_ctx *wc = NULL; 40 1.1 christos Entry *e = NULL; 41 1.1 christos Entry *p = NULL; 42 1.1 christos Entry *ne = NULL; 43 1.1 christos Entry dummy = {0}; 44 1.1 christos 45 1.1 christos struct berval p_dn, p_ndn; 46 1.1 christos struct berval new_dn = {0, NULL}, new_ndn = {0, NULL}; 47 1.1 christos 48 1.1 christos Entry *np = NULL; /* newSuperior Entry */ 49 1.1 christos struct berval *np_dn = NULL; /* newSuperior dn */ 50 1.1 christos struct berval *np_ndn = NULL; /* newSuperior ndn */ 51 1.1 christos struct berval *new_parent_dn = NULL; /* np_dn, p_dn, or NULL */ 52 1.1 christos 53 1.1 christos int manageDSAit = get_manageDSAit( op ); 54 1.1 christos char textbuf[SLAP_TEXT_BUFLEN]; 55 1.1 christos size_t textlen = sizeof textbuf; 56 1.1 christos LDAPControl **preread_ctrl = NULL; 57 1.1 christos LDAPControl **postread_ctrl = NULL; 58 1.1 christos LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; 59 1.1 christos int num_ctrls = 0; 60 1.1 christos 61 1.1 christos int rc; 62 1.1 christos 63 1.1 christos int parent_is_glue = 0; 64 1.1 christos int parent_is_leaf = 0; 65 1.1 christos 66 1.1 christos Debug( LDAP_DEBUG_TRACE, "==> wt_modrdn(%s -> newrdn=%s - newsup=%s)\n", 67 1.1 christos op->o_req_dn.bv_val, 68 1.1 christos op->oq_modrdn.rs_newrdn.bv_val, 69 1.1 christos op->oq_modrdn.rs_newSup?op->oq_modrdn.rs_newSup->bv_val:"NULL" ); 70 1.1 christos 71 1.1 christos ctrls[num_ctrls] = NULL; 72 1.1 christos 73 1.1 christos slap_mods_opattrs( op, &op->orr_modlist, 1 ); 74 1.1 christos 75 1.1 christos wc = wt_ctx_get(op, wi); 76 1.1 christos if( !wc ){ 77 1.1 christos Debug( LDAP_DEBUG_ANY, "wt_modrdn: wt_ctx_get failed\n"); 78 1.1 christos rs->sr_err = LDAP_OTHER; 79 1.1 christos rs->sr_text = "internal error"; 80 1.1 christos send_ldap_result( op, rs ); 81 1.1 christos return rs->sr_err; 82 1.1 christos } 83 1.1 christos 84 1.1 christos /* get parent entry */ 85 1.1 christos if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) { 86 1.1 christos rs->sr_err = LDAP_NAMING_VIOLATION; 87 1.1 christos rs->sr_text = "cannot rename suffix entry"; 88 1.1 christos goto return_results; 89 1.1 christos } else { 90 1.1 christos dnParent( &op->o_req_ndn, &p_ndn ); 91 1.1 christos } 92 1.1 christos 93 1.1 christos rc = wt_dn2entry(op->o_bd, wc, &p_ndn, &p); 94 1.1 christos switch( rc ) { 95 1.1 christos case 0: 96 1.1 christos break; 97 1.1 christos case WT_NOTFOUND: 98 1.1 christos Debug( LDAP_DEBUG_ARGS, 99 1.1 christos "<== wt_modrdn: parent does not exist %s\n", p_ndn.bv_val); 100 1.1 christos rs->sr_err = LDAP_NO_SUCH_OBJECT; 101 1.1 christos goto return_results; 102 1.1 christos default: 103 1.1 christos Debug( LDAP_DEBUG_ANY, 104 1.1 christos "<== wt_modrdn: wt_dn2entry failed (%d)\n", rc ); 105 1.1 christos rs->sr_err = LDAP_OTHER; 106 1.1 christos rs->sr_text = "internal error"; 107 1.1 christos goto return_results; 108 1.1 christos } 109 1.1 christos 110 1.1 christos /* check parent for "children" acl */ 111 1.1 christos rc = access_allowed( op, p, children, NULL, 112 1.1 christos op->oq_modrdn.rs_newSup == NULL ? 113 1.1 christos ACL_WRITE : ACL_WDEL, NULL ); 114 1.1 christos 115 1.1 christos if ( !rc ) { 116 1.1 christos rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 117 1.1 christos Debug( LDAP_DEBUG_TRACE, 118 1.1 christos "wt_modrdn: no access to parent\n"); 119 1.1 christos rs->sr_text = "no write access to old parent's children"; 120 1.1 christos goto return_results; 121 1.1 christos } 122 1.1 christos 123 1.1 christos Debug( LDAP_DEBUG_TRACE, 124 1.1 christos "wt_modrdn: wr to children of entry %s OK\n", p_ndn.bv_val ); 125 1.1 christos 126 1.1 christos if ( p_ndn.bv_val == slap_empty_bv.bv_val ) { 127 1.1 christos p_dn = slap_empty_bv; 128 1.1 christos } else { 129 1.1 christos dnParent( &op->o_req_dn, &p_dn ); 130 1.1 christos } 131 1.1 christos 132 1.1 christos Debug( LDAP_DEBUG_TRACE, 133 1.1 christos "wt_modrdn: parent dn=%s\n", p_dn.bv_val ); 134 1.1 christos 135 1.1 christos /* get entry */ 136 1.1 christos rc = wt_dn2entry(op->o_bd, wc, &op->o_req_ndn, &e); 137 1.1 christos switch( rc ) { 138 1.1 christos case 0: 139 1.1 christos break; 140 1.1 christos case WT_NOTFOUND: 141 1.1 christos break; 142 1.1 christos default: 143 1.1 christos Debug( LDAP_DEBUG_ANY, 144 1.1 christos "<== wt_modrdn: wt_dn2entry failed (%d)\n", rc ); 145 1.1 christos rs->sr_err = LDAP_OTHER; 146 1.1 christos rs->sr_text = "internal error"; 147 1.1 christos goto return_results; 148 1.1 christos } 149 1.1 christos 150 1.1 christos if ( rc == WT_NOTFOUND || 151 1.1 christos ( !manageDSAit && e && is_entry_glue( e ) )) { 152 1.1 christos 153 1.1 christos if ( !e ) { 154 1.1 christos Debug( LDAP_DEBUG_ARGS, 155 1.1 christos "<== wt_modrdn: no such object %s\n", op->o_req_dn.bv_val); 156 1.1 christos rc = wt_dn2aentry(op->o_bd, wc, &op->o_req_ndn, &e); 157 1.1 christos switch( rc ) { 158 1.1 christos case 0: 159 1.1 christos break; 160 1.1 christos case WT_NOTFOUND: 161 1.1 christos rs->sr_err = LDAP_NO_SUCH_OBJECT; 162 1.1 christos goto return_results; 163 1.1 christos default: 164 1.1 christos Debug( LDAP_DEBUG_ANY, "wt_modrdn: wt_dn2aentry failed (%d)\n", rc ); 165 1.1 christos rs->sr_err = LDAP_OTHER; 166 1.1 christos rs->sr_text = "internal error"; 167 1.1 christos goto return_results; 168 1.1 christos } 169 1.1 christos } 170 1.1 christos 171 1.1 christos rs->sr_matched = ch_strdup( e->e_dn ); 172 1.1 christos 173 1.1 christos if ( is_entry_referral( e ) ) { 174 1.1 christos BerVarray ref = get_entry_referrals( op, e ); 175 1.1 christos rs->sr_ref = referral_rewrite( ref, &e->e_name, 176 1.1 christos &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 177 1.1 christos ber_bvarray_free( ref ); 178 1.1 christos } else { 179 1.1 christos rs->sr_ref = NULL; 180 1.1 christos } 181 1.1 christos rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED; 182 1.1 christos rs->sr_err = LDAP_REFERRAL; 183 1.1 christos send_ldap_result( op, rs ); 184 1.1 christos goto done; 185 1.1 christos } 186 1.1 christos 187 1.1 christos if ( get_assert( op ) && 188 1.1 christos ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE )) 189 1.1 christos { 190 1.1 christos rs->sr_err = LDAP_ASSERTION_FAILED; 191 1.1 christos goto return_results; 192 1.1 christos } 193 1.1 christos 194 1.1 christos /* check write on old entry */ 195 1.1 christos rc = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL ); 196 1.1 christos if ( !rc ) { 197 1.1 christos Debug( LDAP_DEBUG_TRACE, "wt_modrdn: no access to entry\n"); 198 1.1 christos rs->sr_text = "no write access to old entry"; 199 1.1 christos rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 200 1.1 christos goto return_results; 201 1.1 christos } 202 1.1 christos 203 1.1 christos /* Can't do it if we have kids */ 204 1.1 christos rc = wt_dn2id_has_children( op, wc, e->e_id ); 205 1.1 christos if( rc != WT_NOTFOUND ) { 206 1.1 christos switch( rc ) { 207 1.1 christos case 0: 208 1.1 christos Debug(LDAP_DEBUG_ARGS, "<== wt_modrdn: non-leaf %s\n", op->o_req_dn.bv_val); 209 1.1 christos rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; 210 1.1 christos rs->sr_text = "subtree rename not supported"; 211 1.1 christos break; 212 1.1 christos default: 213 1.1 christos Debug(LDAP_DEBUG_ARGS, 214 1.1 christos "<== wt_modrdn: has_children failed: %s (%d)\n", 215 1.1 christos wiredtiger_strerror(rc), rc ); 216 1.1 christos rs->sr_err = LDAP_OTHER; 217 1.1 christos rs->sr_text = "internal error"; 218 1.1 christos } 219 1.1 christos goto return_results; 220 1.1 christos } 221 1.1 christos 222 1.1 christos if (!manageDSAit && is_entry_referral( e ) ) { 223 1.1 christos /* parent is a referral, don't allow add */ 224 1.1 christos rs->sr_ref = get_entry_referrals( op, e ); 225 1.1 christos 226 1.1 christos Debug( LDAP_DEBUG_TRACE, 227 1.1 christos "wt_modrdn: entry %s is referral\n", e->e_dn ); 228 1.1 christos 229 1.1 christos rs->sr_err = LDAP_REFERRAL, 230 1.1 christos rs->sr_matched = e->e_name.bv_val; 231 1.1 christos send_ldap_result( op, rs ); 232 1.1 christos 233 1.1 christos ber_bvarray_free( rs->sr_ref ); 234 1.1 christos rs->sr_ref = NULL; 235 1.1 christos rs->sr_matched = NULL; 236 1.1 christos goto done; 237 1.1 christos } 238 1.1 christos 239 1.1 christos new_parent_dn = &p_dn; /* New Parent unless newSuperior given */ 240 1.1 christos if ( op->oq_modrdn.rs_newSup != NULL ) { 241 1.1 christos Debug( LDAP_DEBUG_TRACE, 242 1.1 christos "wt_modrdn: new parent \"%s\" requested...\n", 243 1.1 christos op->oq_modrdn.rs_newSup->bv_val ); 244 1.1 christos 245 1.1 christos /* newSuperior == oldParent? */ 246 1.1 christos if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) { 247 1.1 christos Debug( LDAP_DEBUG_TRACE, 248 1.1 christos "wt_modrdn: new parent \"%s\" same as the old parent \"%s\"\n", 249 1.1 christos op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val ); 250 1.1 christos op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */ 251 1.1 christos } 252 1.1 christos } 253 1.1 christos 254 1.1 christos if ( op->oq_modrdn.rs_newSup != NULL ) { 255 1.1 christos if ( op->oq_modrdn.rs_newSup->bv_len ) { 256 1.1 christos np_dn = op->oq_modrdn.rs_newSup; 257 1.1 christos np_ndn = op->oq_modrdn.rs_nnewSup; 258 1.1 christos 259 1.1 christos /* newSuperior == oldParent? - checked above */ 260 1.1 christos /* newSuperior == entry being moved?, if so ==> ERROR */ 261 1.1 christos if ( dnIsSuffix( np_ndn, &e->e_nname )) { 262 1.1 christos rs->sr_err = LDAP_NO_SUCH_OBJECT; 263 1.1 christos rs->sr_text = "new superior not found"; 264 1.1 christos goto return_results; 265 1.1 christos } 266 1.1 christos /* Get Entry with dn=newSuperior. Does newSuperior exist? */ 267 1.1 christos rc = wt_dn2entry(op->o_bd, wc, np_ndn, &np); 268 1.1 christos switch( rc ) { 269 1.1 christos case 0: 270 1.1 christos break; 271 1.1 christos case WT_NOTFOUND: 272 1.1 christos Debug( LDAP_DEBUG_ANY, 273 1.1 christos "<== wt_modrdn: new superior not found: %s\n", 274 1.1 christos np_ndn->bv_val ); 275 1.1 christos rs->sr_err = LDAP_NO_SUCH_OBJECT; 276 1.1 christos rs->sr_text = "new superior not found"; 277 1.1 christos goto return_results; 278 1.1 christos default: 279 1.1 christos Debug( LDAP_DEBUG_ANY, 280 1.1 christos "<== wt_modrdn: wt_dn2entry failed %s (%d)\n", 281 1.1 christos wiredtiger_strerror(rc), rc ); 282 1.1 christos rs->sr_err = LDAP_OTHER; 283 1.1 christos rs->sr_text = "internal error"; 284 1.1 christos goto return_results; 285 1.1 christos } 286 1.1 christos Debug( LDAP_DEBUG_TRACE, 287 1.1 christos "wt_modrdn: wr to new parent OK np=%p, id=%ld\n", 288 1.1 christos (void *) np, (long) np->e_id ); 289 1.1 christos rs->sr_err = access_allowed( op, np, children, 290 1.1 christos NULL, ACL_WADD, NULL ); 291 1.1 christos if( ! rs->sr_err ) { 292 1.1 christos Debug( LDAP_DEBUG_TRACE, 293 1.1 christos "wt_modrdn: no wr to newSup children\n" ); 294 1.1 christos rs->sr_text = "no write access to new superior's children"; 295 1.1 christos rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 296 1.1 christos goto return_results; 297 1.1 christos } 298 1.1 christos if ( is_entry_alias( np ) ) { 299 1.1 christos Debug( LDAP_DEBUG_TRACE, 300 1.1 christos "wt_modrdn: entry is alias\n" ); 301 1.1 christos rs->sr_text = "new superior is an alias"; 302 1.1 christos rs->sr_err = LDAP_ALIAS_PROBLEM; 303 1.1 christos goto return_results; 304 1.1 christos } 305 1.1 christos if ( is_entry_referral( np ) ) { 306 1.1 christos /* parent is a referral, don't allow add */ 307 1.1 christos Debug( LDAP_DEBUG_TRACE, 308 1.1 christos "wt_modrdn: entry is referral\n" ); 309 1.1 christos rs->sr_text = "new superior is a referral"; 310 1.1 christos rs->sr_err = LDAP_OTHER; 311 1.1 christos goto return_results; 312 1.1 christos } 313 1.1 christos } else { 314 1.1 christos /* no parent, modrdn entry directly under root */ 315 1.1 christos /* TODO: */ 316 1.1 christos Debug( LDAP_DEBUG_TRACE, 317 1.1 christos "wt_modrdn: no parent, not implement yet\n" ); 318 1.1 christos rs->sr_text = "not implement yet"; 319 1.1 christos rs->sr_err = LDAP_OTHER; 320 1.1 christos goto return_results; 321 1.1 christos } 322 1.1 christos 323 1.1 christos Debug( LDAP_DEBUG_TRACE, 324 1.1 christos "wt_modrdn: wr to new parent's children OK\n" ); 325 1.1 christos new_parent_dn = np_dn; 326 1.1 christos } 327 1.1 christos 328 1.1 christos /* Build target dn and make sure target entry doesn't exist already. */ 329 1.1 christos if (!new_dn.bv_val) { 330 1.1 christos build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn, NULL ); 331 1.1 christos } 332 1.1 christos 333 1.1 christos if (!new_ndn.bv_val) { 334 1.1 christos struct berval bv = {0, NULL}; 335 1.1 christos dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx ); 336 1.1 christos ber_dupbv( &new_ndn, &bv ); 337 1.1 christos /* FIXME: why not call dnNormalize() w/o ctx? */ 338 1.1 christos op->o_tmpfree( bv.bv_val, op->o_tmpmemctx ); 339 1.1 christos } 340 1.1 christos 341 1.1 christos Debug( LDAP_DEBUG_TRACE, 342 1.1 christos "wt_modrdn: new ndn=%s\n", new_ndn.bv_val ); 343 1.1 christos 344 1.1 christos /* check new entry */ 345 1.1 christos rc = wt_dn2entry(op->o_bd, wc, &new_ndn, &ne); 346 1.1 christos switch( rc ) { 347 1.1 christos case 0: 348 1.1 christos /* Allow rename to same DN */ 349 1.1 christos if(e->e_id == ne->e_id){ 350 1.1 christos break; 351 1.1 christos } 352 1.1 christos rs->sr_err = LDAP_ALREADY_EXISTS; 353 1.1 christos goto return_results; 354 1.1 christos break; 355 1.1 christos case WT_NOTFOUND: 356 1.1 christos break; 357 1.1 christos default: 358 1.1 christos Debug( LDAP_DEBUG_ANY, 359 1.1 christos "<== wt_modrdn: wt_dn2entry failed %s (%d)\n", 360 1.1 christos wiredtiger_strerror(rc), rc ); 361 1.1 christos rs->sr_err = LDAP_OTHER; 362 1.1 christos rs->sr_text = "internal error"; 363 1.1 christos goto return_results; 364 1.1 christos } 365 1.1 christos 366 1.1 christos assert( op->orr_modlist != NULL ); 367 1.1 christos 368 1.1 christos if( op->o_preread ) { 369 1.1 christos if( preread_ctrl == NULL ) { 370 1.1 christos preread_ctrl = &ctrls[num_ctrls++]; 371 1.1 christos ctrls[num_ctrls] = NULL; 372 1.1 christos } 373 1.1 christos if( slap_read_controls( op, rs, e, 374 1.1 christos &slap_pre_read_bv, preread_ctrl ) ) 375 1.1 christos { 376 1.1 christos Debug( LDAP_DEBUG_TRACE, 377 1.1 christos "<== wt_modrdn: pre-read failed!\n" ); 378 1.1 christos if ( op->o_preread & SLAP_CONTROL_CRITICAL ) { 379 1.1 christos /* FIXME: is it correct to abort 380 1.1 christos * operation if control fails? */ 381 1.1 christos goto return_results; 382 1.1 christos } 383 1.1 christos } 384 1.1 christos } 385 1.1 christos 386 1.1 christos /* begin transaction */ 387 1.1 christos rc = wc->session->begin_transaction(wc->session, NULL); 388 1.1 christos if( rc ) { 389 1.1 christos Debug( LDAP_DEBUG_TRACE, 390 1.1 christos "wt_modrdn: begin_transaction failed: %s (%d)\n", 391 1.1 christos wiredtiger_strerror(rc), rc ); 392 1.1 christos rs->sr_err = LDAP_OTHER; 393 1.1 christos rs->sr_text = "begin_transaction failed"; 394 1.1 christos goto return_results; 395 1.1 christos } 396 1.1 christos wc->is_begin_transaction = 1; 397 1.1 christos Debug( LDAP_DEBUG_TRACE, 398 1.1 christos "wt_modrdn: session id: %p\n", wc->session ); 399 1.1 christos 400 1.1 christos /* delete old DN */ 401 1.1 christos rc = wt_dn2id_delete( op, wc, &e->e_nname); 402 1.1 christos if ( rc ) { 403 1.1 christos Debug(LDAP_DEBUG_TRACE, 404 1.1 christos "<== wt_modrdn: delete failed: %s (%d)\n", 405 1.1 christos wiredtiger_strerror(rc), rc ); 406 1.1 christos rs->sr_err = LDAP_OTHER; 407 1.1 christos rs->sr_text = "dn2id delete failed"; 408 1.1 christos goto return_results; 409 1.1 christos } 410 1.1 christos 411 1.1 christos /* copy the entry, then override some fields */ 412 1.1 christos dummy = *e; 413 1.1 christos dummy.e_name = new_dn; 414 1.1 christos dummy.e_nname = new_ndn; 415 1.1 christos dummy.e_attrs = NULL; 416 1.1 christos 417 1.1 christos /* add new DN */ 418 1.1 christos rc = wt_dn2id_add( op, wc, np?np->e_id:p->e_id, &dummy ); 419 1.1 christos if ( rc ) { 420 1.1 christos Debug(LDAP_DEBUG_TRACE, 421 1.1 christos "<== wt_modrdn: add failed: %s (%d)\n", 422 1.1 christos wiredtiger_strerror(rc), rc ); 423 1.1 christos rs->sr_err = LDAP_OTHER; 424 1.1 christos rs->sr_text = "DN add failed"; 425 1.1 christos goto return_results; 426 1.1 christos } 427 1.1 christos dummy.e_attrs = e->e_attrs; 428 1.1 christos 429 1.1 christos rc = wt_modify_internal( op, wc, op->orm_modlist, 430 1.1 christos &dummy, &rs->sr_text, textbuf, textlen ); 431 1.1 christos if( rc != LDAP_SUCCESS ) { 432 1.1 christos Debug(LDAP_DEBUG_TRACE, 433 1.1 christos "<== wt_modrdn: modify failed: %s (%d)\n", 434 1.1 christos wiredtiger_strerror(rc), rc ); 435 1.1 christos if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; 436 1.1 christos goto return_results; 437 1.1 christos } 438 1.1 christos 439 1.1 christos /* update entry */ 440 1.1 christos rc = wt_id2entry_update( op, wc, &dummy ); 441 1.1 christos if ( rc != 0 ) { 442 1.1 christos Debug( LDAP_DEBUG_TRACE, 443 1.1 christos "wt_modrdn: id2entry update failed(%d)\n", rc ); 444 1.1 christos if ( rc == LDAP_ADMINLIMIT_EXCEEDED ) { 445 1.1 christos rs->sr_text = "entry too big"; 446 1.1 christos } else { 447 1.1 christos rs->sr_err = LDAP_OTHER; 448 1.1 christos rs->sr_text = "entry update failed"; 449 1.1 christos } 450 1.1 christos goto return_results; 451 1.1 christos } 452 1.1 christos 453 1.1 christos if ( p_ndn.bv_len != 0 ) { 454 1.1 christos parent_is_glue = is_entry_glue(p); 455 1.1 christos /* TODO: glue entry handling */ 456 1.1 christos } 457 1.1 christos 458 1.1 christos if( op->o_postread ) { 459 1.1 christos if( postread_ctrl == NULL ) { 460 1.1 christos postread_ctrl = &ctrls[num_ctrls++]; 461 1.1 christos ctrls[num_ctrls] = NULL; 462 1.1 christos } 463 1.1 christos if( slap_read_controls( op, rs, &dummy, 464 1.1 christos &slap_post_read_bv, postread_ctrl ) ) 465 1.1 christos { 466 1.1 christos Debug( LDAP_DEBUG_TRACE, 467 1.1 christos "<== wt_modrdn: post-read failed!\n" ); 468 1.1 christos if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { 469 1.1 christos /* FIXME: is it correct to abort 470 1.1 christos * operation if control fails? */ 471 1.1 christos goto return_results; 472 1.1 christos } 473 1.1 christos } 474 1.1 christos } 475 1.1 christos 476 1.1 christos if( op->o_noop ) { 477 1.1 christos rs->sr_err = LDAP_X_NO_OPERATION; 478 1.1 christos goto return_results; 479 1.1 christos } 480 1.1 christos 481 1.1 christos rc = wc->session->commit_transaction(wc->session, NULL); 482 1.1 christos wc->is_begin_transaction = 0; 483 1.1 christos if( rc ) { 484 1.1 christos Debug( LDAP_DEBUG_TRACE, 485 1.1 christos "<== wt_modrdn: commit failed: %s (%d)\n", 486 1.1 christos wiredtiger_strerror(rc), rc ); 487 1.1 christos rs->sr_err = LDAP_OTHER; 488 1.1 christos rs->sr_text = "commit failed"; 489 1.1 christos goto return_results; 490 1.1 christos } 491 1.1 christos 492 1.1 christos Debug(LDAP_DEBUG_TRACE, 493 1.1 christos "wt_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n", 494 1.1 christos op->o_noop ? " (no-op)" : "", 495 1.1 christos dummy.e_id, op->o_req_dn.bv_val ); 496 1.1 christos 497 1.1 christos rs->sr_err = LDAP_SUCCESS; 498 1.1 christos rs->sr_text = NULL; 499 1.1 christos if( num_ctrls ) rs->sr_ctrls = ctrls; 500 1.1 christos 501 1.1 christos return_results: 502 1.1 christos if ( dummy.e_attrs ) { 503 1.1 christos attrs_free( dummy.e_attrs ); 504 1.1 christos } 505 1.1 christos send_ldap_result( op, rs ); 506 1.1 christos 507 1.1 christos if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) { 508 1.1 christos op->o_delete_glue_parent = 1; 509 1.1 christos } 510 1.1 christos 511 1.1 christos done: 512 1.1 christos if( wc && wc->is_begin_transaction ){ 513 1.1 christos Debug( LDAP_DEBUG_TRACE, "wt_modrdn: rollback transaction\n" ); 514 1.1 christos wc->session->rollback_transaction(wc->session, NULL); 515 1.1 christos wc->is_begin_transaction = 0; 516 1.1 christos } 517 1.1 christos 518 1.1 christos slap_graduate_commit_csn( op ); 519 1.1 christos 520 1.1 christos if( new_dn.bv_val != NULL ) free( new_dn.bv_val ); 521 1.1 christos if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val ); 522 1.1 christos 523 1.1 christos /* free entry */ 524 1.1 christos if( e != NULL ) { 525 1.1 christos wt_entry_return( e ); 526 1.1 christos } 527 1.1 christos /* free parent entry */ 528 1.1 christos if( p != NULL ) { 529 1.1 christos wt_entry_return( p ); 530 1.1 christos } 531 1.1 christos /* free new entry */ 532 1.1 christos if( ne != NULL ) { 533 1.1 christos wt_entry_return( ne ); 534 1.1 christos } 535 1.1 christos /* free new parent entry */ 536 1.1 christos if( np != NULL ) { 537 1.1 christos wt_entry_return( np ); 538 1.1 christos } 539 1.1 christos 540 1.1 christos if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) { 541 1.1 christos slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); 542 1.1 christos slap_sl_free( *preread_ctrl, op->o_tmpmemctx ); 543 1.1 christos } 544 1.1 christos if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) { 545 1.1 christos slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); 546 1.1 christos slap_sl_free( *postread_ctrl, op->o_tmpmemctx ); 547 1.1 christos } 548 1.1 christos return rs->sr_err; 549 1.1 christos } 550 1.1 christos 551 1.1 christos /* 552 1.1 christos * Local variables: 553 1.1 christos * indent-tabs-mode: t 554 1.1 christos * tab-width: 4 555 1.1 christos * c-basic-offset: 4 556 1.1 christos * End: 557 1.1 christos */ 558