sorta works

This commit is contained in:
nora 2024-08-11 20:23:20 +02:00
parent 2b2e2ac1f0
commit bc7e12e50b
2 changed files with 166 additions and 10 deletions

View file

@ -1,15 +1,29 @@
use tracing::debug;
use std::collections::VecDeque;
use tracing::{debug, warn};
use crate::packet::Packet;
use crate::parse::Parser;
use crate::Result;
use crate::client_error;
use crate::packet::Packet;
use crate::parse::{Parser, Writer};
use crate::Result;
pub(crate) struct ServerChannelsState {}
pub(crate) struct ServerChannelsState {
packets_to_send: VecDeque<Packet>,
channels: Vec<SessionChannel>,
}
struct SessionChannel {
peer_channel: u32,
has_pty: bool,
has_shell: bool,
sent_bytes: Vec<u8>,
}
impl ServerChannelsState {
pub(crate) fn new() -> Self {
ServerChannelsState {}
ServerChannelsState {
packets_to_send: VecDeque::new(),
channels: Vec::new(),
}
}
pub(crate) fn on_packet(&mut self, packet_type: u8, mut payload: Parser<'_>) -> Result<()> {
@ -25,9 +39,114 @@ impl ServerChannelsState {
match channel_type {
"session" => {
todo!("open session")
let our_number = self.channels.len() as u32;
let mut confirm = Writer::new();
confirm.u8(Packet::SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
confirm.u32(our_number);
confirm.u32(sender_channel);
confirm.u32(initial_window_size);
confirm.u32(max_packet_size);
self.channels.push(SessionChannel {
peer_channel: sender_channel,
has_pty: false,
has_shell: false,
sent_bytes: Vec::new(),
});
self.packets_to_send.push_back(Packet {
payload: confirm.finish(),
});
debug!(?channel_type, ?our_number, "Successfully opened channel");
}
_ => {
let mut failure = Writer::new();
failure.u8(Packet::SSH_MSG_CHANNEL_OPEN_FAILURE);
failure.u32(sender_channel);
failure.u32(3); // SSH_OPEN_UNKNOWN_CHANNEL_TYPE
failure.string(b"unknown channel type");
failure.string(b"en_US");
self.packets_to_send.push_back(Packet {
payload: failure.finish(),
});
}
}
}
Packet::SSH_MSG_CHANNEL_DATA => {
let our_channel = payload.u32()?;
let data = payload.string()?;
let channel = self.channel(our_channel)?;
channel.recv_bytes(data);
let mut reply = Writer::new();
reply.u8(Packet::SSH_MSG_CHANNEL_DATA);
reply.u32(channel.peer_channel);
reply.string(data);
self.packets_to_send.push_back(Packet {
payload: reply.finish(),
});
}
Packet::SSH_MSG_CHANNEL_REQUEST => {
let our_channel = payload.u32()?;
let request_type = payload.utf8_string()?;
let want_reply = payload.bool()?;
debug!(?our_channel, ?request_type, "Got channel request");
let channel = self.channel(our_channel)?;
let peer_channel = channel.peer_channel;
match request_type {
"pty-req" => {
let term = payload.utf8_string()?;
let width_chars = payload.u32()?;
let height_rows = payload.u32()?;
let _width_px = payload.u32()?;
let _height_px = payload.u32()?;
let _term_modes = payload.string()?;
debug!(
?our_channel,
?term,
?width_chars,
?height_rows,
"Trying to open a terminal"
);
// Faithfully allocate the PTY.
channel.has_pty = true;
if want_reply {
self.send_channel_success(peer_channel);
}
}
"shell" => {
if !channel.has_pty {
self.send_channel_failure(peer_channel);
}
// Sure! (reborrow)
let channel = self.channel(our_channel)?;
channel.has_shell = true;
debug!(?our_channel, "Opening shell");
if want_reply {
self.send_channel_success(peer_channel);
}
}
"signal" => {
debug!(?our_channel, "Received signal");
// Ignore signals, something we can do.
}
_ => {
warn!(?request_type, ?our_channel, "Unknown channel request");
self.send_channel_failure(peer_channel);
}
_ => todo!("response with SSH_MSG_CHANNEL_OPEN_FAILURE"),
}
}
_ => {
@ -37,4 +156,38 @@ impl ServerChannelsState {
Ok(())
}
pub(crate) fn packets_to_send(&mut self) -> impl Iterator<Item = Packet> + '_ {
self.packets_to_send.drain(..)
}
fn send_channel_success(&mut self, recipient_channel: u32) {
let mut failure = Writer::new();
failure.u8(Packet::SSH_MSG_CHANNEL_SUCCESS);
failure.u32(recipient_channel);
self.packets_to_send.push_back(Packet {
payload: failure.finish(),
});
}
fn send_channel_failure(&mut self, recipient_channel: u32) {
let mut failure = Writer::new();
failure.u8(Packet::SSH_MSG_CHANNEL_FAILURE);
failure.u32(recipient_channel);
self.packets_to_send.push_back(Packet {
payload: failure.finish(),
});
}
fn channel(&mut self, number: u32) -> Result<&mut SessionChannel> {
self.channels
.get_mut(number as usize)
.ok_or_else(|| client_error!("unknown channel: {number}"))
}
}
impl SessionChannel {
fn recv_bytes(&mut self, bytes: &[u8]) {
self.sent_bytes.extend_from_slice(bytes);
}
}

View file

@ -406,8 +406,8 @@ impl ServerConnection {
let mut banner = Writer::new();
banner.u8(Packet::SSH_MSG_USERAUTH_BANNER);
banner.string(b"this system ONLY allows catgirls to enter.\r\nall other attempts WILL be prosecuted to the full extent of the rawr!!\r\n");
banner.string(b"en-US");
banner.string(b"!! this system ONLY allows catgirls to enter !!\r\n!! all other attempts WILL be prosecuted to the full extent of the rawr !!\r\n");
banner.string(b"en_US");
self.packet_transport.queue_packet(Packet {
payload: banner.finish(),
});
@ -431,6 +431,9 @@ impl ServerConnection {
// Connection-related packets
90..128 => {
con.on_packet(packet_type, payload)?;
for packet in con.packets_to_send() {
self.packet_transport.queue_packet(packet);
}
}
Packet::SSH_MSG_GLOBAL_REQUEST => {
let request_name = payload.utf8_string()?;