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