From 5b05fb6f740558528199837a0c775316a2ace066 Mon Sep 17 00:00:00 2001 From: "bors[bot]" <26634292+bors[bot]@users.noreply.github.com> Date: Fri, 15 Jul 2022 20:19:51 +0000 Subject: [PATCH] Merge #2664 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2664: Fix execution of `sudo` through `exec` command r=townsend2010 a=luis4a0 Fixes #2663. Co-authored-by: Luis PeƱaranda --- src/client/cli/cmd/exec.cpp | 11 ++++++++++- tests/test_cli_client.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/client/cli/cmd/exec.cpp b/src/client/cli/cmd/exec.cpp index 24642e8d42..86c3b01996 100644 --- a/src/client/cli/cmd/exec.cpp +++ b/src/client/cli/cmd/exec.cpp @@ -169,7 +169,16 @@ mp::ReturnCode cmd::Exec::exec_success(const mp::SSHInfoReply& reply, const mp:: std::vector> all_args; if (dir) { - all_args = {{"cd", *dir}, {args}}; + if (args[0] == "sudo") + { + // If we are running through 'sudo' and need to change directory, it might happen that the default user + // does not have access to the folder and thus the cd command will fail. Additionally, `cd` cannot be + // ran with sudo, what forces us to run everything through `sh`. + auto sh_args = fmt::format("cd {} && {}", *dir, fmt::join(args, " ")); + all_args = {{"sudo", "sh", "-c", sh_args}}; + } + else + all_args = {{"cd", *dir}, {args}}; } else all_args = {{args}}; diff --git a/tests/test_cli_client.cpp b/tests/test_cli_client.cpp index 92421d202d..0f3b1c60fa 100644 --- a/tests/test_cli_client.cpp +++ b/tests/test_cli_client.cpp @@ -1284,6 +1284,38 @@ TEST_F(Client, execCmdWithDirPrependsCd) EXPECT_EQ(send_command({"exec", instance_name, "--working-directory", dir, "--", cmd}), mp::ReturnCode::Ok); } +TEST_F(Client, execCmdWithDirAndSudoUsesSh) +{ + std::string dir{"/root/"}; + std::vector cmds{"sudo", "pwd"}; + + std::string cmds_string{cmds[0]}; + for (size_t i = 1; i < cmds.size(); ++i) + cmds_string += " " + cmds[i]; + + REPLACE(ssh_channel_request_exec, ([&dir, &cmds_string](ssh_channel, const char* raw_cmd) { + EXPECT_EQ(raw_cmd, "'sudo' 'sh' '-c' 'cd " + dir + " && " + cmds_string + "'"); + + return SSH_OK; + })); + + std::string instance_name{"instance"}; + mp::SSHInfoReply response = make_fake_ssh_info_response(instance_name); + + EXPECT_CALL(mock_daemon, ssh_info(_, _, _)) + .WillOnce([&response](grpc::ServerContext* context, const mp::SSHInfoRequest* request, + grpc::ServerWriter* server) { + server->Write(response); + return grpc::Status{}; + }); + + std::vector full_cmdline{"exec", instance_name, "--working-directory", dir, "--"}; + for (const auto& c : cmds) + full_cmdline.push_back(c); + + EXPECT_EQ(send_command(full_cmdline), mp::ReturnCode::Ok); +} + TEST_F(Client, execCmdFailsIfSshExecThrows) { std::string dir{"/home/ubuntu/"};