1 /* $OpenLDAP: pkg/ldap/servers/slapd/back-sql/modrdn.c,v 1.39.2.5 2008/02/11 23:26:48 kurt Exp $ */ 2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1999-2008 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 32 int 33 backsql_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 #ifdef BACKSQL_ARBITRARY_KEY 111 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=%s\n", 112 e_id.eid_id.bv_val, 0, 0 ); 113 #else /* ! BACKSQL_ARBITRARY_KEY */ 114 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=%ld\n", 115 e_id.eid_id, 0, 0 ); 116 #endif /* ! BACKSQL_ARBITRARY_KEY */ 117 118 if ( get_assert( op ) && 119 ( test_filter( op, &r, get_assertion( op ) ) 120 != LDAP_COMPARE_TRUE ) ) 121 { 122 rs->sr_err = LDAP_ASSERTION_FAILED; 123 e = &r; 124 goto done; 125 } 126 127 if ( backsql_has_children( op, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) { 128 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 129 "entry \"%s\" has children\n", 130 op->o_req_dn.bv_val, 0, 0 ); 131 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; 132 rs->sr_text = "subtree rename not supported"; 133 e = &r; 134 goto done; 135 } 136 137 /* 138 * Check for entry access to target 139 */ 140 if ( !access_allowed( op, &r, slap_schema.si_ad_entry, 141 NULL, ACL_WRITE, NULL ) ) { 142 Debug( LDAP_DEBUG_TRACE, " no access to entry\n", 0, 0, 0 ); 143 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 144 goto done; 145 } 146 147 dnParent( &op->o_req_dn, &pdn ); 148 dnParent( &op->o_req_ndn, &pndn ); 149 150 /* 151 * namingContext "" is not supported 152 */ 153 if ( BER_BVISEMPTY( &pdn ) ) { 154 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 155 "parent is \"\" - aborting\n", 0, 0, 0 ); 156 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 157 rs->sr_text = "not allowed within namingContext"; 158 e = NULL; 159 goto done; 160 } 161 162 /* 163 * Check for children access to parent 164 */ 165 bsi.bsi_e = &p; 166 e_id = bsi.bsi_base_id; 167 memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) ); 168 rs->sr_err = backsql_init_search( &bsi, &pndn, 169 LDAP_SCOPE_BASE, 170 (time_t)(-1), NULL, dbh, op, rs, 171 slap_anlist_all_attributes, 172 BACKSQL_ISF_GET_ENTRY ); 173 174 #ifdef BACKSQL_ARBITRARY_KEY 175 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 176 "old parent entry id is %s\n", 177 bsi.bsi_base_id.eid_id.bv_val, 0, 0 ); 178 #else /* ! BACKSQL_ARBITRARY_KEY */ 179 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 180 "old parent entry id is %ld\n", 181 bsi.bsi_base_id.eid_id, 0, 0 ); 182 #endif /* ! BACKSQL_ARBITRARY_KEY */ 183 184 if ( rs->sr_err != LDAP_SUCCESS ) { 185 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " 186 "could not retrieve renameDN ID - no such entry\n", 187 0, 0, 0 ); 188 e = &p; 189 goto done; 190 } 191 192 if ( !access_allowed( op, &p, slap_schema.si_ad_children, NULL, 193 newSuperior ? ACL_WDEL : ACL_WRITE, NULL ) ) 194 { 195 Debug( LDAP_DEBUG_TRACE, " no access to parent\n", 0, 0, 0 ); 196 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 197 goto done; 198 } 199 200 if ( newSuperior ) { 201 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); 202 203 /* 204 * namingContext "" is not supported 205 */ 206 if ( BER_BVISEMPTY( newSuperior ) ) { 207 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 208 "newSuperior is \"\" - aborting\n", 0, 0, 0 ); 209 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 210 rs->sr_text = "not allowed within namingContext"; 211 e = NULL; 212 goto done; 213 } 214 215 new_pdn = newSuperior; 216 new_npdn = op->oq_modrdn.rs_nnewSup; 217 218 /* 219 * Check for children access to new parent 220 */ 221 bsi.bsi_e = &n; 222 rs->sr_err = backsql_init_search( &bsi, new_npdn, 223 LDAP_SCOPE_BASE, 224 (time_t)(-1), NULL, dbh, op, rs, 225 slap_anlist_all_attributes, 226 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); 227 if ( rs->sr_err != LDAP_SUCCESS ) { 228 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " 229 "could not retrieve renameDN ID - no such entry\n", 230 0, 0, 0 ); 231 e = &n; 232 goto done; 233 } 234 235 n_id = bsi.bsi_base_id; 236 237 #ifdef BACKSQL_ARBITRARY_KEY 238 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 239 "new parent entry id=%s\n", 240 n_id.eid_id.bv_val, 0, 0 ); 241 #else /* ! BACKSQL_ARBITRARY_KEY */ 242 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 243 "new parent entry id=%ld\n", 244 n_id.eid_id, 0, 0 ); 245 #endif /* ! BACKSQL_ARBITRARY_KEY */ 246 247 if ( !access_allowed( op, &n, slap_schema.si_ad_children, 248 NULL, ACL_WADD, NULL ) ) { 249 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 250 "no access to new parent \"%s\"\n", 251 new_pdn->bv_val, 0, 0 ); 252 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 253 e = &n; 254 goto done; 255 } 256 257 } else { 258 n_id = bsi.bsi_base_id; 259 new_pdn = &pdn; 260 new_npdn = &pndn; 261 } 262 263 memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) ); 264 265 if ( newSuperior && dn_match( &pndn, new_npdn ) ) { 266 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 267 "newSuperior is equal to old parent - ignored\n", 268 0, 0, 0 ); 269 newSuperior = NULL; 270 } 271 272 if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) { 273 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 274 "newSuperior is equal to entry being moved " 275 "- aborting\n", 0, 0, 0 ); 276 rs->sr_err = LDAP_OTHER; 277 rs->sr_text = "newSuperior is equal to old DN"; 278 e = &r; 279 goto done; 280 } 281 282 build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn, 283 op->o_tmpmemctx ); 284 build_new_dn( &new_ndn, new_npdn, &op->oq_modrdn.rs_nnewrdn, 285 op->o_tmpmemctx ); 286 287 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): new entry dn is \"%s\"\n", 288 new_dn.bv_val, 0, 0 ); 289 290 realnew_dn = new_dn; 291 if ( backsql_api_dn2odbc( op, rs, &realnew_dn ) ) { 292 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): " 293 "backsql_api_dn2odbc(\"%s\") failed\n", 294 op->o_req_dn.bv_val, realnew_dn.bv_val, 0 ); 295 SQLFreeStmt( sth, SQL_DROP ); 296 297 rs->sr_text = "SQL-backend error"; 298 rs->sr_err = LDAP_OTHER; 299 e = NULL; 300 goto done; 301 } 302 303 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 304 "executing renentry_stmt\n", 0, 0, 0 ); 305 306 rc = backsql_Prepare( dbh, &sth, bi->sql_renentry_stmt, 0 ); 307 if ( rc != SQL_SUCCESS ) { 308 Debug( LDAP_DEBUG_TRACE, 309 " backsql_modrdn(): " 310 "error preparing renentry_stmt\n", 0, 0, 0 ); 311 backsql_PrintErrors( bi->sql_db_env, dbh, 312 sth, rc ); 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_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realnew_dn ); 321 if ( rc != SQL_SUCCESS ) { 322 Debug( LDAP_DEBUG_TRACE, 323 " backsql_add_attr(): " 324 "error binding DN 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, 2, SQL_PARAM_INPUT, &n_id.eid_id ); 337 if ( rc != SQL_SUCCESS ) { 338 Debug( LDAP_DEBUG_TRACE, 339 " backsql_add_attr(): " 340 "error binding parent 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, 3, SQL_PARAM_INPUT, &e_id.eid_keyval ); 353 if ( rc != SQL_SUCCESS ) { 354 Debug( LDAP_DEBUG_TRACE, 355 " backsql_add_attr(): " 356 "error binding entry 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 = backsql_BindParamID( sth, 4, SQL_PARAM_INPUT, &e_id.eid_id ); 369 if ( rc != SQL_SUCCESS ) { 370 Debug( LDAP_DEBUG_TRACE, 371 " backsql_add_attr(): " 372 "error binding ID parameter for objectClass %s\n", 373 oc->bom_oc->soc_cname.bv_val, 0, 0 ); 374 backsql_PrintErrors( bi->sql_db_env, dbh, 375 sth, rc ); 376 SQLFreeStmt( sth, SQL_DROP ); 377 378 rs->sr_text = "SQL-backend error"; 379 rs->sr_err = LDAP_OTHER; 380 e = NULL; 381 goto done; 382 } 383 384 rc = SQLExecute( sth ); 385 if ( rc != SQL_SUCCESS ) { 386 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " 387 "could not rename ldap_entries record\n", 0, 0, 0 ); 388 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 389 SQLFreeStmt( sth, SQL_DROP ); 390 rs->sr_err = LDAP_OTHER; 391 rs->sr_text = "SQL-backend error"; 392 e = NULL; 393 goto done; 394 } 395 SQLFreeStmt( sth, SQL_DROP ); 396 397 assert( op->orr_modlist != NULL ); 398 399 slap_mods_opattrs( op, &op->orr_modlist, 1 ); 400 401 assert( e_id.eid_oc != NULL ); 402 oc = e_id.eid_oc; 403 rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, op->orr_modlist ); 404 slap_graduate_commit_csn( op ); 405 if ( rs->sr_err != LDAP_SUCCESS ) { 406 e = &r; 407 goto done; 408 } 409 410 if ( BACKSQL_CHECK_SCHEMA( bi ) ) { 411 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; 412 413 backsql_entry_clean( op, &r ); 414 (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx ); 415 416 bsi.bsi_e = &r; 417 rs->sr_err = backsql_init_search( &bsi, &new_ndn, 418 LDAP_SCOPE_BASE, 419 (time_t)(-1), NULL, dbh, op, rs, 420 slap_anlist_all_attributes, 421 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); 422 switch ( rs->sr_err ) { 423 case LDAP_SUCCESS: 424 break; 425 426 case LDAP_REFERRAL: 427 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) && 428 dn_match( &new_ndn, &bsi.bsi_e->e_nname ) ) 429 { 430 rs->sr_err = LDAP_SUCCESS; 431 rs->sr_text = NULL; 432 rs->sr_matched = NULL; 433 if ( rs->sr_ref ) { 434 ber_bvarray_free( rs->sr_ref ); 435 rs->sr_ref = NULL; 436 } 437 break; 438 } 439 e = &r; 440 /* fallthru */ 441 442 default: 443 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " 444 "could not retrieve modrdnDN ID - no such entry\n", 445 0, 0, 0 ); 446 if ( !BER_BVISNULL( &r.e_nname ) ) { 447 /* FIXME: should always be true! */ 448 e = &r; 449 450 } else { 451 e = NULL; 452 } 453 goto done; 454 } 455 456 e_id = bsi.bsi_base_id; 457 458 rs->sr_err = entry_schema_check( op, &r, NULL, 0, 0, 459 &rs->sr_text, textbuf, sizeof( textbuf ) ); 460 if ( rs->sr_err != LDAP_SUCCESS ) { 461 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): " 462 "entry failed schema check -- aborting\n", 463 r.e_name.bv_val, 0, 0 ); 464 e = NULL; 465 goto done; 466 } 467 } 468 469 done:; 470 if ( e != NULL ) { 471 if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL, 472 ACL_DISCLOSE, NULL ) ) 473 { 474 rs->sr_err = LDAP_NO_SUCH_OBJECT; 475 rs->sr_text = NULL; 476 rs->sr_matched = NULL; 477 if ( rs->sr_ref ) { 478 ber_bvarray_free( rs->sr_ref ); 479 rs->sr_ref = NULL; 480 } 481 } 482 } 483 484 /* 485 * Commit only if all operations succeed 486 */ 487 if ( sth != SQL_NULL_HSTMT ) { 488 SQLUSMALLINT CompletionType = SQL_ROLLBACK; 489 490 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { 491 CompletionType = SQL_COMMIT; 492 } 493 494 SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); 495 } 496 497 if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) { 498 rs->sr_err = LDAP_X_NO_OPERATION; 499 } 500 501 send_ldap_result( op, rs ); 502 slap_graduate_commit_csn( op ); 503 504 if ( !BER_BVISNULL( &realnew_dn ) && realnew_dn.bv_val != new_dn.bv_val ) { 505 ch_free( realnew_dn.bv_val ); 506 } 507 508 if ( !BER_BVISNULL( &new_dn ) ) { 509 slap_sl_free( new_dn.bv_val, op->o_tmpmemctx ); 510 } 511 512 if ( !BER_BVISNULL( &new_ndn ) ) { 513 slap_sl_free( new_ndn.bv_val, op->o_tmpmemctx ); 514 } 515 516 if ( !BER_BVISNULL( &e_id.eid_ndn ) ) { 517 (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx ); 518 } 519 520 if ( !BER_BVISNULL( &n_id.eid_ndn ) ) { 521 (void)backsql_free_entryID( &n_id, 0, op->o_tmpmemctx ); 522 } 523 524 if ( !BER_BVISNULL( &r.e_nname ) ) { 525 backsql_entry_clean( op, &r ); 526 } 527 528 if ( !BER_BVISNULL( &p.e_nname ) ) { 529 backsql_entry_clean( op, &p ); 530 } 531 532 if ( !BER_BVISNULL( &n.e_nname ) ) { 533 backsql_entry_clean( op, &n ); 534 } 535 536 if ( rs->sr_ref ) { 537 ber_bvarray_free( rs->sr_ref ); 538 rs->sr_ref = NULL; 539 } 540 541 Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 ); 542 543 return rs->sr_err; 544 } 545 546