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