diff --git a/Cargo.toml b/Cargo.toml index 0e77fda..d6e9f0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,5 +8,3 @@ include = [ "lib/**/*.php" ] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bincode = "1.3.1" -serde = { version = "1.0.63", features = [ "derive" ] } diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 0000000..fd81aca --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,28 @@ +pub const SSH_FXP_INIT: u8 = 1; +pub const SSH_FXP_VERSION: u8 = 2; +pub const SSH_FXP_OPEN: u8 = 3; +pub const SSH_FXP_CLOSE: u8 = 4; +pub const SSH_FXP_READ: u8 = 5; +pub const SSH_FXP_WRITE: u8 = 6; +pub const SSH_FXP_LSTAT: u8 = 7; +pub const SSH_FXP_FSTAT: u8 = 8; +pub const SSH_FXP_SETSTAT: u8 = 9; +pub const SSH_FXP_FSETSTAT: u8 = 10; +pub const SSH_FXP_OPENDIR: u8 = 11; +pub const SSH_FXP_READDIR: u8 = 12; +pub const SSH_FXP_REMOVE: u8 = 13; +pub const SSH_FXP_MKDIR: u8 = 14; +pub const SSH_FXP_RMDIR: u8 = 15; +pub const SSH_FXP_REALPATH: u8 = 16; +pub const SSH_FXP_STAT: u8 = 17; +pub const SSH_FXP_RENAME: u8 = 18; +pub const SSH_FXP_READLINK: u8 = 19; +pub const SSH_FXP_SYMLINK: u8 = 20; +pub const SSH_FXP_STATUS: u8 = 101; +pub const SSH_FXP_HANDLE: u8 = 102; +pub const SSH_FXP_DATA: u8 = 103; +pub const SSH_FXP_NAME: u8 = 104; +pub const SSH_FXP_ATTRS: u8 = 105; +pub const SSH_FXP_EXTENDED: u8 = 200; +pub const SSH_FXP_EXTENDED_REPLY: u8 = 201; +pub const NEXTCLOUD_PATH: &str = "/var/www/nextcloud.sergiotarxz.freemyip.com/htdocs/"; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..43e7ca6 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +pub mod packet; +pub mod constants; diff --git a/src/main.rs b/src/main.rs index 04d81e1..87dc746 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,41 +1,14 @@ -use std::convert::TryInto; +use fake_sftp::packet::Packet; + +use fake_sftp::packet::dispatch_packet; + use std::io::{stdin, BufReader, BufWriter, Read, Write}; use std::process::Command; -use std::vec::Vec; - -const SSH_FXP_INIT: u8 = 1; -const SSH_FXP_VERSION: u8 = 2; -const SSH_FXP_OPEN: u8 = 3; -const SSH_FXP_CLOSE: u8 = 4; -const SSH_FXP_READ: u8 = 5; -const SSH_FXP_WRITE: u8 = 6; -const SSH_FXP_LSTAT: u8 = 7; -const SSH_FXP_FSTAT: u8 = 8; -const SSH_FXP_SETSTAT: u8 = 9; -const SSH_FXP_FSETSTAT: u8 = 10; -const SSH_FXP_OPENDIR: u8 = 11; -const SSH_FXP_READDIR: u8 = 12; -const SSH_FXP_REMOVE: u8 = 13; -const SSH_FXP_MKDIR: u8 = 14; -const SSH_FXP_RMDIR: u8 = 15; -const SSH_FXP_REALPATH: u8 = 16; -const SSH_FXP_STAT: u8 = 17; -const SSH_FXP_RENAME: u8 = 18; -const SSH_FXP_READLINK: u8 = 19; -const SSH_FXP_SYMLINK: u8 = 20; -const SSH_FXP_STATUS: u8 = 101; -const SSH_FXP_HANDLE: u8 = 102; -const SSH_FXP_DATA: u8 = 103; -const SSH_FXP_NAME: u8 = 104; -const SSH_FXP_ATTRS: u8 = 105; -const SSH_FXP_EXTENDED: u8 = 200; -const SSH_FXP_EXTENDED_REPLY: u8 = 201; -const NEXTCLOUD_PATH: &str = "/var/www/nextcloud.sergiotarxz.freemyip.com/htdocs/"; fn main() { eprintln!("{}", execute_php("echo \"hola rusty mundo\";")); loop { - let packet = Packet::read_packet(); + let packet = fake_sftp::packet::Packet::read_packet(); dispatch_packet(packet) } } @@ -50,135 +23,3 @@ fn execute_php(command: &str) -> String { buff_stderr.flush(); return String::from_utf8(output.stdout).expect("Unable to parse php response"); } - -fn dispatch_packet(packet: Packet) { - let mut buff_stdout = BufWriter::new(std::io::stdout()); - if packet.packet_header.type_packet == SSH_FXP_INIT { - let init_packet_data: VersionPacketData = match VersionPacketData::deserialize(&packet.data) - { - Ok(ok) => ok, - Err(err) => panic!(err), - }; - eprintln!("The client version is {}.", init_packet_data.version); - if init_packet_data.version < 3 { - panic!("Unsupported version, minimal client version 3."); - } - let version_packet_data = VersionPacketData { - version: 3, - extension_data: Vec::new(), - }; - let mut response_packet = Packet { - packet_header: PacketHeader { - length: 0, - type_packet: SSH_FXP_VERSION, - }, - data: version_packet_data.serialize(), - }; - let serialized_response = response_packet.serialize(); - eprintln!("{:#?}", serialized_response); - buff_stdout.write(&serialized_response); - buff_stdout.flush(); - } -} - -impl VersionPacketData { - fn deserialize(x: &[u8]) -> Result { - if x.len() < 4 { - return Err("Error parsing version from init packet header.".to_string()); - } else { - let mut u32_byte_array: [u8; 4] = [0; 4]; - let mut extension_data = Vec::new(); - u32_byte_array.copy_from_slice(&x[0..4]); - if x.len() > 4 { - extension_data.extend(&x[4..]); - } - return Ok(VersionPacketData { - version: u32::from_be_bytes(u32_byte_array), - extension_data: extension_data, - }); - } - } - fn serialize(&self) -> Vec { - let mut return_bytes = Vec::new(); - let u32_byte_array: [u8; 4] = self.version.to_be_bytes(); - return_bytes.extend(&u32_byte_array); - if self.extension_data.len() > 0 { - return_bytes.extend(&self.extension_data); - } - return_bytes - } -} - -impl Packet { - fn read_packet() -> Packet { - let mut packet_header: [u8; 5] = [0; 5]; - let mut buff_stdin = BufReader::new(std::io::stdin()); - match buff_stdin.read(&mut packet_header) { - Ok(ok) => ok, - Err(err) => panic!("Could not fetch packet: {}", err), - }; - eprintln!("{:#?}", packet_header); - let packet_header: PacketHeader = PacketHeader::deserialize(&packet_header); - eprintln!( - "Packet length {} and type {}.", - packet_header.length, packet_header.type_packet - ); - let mut data: Vec = Vec::new(); - data.resize(packet_header.length as usize - 1, 0); - match buff_stdin.read(&mut data) { - Ok(ok) => ok, - Err(err) => panic!("Could not fetch data: {}", err), - }; - eprintln!("{:#?}", data); - Packet::deserialize(packet_header, data) - } - fn deserialize(packet_header: PacketHeader, data: Vec) -> Packet { - Packet { - packet_header: packet_header, - data: data, - } - } - fn serialize(&mut self) -> Vec { - self.packet_header.length = (self.data.len() + 1) as u32; - let mut return_bytes = Vec::new(); - return_bytes.extend(&self.packet_header.serialize()); - return_bytes.extend(&self.data); - return_bytes - } -} - -struct PacketHeader { - length: u32, - type_packet: u8, -} -impl PacketHeader { - fn deserialize(x: &[u8; 5]) -> PacketHeader { - let mut u32_byte_array: [u8; 4] = [0; 4]; - u32_byte_array.copy_from_slice(&x[0..4]); - PacketHeader { - length: u32::from_be_bytes(u32_byte_array), - type_packet: x[4], - } - } - fn serialize(&self) -> [u8; 5] { - let serializated_data: [u8; 5] = [0; 5]; - let length = self.length.to_be_bytes(); - let type_packet = self.type_packet; - let mut return_bytes = length.to_vec(); - return_bytes.extend(&[type_packet][..]); - let boxed_return_bytes: Box<[u8; 5]> = return_bytes - .into_boxed_slice() - .try_into() - .expect("Unable to serialize."); - *boxed_return_bytes - } -} - -struct Packet { - packet_header: PacketHeader, - data: Vec, -} -struct VersionPacketData { - version: u32, - extension_data: Vec, -} diff --git a/src/packet.rs b/src/packet.rs new file mode 100644 index 0000000..2184a7a --- /dev/null +++ b/src/packet.rs @@ -0,0 +1,80 @@ +pub mod data; +pub mod header; + +use crate::constants::SSH_FXP_INIT; +use crate::constants::SSH_FXP_VERSION; + +use std::io::{BufReader, BufWriter, Read, Write}; + +pub fn dispatch_packet(packet: Packet) { + let mut buff_stdout = BufWriter::new(std::io::stdout()); + if packet.packet_header.type_packet == SSH_FXP_INIT { + let init_packet_data: data::version::VersionData = + match data::version::VersionData::deserialize(&packet.data) { + Ok(ok) => ok, + Err(err) => panic!(err), + }; + eprintln!("The client version is {}.", init_packet_data.version); + if init_packet_data.version < 3 { + panic!("Unsupported version, minimal client version 3."); + } + let version_packet_data = data::version::VersionData { + version: 3, + extension_data: Vec::new(), + }; + let mut response_packet = Packet { + packet_header: header::PacketHeader { + length: 0, + type_packet: SSH_FXP_VERSION, + }, + data: version_packet_data.serialize(), + }; + let serialized_response = response_packet.serialize(); + eprintln!("{:#?}", &serialized_response); + buff_stdout.write(&serialized_response); + buff_stdout.flush(); + } +} + +pub struct Packet { + pub packet_header: header::PacketHeader, + pub data: Vec, +} + +impl Packet { + pub fn read_packet() -> Packet { + let mut packet_header: [u8; 5] = [0; 5]; + let mut buff_stdin = BufReader::new(std::io::stdin()); + match buff_stdin.read(&mut packet_header) { + Ok(ok) => ok, + Err(err) => panic!("Could not fetch packet: {}", err), + }; + eprintln!("{:#?}", packet_header); + let packet_header: header::PacketHeader = header::PacketHeader::deserialize(&packet_header); + eprintln!( + "Packet length {} and type {}.", + packet_header.length, packet_header.type_packet + ); + let mut data: Vec = Vec::new(); + data.resize(packet_header.length as usize - 1, 0); + match buff_stdin.read(&mut data) { + Ok(ok) => ok, + Err(err) => panic!("Could not fetch data: {}", err), + }; + eprintln!("{:#?}", data); + Packet::deserialize(packet_header, data) + } + pub fn deserialize(packet_header: header::PacketHeader, data: Vec) -> Packet { + Packet { + packet_header: packet_header, + data: data, + } + } + pub fn serialize(&mut self) -> Vec { + self.packet_header.length = (self.data.len() + 1) as u32; + let mut return_bytes = Vec::new(); + return_bytes.extend(&self.packet_header.serialize()); + return_bytes.extend(&self.data); + return_bytes + } +} diff --git a/src/packet/data.rs b/src/packet/data.rs new file mode 100644 index 0000000..a6db76a --- /dev/null +++ b/src/packet/data.rs @@ -0,0 +1 @@ +pub mod version; diff --git a/src/packet/data/version.rs b/src/packet/data/version.rs new file mode 100644 index 0000000..9f28ea1 --- /dev/null +++ b/src/packet/data/version.rs @@ -0,0 +1,32 @@ +pub struct VersionData { + pub version: u32, + pub extension_data: Vec, +} + +impl VersionData { + pub fn deserialize(x: &[u8]) -> Result { + if x.len() < 4 { + return Err("Error parsing version from init packet header.".to_string()); + } else { + let mut u32_byte_array: [u8; 4] = [0; 4]; + let mut extension_data = Vec::new(); + u32_byte_array.copy_from_slice(&x[0..4]); + if x.len() > 4 { + extension_data.extend(&x[4..]); + } + return Ok(VersionData { + version: u32::from_be_bytes(u32_byte_array), + extension_data: extension_data, + }); + } + } + pub fn serialize(&self) -> Vec { + let mut return_bytes = Vec::new(); + let u32_byte_array: [u8; 4] = self.version.to_be_bytes(); + return_bytes.extend(&u32_byte_array); + if self.extension_data.len() > 0 { + return_bytes.extend(&self.extension_data); + } + return_bytes + } +} diff --git a/src/packet/header.rs b/src/packet/header.rs new file mode 100644 index 0000000..5bd5b72 --- /dev/null +++ b/src/packet/header.rs @@ -0,0 +1,28 @@ +use std::convert::TryInto; +pub struct PacketHeader { + pub length: u32, + pub type_packet: u8, +} + +impl PacketHeader { + pub fn deserialize(x: &[u8; 5]) -> PacketHeader { + let mut u32_byte_array: [u8; 4] = [0; 4]; + u32_byte_array.copy_from_slice(&x[0..4]); + PacketHeader { + length: u32::from_be_bytes(u32_byte_array), + type_packet: x[4], + } + } + pub fn serialize(&self) -> [u8; 5] { + let serializated_data: [u8; 5] = [0; 5]; + let length = self.length.to_be_bytes(); + let type_packet = self.type_packet; + let mut return_bytes = length.to_vec(); + return_bytes.extend(&[type_packet][..]); + let boxed_return_bytes: Box<[u8; 5]> = return_bytes + .into_boxed_slice() + .try_into() + .expect("Unable to serialize."); + *boxed_return_bytes + } +}