Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 37 additions & 29 deletions Userland/Services/SSHServer/SSHClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,45 +426,53 @@ ErrorOr<void> SSHClient::handle_channel_request(GenericMessage& message)
}

if (request_type == "exec"sv.bytes()) {
auto command = TRY(decode_string(message.payload));
TRY(handle_channel_exec(session, message));
return {};
}

return Error::from_string_literal("Unsupported channel request");
}

// 6.5. Starting a Shell or a Command
// https://datatracker.ietf.org/doc/html/rfc4254#section-6.5
ErrorOr<void> SSHClient::handle_channel_exec(Session& session, GenericMessage& message)
{
auto command = TRY(decode_string(message.payload));

// FIXME: This is a naive implementation, we should stream the result back
// to the user and not block the event loop during the execution of
// the command.
// We should also use the user's shell rather than hardcoding it.
// FIXME: This is a naive implementation, we should stream the result back
// to the user and not block the event loop during the execution of
// the command.
// We should also use the user's shell rather than hardcoding it.

#ifdef AK_OS_SERENITY
auto shell = "/bin/Shell"sv;
auto shell = "/bin/Shell"sv;
#else
auto shell = "/bin/sh"sv;
auto shell = "/bin/sh"sv;
#endif

Vector<ByteString> args;
args.append(shell);
args.append("-c");
args.append(ByteString(command.bytes()));
Vector<ByteString> args;
args.append(shell);
args.append("-c");
args.append(ByteString(command.bytes()));

Vector<char const*> raw_args;
raw_args.ensure_capacity(args.size() + 1);
for (auto& arg : args)
raw_args.append(arg.characters());
Vector<char const*> raw_args;
raw_args.ensure_capacity(args.size() + 1);
for (auto& arg : args)
raw_args.append(arg.characters());

raw_args.append(nullptr);
raw_args.append(nullptr);

auto child = TRY(Core::Command::create(shell, raw_args.data()));
auto output = TRY(child->read_all());
auto status = TRY(child->status());
auto child = TRY(Core::Command::create(shell, raw_args.data()));
auto output = TRY(child->read_all());
auto status = TRY(child->status());

if (status != Core::Command::ProcessResult::DoneWithZeroExitCode)
return Error::from_string_literal("Unable to run command");
if (status != Core::Command::ProcessResult::DoneWithZeroExitCode)
return Error::from_string_literal("Unable to run command");

TRY(send_channel_success_message(session));
TRY(send_channel_data(session, output.standard_output));
TRY(send_channel_close(session));
return {};
}

return Error::from_string_literal("Unsupported channel request");
TRY(send_channel_success_message(session));
TRY(send_channel_data(session, output.standard_output));
TRY(send_channel_close(session));
return {};
}

ErrorOr<void> SSHClient::send_channel_success_message(Session const& session)
Expand All @@ -476,7 +484,7 @@ ErrorOr<void> SSHClient::send_channel_success_message(Session const& session)
return {};
}

ErrorOr<void> SSHClient::send_channel_data(Session const& session, ByteBuffer const& data)
ErrorOr<void> SSHClient::send_channel_data(Session const& session, ReadonlyBytes data)
{
AllocatingMemoryStream stream;
TRY(stream.write_value(MessageID::CHANNEL_DATA));
Expand Down
3 changes: 2 additions & 1 deletion Userland/Services/SSHServer/SSHClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ class SSHClient : public Peer {
ErrorOr<void> handle_channel_open_message(GenericMessage&);
ErrorOr<void> send_channel_open_confirmation(Session const&);
ErrorOr<void> handle_channel_request(GenericMessage&);
ErrorOr<void> handle_channel_exec(Session&, GenericMessage&);
ErrorOr<void> send_channel_success_message(Session const&);
ErrorOr<void> send_channel_data(Session const&, ByteBuffer const&);
ErrorOr<void> send_channel_data(Session const&, ReadonlyBytes);
ErrorOr<void> handle_channel_close(GenericMessage&);
ErrorOr<void> send_channel_close(Session&);
ErrorOr<Session*> find_session(u32 sender_channel_id);
Expand Down
Loading