mirror of
https://github.com/Noratrieb/cluelessh.git
synced 2026-01-14 16:35:06 +01:00
ineteractive "tty"
This commit is contained in:
parent
6486bb4c81
commit
c7965e404a
3 changed files with 113 additions and 13 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
mod readline;
|
||||||
|
|
||||||
use std::{net::SocketAddr, sync::Arc};
|
use std::{net::SocketAddr, sync::Arc};
|
||||||
|
|
||||||
use cluelessh_tokio::{server::ServerAuthVerify, Channel};
|
use cluelessh_tokio::{server::ServerAuthVerify, Channel};
|
||||||
|
|
@ -134,6 +136,8 @@ async fn handle_session_channel(
|
||||||
mut channel: Channel,
|
mut channel: Channel,
|
||||||
total_sent_data: Arc<Mutex<Vec<u8>>>,
|
total_sent_data: Arc<Mutex<Vec<u8>>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let mut readline = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match channel.next_update().await {
|
match channel.next_update().await {
|
||||||
Ok(update) => match update {
|
Ok(update) => match update {
|
||||||
|
|
@ -141,6 +145,13 @@ async fn handle_session_channel(
|
||||||
let success = ChannelOperationKind::Success;
|
let success = ChannelOperationKind::Success;
|
||||||
match req {
|
match req {
|
||||||
ChannelRequest::PtyReq { want_reply, .. } => {
|
ChannelRequest::PtyReq { want_reply, .. } => {
|
||||||
|
let mut new_readline = readline::InteractiveShell::new();
|
||||||
|
let to_write = new_readline.bytes_to_write();
|
||||||
|
if !to_write.is_empty() {
|
||||||
|
channel.send(ChannelOperationKind::Data(to_write)).await?;
|
||||||
|
}
|
||||||
|
readline = Some(new_readline);
|
||||||
|
|
||||||
if want_reply {
|
if want_reply {
|
||||||
channel.send(success).await?;
|
channel.send(success).await?;
|
||||||
}
|
}
|
||||||
|
|
@ -176,13 +187,7 @@ async fn handle_session_channel(
|
||||||
}
|
}
|
||||||
ChannelUpdateKind::OpenFailed { .. } => todo!(),
|
ChannelUpdateKind::OpenFailed { .. } => todo!(),
|
||||||
ChannelUpdateKind::Data { data } => {
|
ChannelUpdateKind::Data { data } => {
|
||||||
let is_eof = data.contains(&0x04 /*EOF, Ctrl-D*/);
|
// Store sent data
|
||||||
|
|
||||||
// echo :3
|
|
||||||
channel
|
|
||||||
.send(ChannelOperationKind::Data(data.clone()))
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut total_sent_data = total_sent_data.lock().await;
|
let mut total_sent_data = total_sent_data.lock().await;
|
||||||
// arbitrary limit
|
// arbitrary limit
|
||||||
if total_sent_data.len() < 50_000 {
|
if total_sent_data.len() < 50_000 {
|
||||||
|
|
@ -195,6 +200,28 @@ async fn handle_session_channel(
|
||||||
channel.send(ChannelOperationKind::Close).await?;
|
channel.send(ChannelOperationKind::Close).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(readline) = &mut readline {
|
||||||
|
readline.recv_bytes(&data);
|
||||||
|
let to_write = readline.bytes_to_write();
|
||||||
|
if !to_write.is_empty() {
|
||||||
|
channel.send(ChannelOperationKind::Data(to_write)).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if readline.should_exit() {
|
||||||
|
debug!("Received Ctrl-D, closing channel");
|
||||||
|
|
||||||
|
channel.send(ChannelOperationKind::Eof).await?;
|
||||||
|
channel.send(ChannelOperationKind::Close).await?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// bad fallback behavior
|
||||||
|
let is_eof = data.contains(&0x04 /*EOF, Ctrl-D*/);
|
||||||
|
|
||||||
|
// echo :3
|
||||||
|
channel
|
||||||
|
.send(ChannelOperationKind::Data(data.clone()))
|
||||||
|
.await?;
|
||||||
|
|
||||||
if is_eof {
|
if is_eof {
|
||||||
debug!("Received Ctrl-D, closing channel");
|
debug!("Received Ctrl-D, closing channel");
|
||||||
|
|
||||||
|
|
@ -202,6 +229,7 @@ async fn handle_session_channel(
|
||||||
channel.send(ChannelOperationKind::Close).await?;
|
channel.send(ChannelOperationKind::Close).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ChannelUpdateKind::Open(_)
|
ChannelUpdateKind::Open(_)
|
||||||
| ChannelUpdateKind::Closed
|
| ChannelUpdateKind::Closed
|
||||||
| ChannelUpdateKind::ExtendedData { .. }
|
| ChannelUpdateKind::ExtendedData { .. }
|
||||||
|
|
@ -233,7 +261,7 @@ fn execute_command(command: &[u8]) -> ProcessOutput {
|
||||||
stdout: b"what the hell".to_vec(),
|
stdout: b"what the hell".to_vec(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
match command {
|
match command.trim() {
|
||||||
"uname -s -v -n -r -m" => ProcessOutput {
|
"uname -s -v -n -r -m" => ProcessOutput {
|
||||||
status: 0,
|
status: 0,
|
||||||
stdout: UNAME_SVNRM.to_vec(),
|
stdout: UNAME_SVNRM.to_vec(),
|
||||||
|
|
|
||||||
72
bin/cluelessh-faked/src/readline.rs
Normal file
72
bin/cluelessh-faked/src/readline.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
pub struct InteractiveShell {
|
||||||
|
line_buf: Vec<u8>,
|
||||||
|
out_buf: Vec<u8>,
|
||||||
|
should_exit: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InteractiveShell {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut this = Self {
|
||||||
|
line_buf: Vec::new(),
|
||||||
|
out_buf: Vec::new(),
|
||||||
|
should_exit: false,
|
||||||
|
};
|
||||||
|
this.prompt();
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recv_bytes(&mut self, data: &[u8]) {
|
||||||
|
// we're doing a little bit of tty-drivering
|
||||||
|
for &byte in data {
|
||||||
|
match byte {
|
||||||
|
// EOF
|
||||||
|
0x04 => {
|
||||||
|
self.should_exit = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
b'\r' => {
|
||||||
|
let output = super::execute_command(&self.line_buf);
|
||||||
|
self.line_buf.clear();
|
||||||
|
self.write(b"\r\n");
|
||||||
|
self.write(&output.stdout);
|
||||||
|
self.prompt();
|
||||||
|
}
|
||||||
|
// ESC
|
||||||
|
27 => {
|
||||||
|
// We don't handle any of the fancy escape characters, so just drop it to avoid weird behavior.
|
||||||
|
}
|
||||||
|
// DEL
|
||||||
|
127 => {
|
||||||
|
// Backspace, space, backspace.
|
||||||
|
// We literally erase it.
|
||||||
|
if self.line_buf.len() > 0 {
|
||||||
|
self.write(&[8, 32, 8]);
|
||||||
|
self.line_buf.truncate(self.line_buf.len() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if self.line_buf.len() < 1_000 {
|
||||||
|
self.line_buf.extend_from_slice(&[byte]);
|
||||||
|
}
|
||||||
|
self.write(&[byte]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prompt(&mut self) {
|
||||||
|
self.write(b"# ");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, data: &[u8]) {
|
||||||
|
self.out_buf.extend_from_slice(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn should_exit(&self) -> bool {
|
||||||
|
self.should_exit
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes_to_write(&mut self) -> Vec<u8> {
|
||||||
|
std::mem::take(&mut self.out_buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue