diff --git a/Userland/Services/SSHServer/SSHClient.cpp b/Userland/Services/SSHServer/SSHClient.cpp index 74e97f4829a893..f12e02b0fb41f0 100644 --- a/Userland/Services/SSHServer/SSHClient.cpp +++ b/Userland/Services/SSHServer/SSHClient.cpp @@ -426,45 +426,53 @@ ErrorOr 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 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 args; - args.append(shell); - args.append("-c"); - args.append(ByteString(command.bytes())); + Vector args; + args.append(shell); + args.append("-c"); + args.append(ByteString(command.bytes())); - Vector raw_args; - raw_args.ensure_capacity(args.size() + 1); - for (auto& arg : args) - raw_args.append(arg.characters()); + Vector 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 SSHClient::send_channel_success_message(Session const& session) @@ -476,7 +484,7 @@ ErrorOr SSHClient::send_channel_success_message(Session const& session) return {}; } -ErrorOr SSHClient::send_channel_data(Session const& session, ByteBuffer const& data) +ErrorOr SSHClient::send_channel_data(Session const& session, ReadonlyBytes data) { AllocatingMemoryStream stream; TRY(stream.write_value(MessageID::CHANNEL_DATA)); diff --git a/Userland/Services/SSHServer/SSHClient.h b/Userland/Services/SSHServer/SSHClient.h index 1267d192943a13..1738937c344d9a 100644 --- a/Userland/Services/SSHServer/SSHClient.h +++ b/Userland/Services/SSHServer/SSHClient.h @@ -86,8 +86,9 @@ class SSHClient : public Peer { ErrorOr handle_channel_open_message(GenericMessage&); ErrorOr send_channel_open_confirmation(Session const&); ErrorOr handle_channel_request(GenericMessage&); + ErrorOr handle_channel_exec(Session&, GenericMessage&); ErrorOr send_channel_success_message(Session const&); - ErrorOr send_channel_data(Session const&, ByteBuffer const&); + ErrorOr send_channel_data(Session const&, ReadonlyBytes); ErrorOr handle_channel_close(GenericMessage&); ErrorOr send_channel_close(Session&); ErrorOr find_session(u32 sender_channel_id);