1/* $NetBSD: modrdn.c,v 1.1.1.3 2010/12/12 15:23:25 adam Exp $ */ 2 3/* OpenLDAP: pkg/ldap/servers/slapd/back-sql/modrdn.c,v 1.39.2.8 2010/04/13 20:23:43 kurt Exp */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2010 The OpenLDAP Foundation. 7 * Portions Copyright 1999 Dmitry Kovalev. 8 * Portions Copyright 2002 Pierangelo Masarati. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19/* ACKNOWLEDGEMENTS: 20 * This work was initially developed by Dmitry Kovalev for inclusion 21 * by OpenLDAP Software. Additional significant contributors include 22 * Pierangelo Masarati. 23 */ 24 25#include "portable.h" 26 27#include <stdio.h> 28#include <sys/types.h> 29#include "ac/string.h" 30 31#include "slap.h" 32#include "proto-sql.h" 33 34int 35backsql_modrdn( Operation *op, SlapReply *rs ) 36{ 37 backsql_info *bi = (backsql_info*)op->o_bd->be_private; 38 SQLHDBC dbh = SQL_NULL_HDBC; 39 SQLHSTMT sth = SQL_NULL_HSTMT; 40 RETCODE rc; 41 backsql_entryID e_id = BACKSQL_ENTRYID_INIT, 42 n_id = BACKSQL_ENTRYID_INIT; 43 backsql_srch_info bsi = { 0 }; 44 backsql_oc_map_rec *oc = NULL; 45 struct berval pdn = BER_BVNULL, pndn = BER_BVNULL, 46 *new_pdn = NULL, *new_npdn = NULL, 47 new_dn = BER_BVNULL, new_ndn = BER_BVNULL, 48 realnew_dn = BER_BVNULL; 49 Entry r = { 0 }, 50 p = { 0 }, 51 n = { 0 }, 52 *e = NULL; 53 int manageDSAit = get_manageDSAit( op ); 54 struct berval *newSuperior = op->oq_modrdn.rs_newSup; 55 56 Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry \"%s\", " 57 "newrdn=\"%s\", newSuperior=\"%s\"\n", 58 op->o_req_dn.bv_val, op->oq_modrdn.rs_newrdn.bv_val, 59 newSuperior ? newSuperior->bv_val : "(NULL)" ); 60 61 rs->sr_err = backsql_get_db_conn( op, &dbh ); 62 if ( rs->sr_err != LDAP_SUCCESS ) { 63 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 64 "could not get connection handle - exiting\n", 65 0, 0, 0 ); 66 rs->sr_text = ( rs->sr_err == LDAP_OTHER ) 67 ? "SQL-backend error" : NULL; 68 e = NULL; 69 goto done; 70 } 71 72 bsi.bsi_e = &r; 73 rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, 74 LDAP_SCOPE_BASE, 75 (time_t)(-1), NULL, dbh, op, rs, 76 slap_anlist_all_attributes, 77 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) ); 78 switch ( rs->sr_err ) { 79 case LDAP_SUCCESS: 80 break; 81 82 case LDAP_REFERRAL: 83 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && 84 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) ) 85 { 86 rs->sr_err = LDAP_SUCCESS; 87 rs->sr_text = NULL; 88 rs->sr_matched = NULL; 89 if ( rs->sr_ref ) { 90 ber_bvarray_free( rs->sr_ref ); 91 rs->sr_ref = NULL; 92 } 93 break; 94 } 95 e = &r; 96 /* fallthru */ 97 98 default: 99 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " 100 "could not retrieve modrdnDN ID - no such entry\n", 101 0, 0, 0 ); 102 if ( !BER_BVISNULL( &r.e_nname ) ) { 103 /* FIXME: should always be true! */ 104 e = &r; 105 106 } else { 107 e = NULL; 108 } 109 goto done; 110 } 111 112#ifdef BACKSQL_ARBITRARY_KEY 113 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=%s\n", 114 e_id.eid_id.bv_val, 0, 0 ); 115#else /* ! BACKSQL_ARBITRARY_KEY */ 116 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=%ld\n", 117 e_id.eid_id, 0, 0 ); 118#endif /* ! BACKSQL_ARBITRARY_KEY */ 119 120 if ( get_assert( op ) && 121 ( test_filter( op, &r, get_assertion( op ) ) 122 != LDAP_COMPARE_TRUE ) ) 123 { 124 rs->sr_err = LDAP_ASSERTION_FAILED; 125 e = &r; 126 goto done; 127 } 128 129 if ( backsql_has_children( op, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) { 130 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 131 "entry \"%s\" has children\n", 132 op->o_req_dn.bv_val, 0, 0 ); 133 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; 134 rs->sr_text = "subtree rename not supported"; 135 e = &r; 136 goto done; 137 } 138 139 /* 140 * Check for entry access to target 141 */ 142 if ( !access_allowed( op, &r, slap_schema.si_ad_entry, 143 NULL, ACL_WRITE, NULL ) ) { 144 Debug( LDAP_DEBUG_TRACE, " no access to entry\n", 0, 0, 0 ); 145 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 146 goto done; 147 } 148 149 dnParent( &op->o_req_dn, &pdn ); 150 dnParent( &op->o_req_ndn, &pndn ); 151 152 /* 153 * namingContext "" is not supported 154 */ 155 if ( BER_BVISEMPTY( &pdn ) ) { 156 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 157 "parent is \"\" - aborting\n", 0, 0, 0 ); 158 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 159 rs->sr_text = "not allowed within namingContext"; 160 e = NULL; 161 goto done; 162 } 163 164 /* 165 * Check for children access to parent 166 */ 167 bsi.bsi_e = &p; 168 e_id = bsi.bsi_base_id; 169 memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) ); 170 rs->sr_err = backsql_init_search( &bsi, &pndn, 171 LDAP_SCOPE_BASE, 172 (time_t)(-1), NULL, dbh, op, rs, 173 slap_anlist_all_attributes, 174 BACKSQL_ISF_GET_ENTRY ); 175 176#ifdef BACKSQL_ARBITRARY_KEY 177 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 178 "old parent entry id is %s\n", 179 bsi.bsi_base_id.eid_id.bv_val, 0, 0 ); 180#else /* ! BACKSQL_ARBITRARY_KEY */ 181 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 182 "old parent entry id is %ld\n", 183 bsi.bsi_base_id.eid_id, 0, 0 ); 184#endif /* ! BACKSQL_ARBITRARY_KEY */ 185 186 if ( rs->sr_err != LDAP_SUCCESS ) { 187 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " 188 "could not retrieve renameDN ID - no such entry\n", 189 0, 0, 0 ); 190 e = &p; 191 goto done; 192 } 193 194 if ( !access_allowed( op, &p, slap_schema.si_ad_children, NULL, 195 newSuperior ? ACL_WDEL : ACL_WRITE, NULL ) ) 196 { 197 Debug( LDAP_DEBUG_TRACE, " no access to parent\n", 0, 0, 0 ); 198 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 199 goto done; 200 } 201 202 if ( newSuperior ) { 203 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); 204 205 /* 206 * namingContext "" is not supported 207 */ 208 if ( BER_BVISEMPTY( newSuperior ) ) { 209 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 210 "newSuperior is \"\" - aborting\n", 0, 0, 0 ); 211 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 212 rs->sr_text = "not allowed within namingContext"; 213 e = NULL; 214 goto done; 215 } 216 217 new_pdn = newSuperior; 218 new_npdn = op->oq_modrdn.rs_nnewSup; 219 220 /* 221 * Check for children access to new parent 222 */ 223 bsi.bsi_e = &n; 224 rs->sr_err = backsql_init_search( &bsi, new_npdn, 225 LDAP_SCOPE_BASE, 226 (time_t)(-1), NULL, dbh, op, rs, 227 slap_anlist_all_attributes, 228 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); 229 if ( rs->sr_err != LDAP_SUCCESS ) { 230 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " 231 "could not retrieve renameDN ID - no such entry\n", 232 0, 0, 0 ); 233 e = &n; 234 goto done; 235 } 236 237 n_id = bsi.bsi_base_id; 238 239#ifdef BACKSQL_ARBITRARY_KEY 240 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 241 "new parent entry id=%s\n", 242 n_id.eid_id.bv_val, 0, 0 ); 243#else /* ! BACKSQL_ARBITRARY_KEY */ 244 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 245 "new parent entry id=%ld\n", 246 n_id.eid_id, 0, 0 ); 247#endif /* ! BACKSQL_ARBITRARY_KEY */ 248 249 if ( !access_allowed( op, &n, slap_schema.si_ad_children, 250 NULL, ACL_WADD, NULL ) ) { 251 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 252 "no access to new parent \"%s\"\n", 253 new_pdn->bv_val, 0, 0 ); 254 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 255 e = &n; 256 goto done; 257 } 258 259 } else { 260 n_id = bsi.bsi_base_id; 261 new_pdn = &pdn; 262 new_npdn = &pndn; 263 } 264 265 memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) ); 266 267 if ( newSuperior && dn_match( &pndn, new_npdn ) ) { 268 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 269 "newSuperior is equal to old parent - ignored\n", 270 0, 0, 0 ); 271 newSuperior = NULL; 272 } 273 274 if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) { 275 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 276 "newSuperior is equal to entry being moved " 277 "- aborting\n", 0, 0, 0 ); 278 rs->sr_err = LDAP_OTHER; 279 rs->sr_text = "newSuperior is equal to old DN"; 280 e = &r; 281 goto done; 282 } 283 284 build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn, 285 op->o_tmpmemctx ); 286 build_new_dn( &new_ndn, new_npdn, &op->oq_modrdn.rs_nnewrdn, 287 op->o_tmpmemctx ); 288 289 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): new entry dn is \"%s\"\n", 290 new_dn.bv_val, 0, 0 ); 291 292 realnew_dn = new_dn; 293 if ( backsql_api_dn2odbc( op, rs, &realnew_dn ) ) { 294 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): " 295 "backsql_api_dn2odbc(\"%s\") failed\n", 296 op->o_req_dn.bv_val, realnew_dn.bv_val, 0 ); 297 SQLFreeStmt( sth, SQL_DROP ); 298 299 rs->sr_text = "SQL-backend error"; 300 rs->sr_err = LDAP_OTHER; 301 e = NULL; 302 goto done; 303 } 304 305 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 306 "executing renentry_stmt\n", 0, 0, 0 ); 307 308 rc = backsql_Prepare( dbh, &sth, bi->sql_renentry_stmt, 0 ); 309 if ( rc != SQL_SUCCESS ) { 310 Debug( LDAP_DEBUG_TRACE, 311 " backsql_modrdn(): " 312 "error preparing renentry_stmt\n", 0, 0, 0 ); 313 backsql_PrintErrors( bi->sql_db_env, dbh, 314 sth, rc ); 315 316 rs->sr_text = "SQL-backend error"; 317 rs->sr_err = LDAP_OTHER; 318 e = NULL; 319 goto done; 320 } 321 322 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realnew_dn ); 323 if ( rc != SQL_SUCCESS ) { 324 Debug( LDAP_DEBUG_TRACE, 325 " backsql_add_attr(): " 326 "error binding DN parameter for objectClass %s\n", 327 oc->bom_oc->soc_cname.bv_val, 0, 0 ); 328 backsql_PrintErrors( bi->sql_db_env, dbh, 329 sth, rc ); 330 SQLFreeStmt( sth, SQL_DROP ); 331 332 rs->sr_text = "SQL-backend error"; 333 rs->sr_err = LDAP_OTHER; 334 e = NULL; 335 goto done; 336 } 337 338 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT, &n_id.eid_id ); 339 if ( rc != SQL_SUCCESS ) { 340 Debug( LDAP_DEBUG_TRACE, 341 " backsql_add_attr(): " 342 "error binding parent ID parameter for objectClass %s\n", 343 oc->bom_oc->soc_cname.bv_val, 0, 0 ); 344 backsql_PrintErrors( bi->sql_db_env, dbh, 345 sth, rc ); 346 SQLFreeStmt( sth, SQL_DROP ); 347 348 rs->sr_text = "SQL-backend error"; 349 rs->sr_err = LDAP_OTHER; 350 e = NULL; 351 goto done; 352 } 353 354 rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &e_id.eid_keyval ); 355 if ( rc != SQL_SUCCESS ) { 356 Debug( LDAP_DEBUG_TRACE, 357 " backsql_add_attr(): " 358 "error binding entry ID parameter for objectClass %s\n", 359 oc->bom_oc->soc_cname.bv_val, 0, 0 ); 360 backsql_PrintErrors( bi->sql_db_env, dbh, 361 sth, rc ); 362 SQLFreeStmt( sth, SQL_DROP ); 363 364 rs->sr_text = "SQL-backend error"; 365 rs->sr_err = LDAP_OTHER; 366 e = NULL; 367 goto done; 368 } 369 370 rc = backsql_BindParamID( sth, 4, SQL_PARAM_INPUT, &e_id.eid_id ); 371 if ( rc != SQL_SUCCESS ) { 372 Debug( LDAP_DEBUG_TRACE, 373 " backsql_add_attr(): " 374 "error binding ID parameter for objectClass %s\n", 375 oc->bom_oc->soc_cname.bv_val, 0, 0 ); 376 backsql_PrintErrors( bi->sql_db_env, dbh, 377 sth, rc ); 378 SQLFreeStmt( sth, SQL_DROP ); 379 380 rs->sr_text = "SQL-backend error"; 381 rs->sr_err = LDAP_OTHER; 382 e = NULL; 383 goto done; 384 } 385 386 rc = SQLExecute( sth ); 387 if ( rc != SQL_SUCCESS ) { 388 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 389 "could not rename ldap_entries record\n", 0, 0, 0 ); 390 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 391 SQLFreeStmt( sth, SQL_DROP ); 392 rs->sr_err = LDAP_OTHER; 393 rs->sr_text = "SQL-backend error"; 394 e = NULL; 395 goto done; 396 } 397 SQLFreeStmt( sth, SQL_DROP ); 398 399 assert( op->orr_modlist != NULL ); 400 401 slap_mods_opattrs( op, &op->orr_modlist, 1 ); 402 403 assert( e_id.eid_oc != NULL ); 404 oc = e_id.eid_oc; 405 rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, op->orr_modlist ); 406 slap_graduate_commit_csn( op ); 407 if ( rs->sr_err != LDAP_SUCCESS ) { 408 e = &r; 409 goto done; 410 } 411 412 if ( BACKSQL_CHECK_SCHEMA( bi ) ) { 413 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; 414 415 backsql_entry_clean( op, &r ); 416 (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx ); 417 418 bsi.bsi_e = &r; 419 rs->sr_err = backsql_init_search( &bsi, &new_ndn, 420 LDAP_SCOPE_BASE, 421 (time_t)(-1), NULL, dbh, op, rs, 422 slap_anlist_all_attributes, 423 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); 424 switch ( rs->sr_err ) { 425 case LDAP_SUCCESS: 426 break; 427 428 case LDAP_REFERRAL: 429 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && 430 dn_match( &new_ndn, &bsi.bsi_e->e_nname ) ) 431 { 432 rs->sr_err = LDAP_SUCCESS; 433 rs->sr_text = NULL; 434 rs->sr_matched = NULL; 435 if ( rs->sr_ref ) { 436 ber_bvarray_free( rs->sr_ref ); 437 rs->sr_ref = NULL; 438 } 439 break; 440 } 441 e = &r; 442 /* fallthru */ 443 444 default: 445 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " 446 "could not retrieve modrdnDN ID - no such entry\n", 447 0, 0, 0 ); 448 if ( !BER_BVISNULL( &r.e_nname ) ) { 449 /* FIXME: should always be true! */ 450 e = &r; 451 452 } else { 453 e = NULL; 454 } 455 goto done; 456 } 457 458 e_id = bsi.bsi_base_id; 459 460 rs->sr_err = entry_schema_check( op, &r, NULL, 0, 0, NULL, 461 &rs->sr_text, textbuf, sizeof( textbuf ) ); 462 if ( rs->sr_err != LDAP_SUCCESS ) { 463 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): " 464 "entry failed schema check -- aborting\n", 465 r.e_name.bv_val, 0, 0 ); 466 e = NULL; 467 goto done; 468 } 469 } 470 471done:; 472 if ( e != NULL ) { 473 if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL, 474 ACL_DISCLOSE, NULL ) ) 475 { 476 rs->sr_err = LDAP_NO_SUCH_OBJECT; 477 rs->sr_text = NULL; 478 rs->sr_matched = NULL; 479 if ( rs->sr_ref ) { 480 ber_bvarray_free( rs->sr_ref ); 481 rs->sr_ref = NULL; 482 } 483 } 484 } 485 486 /* 487 * Commit only if all operations succeed 488 */ 489 if ( sth != SQL_NULL_HSTMT ) { 490 SQLUSMALLINT CompletionType = SQL_ROLLBACK; 491 492 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { 493 CompletionType = SQL_COMMIT; 494 } 495 496 SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); 497 } 498 499 if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) { 500 rs->sr_err = LDAP_X_NO_OPERATION; 501 } 502 503 send_ldap_result( op, rs ); 504 slap_graduate_commit_csn( op ); 505 506 if ( !BER_BVISNULL( &realnew_dn ) && realnew_dn.bv_val != new_dn.bv_val ) { 507 ch_free( realnew_dn.bv_val ); 508 } 509 510 if ( !BER_BVISNULL( &new_dn ) ) { 511 slap_sl_free( new_dn.bv_val, op->o_tmpmemctx ); 512 } 513 514 if ( !BER_BVISNULL( &new_ndn ) ) { 515 slap_sl_free( new_ndn.bv_val, op->o_tmpmemctx ); 516 } 517 518 if ( !BER_BVISNULL( &e_id.eid_ndn ) ) { 519 (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx ); 520 } 521 522 if ( !BER_BVISNULL( &n_id.eid_ndn ) ) { 523 (void)backsql_free_entryID( &n_id, 0, op->o_tmpmemctx ); 524 } 525 526 if ( !BER_BVISNULL( &r.e_nname ) ) { 527 backsql_entry_clean( op, &r ); 528 } 529 530 if ( !BER_BVISNULL( &p.e_nname ) ) { 531 backsql_entry_clean( op, &p ); 532 } 533 534 if ( !BER_BVISNULL( &n.e_nname ) ) { 535 backsql_entry_clean( op, &n ); 536 } 537 538 if ( rs->sr_ref ) { 539 ber_bvarray_free( rs->sr_ref ); 540 rs->sr_ref = NULL; 541 } 542 543 Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 ); 544 545 return rs->sr_err; 546} 547 548