Skip to content

Commit

Permalink
Merge #2664
Browse files Browse the repository at this point in the history
2664: Fix execution of `sudo` through `exec` command r=townsend2010 a=luis4a0

Fixes #2663.

Co-authored-by: Luis Peñaranda <[email protected]>
  • Loading branch information
2 people authored and Chris Townsend committed Jul 16, 2022
1 parent fd605e5 commit 5b05fb6
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/client/cli/cmd/exec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,16 @@ mp::ReturnCode cmd::Exec::exec_success(const mp::SSHInfoReply& reply, const mp::
std::vector<std::vector<std::string>> 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}};
Expand Down
32 changes: 32 additions & 0 deletions tests/test_cli_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string> 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<multipass::SSHInfoReply>* server) {
server->Write(response);
return grpc::Status{};
});

std::vector<std::string> 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/"};
Expand Down

0 comments on commit 5b05fb6

Please sign in to comment.