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