🏡 index : ~doyle/pisshoff.git

author Jordan Doyle <jordan@doyle.la> 2023-06-28 22:39:37.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2023-06-28 22:49:15.0 +00:00:00
commit
cc4416562a82aa3aa80d806bc762965d60b3f5d1 [patch]
tree
f33072b9ec0cceae879e95dfd959c182e0b232b8
parent
176bed4177d1fc3b80ef93abdf2ee486b75fec7c
download
cc4416562a82aa3aa80d806bc762965d60b3f5d1.tar.gz

Start fleshing out filesystem and pwd tracking



Diff

 pisshoff-server/src/command.rs     | 44 +++++++++++++++++++++++++++++++--------
 pisshoff-server/src/file_system.rs | 41 ++++++++++++++++++++++++++++++++++++-
 pisshoff-server/src/main.rs        |  1 +-
 pisshoff-server/src/server.rs      | 11 ++++++++++-
 4 files changed, 89 insertions(+), 8 deletions(-)

diff --git a/pisshoff-server/src/command.rs b/pisshoff-server/src/command.rs
index 1f82200..5e3c615 100644
--- a/pisshoff-server/src/command.rs
+++ b/pisshoff-server/src/command.rs
@@ -2,6 +2,7 @@ pub mod uname;

use crate::server::Connection;
use itertools::{Either, Itertools};
use std::fmt::Write;
use std::{f32, str::FromStr, time::Duration};
use thrussh::{server::Session, ChannelId};

@@ -26,18 +27,45 @@ pub async fn run_command(
            session.data(channel, format!("{}\n", conn.username()).into());
        }
        "pwd" => {
            // TODO: mock FHS
            let username = conn.username();
            let pwd = if conn.username() == "root" {
                "/root\n".to_string()
            session.data(
                channel,
                format!("{}\n", conn.file_system().pwd().display()).into(),
            );
        }
        "ls" => {
            let resp = if args.len() == 1 {
                conn.file_system().ls(None).join("  ")
            } else if args.len() == 2 {
                conn.file_system().ls(Some(args.get(1).unwrap())).join("  ")
            } else {
                format!("/home/{username}\n")
                let mut out = String::new();

                for dir in args.iter().skip(1) {
                    if !out.is_empty() {
                        out.push_str("\n\n");
                    }

                    write!(out, "{dir}:").unwrap();
                    out.push_str(&conn.file_system().ls(Some(dir)).join("  "));
                }

                out
            };

            session.data(channel, pwd.into());
            if !resp.is_empty() {
                session.data(channel, format!("{resp}\n").into());
            }
        }
        "ls" => {
            // pretend /root is empty until we mock the FHS
        "cd" => {
            if args.len() > 2 {
                session.data(
                    channel,
                    "-bash: cd: too many arguments\n".to_string().into(),
                );
                return;
            }

            conn.file_system().cd(args.get(1).map(String::as_str));
        }
        "exit" => {
            let exit_status = args
diff --git a/pisshoff-server/src/file_system.rs b/pisshoff-server/src/file_system.rs
new file mode 100644
index 0000000..5f96385
--- /dev/null
+++ b/pisshoff-server/src/file_system.rs
@@ -0,0 +1,41 @@
#![allow(dead_code)]

use std::path::{Path, PathBuf};

/// A fake file system, stored in memory only active for the current session.
pub struct FileSystem {
    pwd: PathBuf,
    home: PathBuf,
}

impl FileSystem {
    pub fn new(user: &str) -> Self {
        let pwd = if user == "root" {
            PathBuf::new().join("/root")
        } else {
            PathBuf::new().join("/home").join(user)
        };

        Self {
            home: pwd.clone(),
            pwd,
        }
    }

    pub fn cd(&mut self, v: Option<&str>) {
        if let Some(v) = v {
            self.pwd.push(v);
        } else {
            self.pwd = self.home.clone();
        }
    }

    pub fn pwd(&self) -> &Path {
        &self.pwd
    }

    #[allow(clippy::unused_self)]
    pub fn ls(&self, _dir: Option<&str>) -> &[&str] {
        &[]
    }
}
diff --git a/pisshoff-server/src/main.rs b/pisshoff-server/src/main.rs
index 379a4c4..71af86d 100644
--- a/pisshoff-server/src/main.rs
+++ b/pisshoff-server/src/main.rs
@@ -17,6 +17,7 @@ use tracing_subscriber::EnvFilter;
mod audit;
mod command;
mod config;
mod file_system;
mod server;
mod state;

diff --git a/pisshoff-server/src/server.rs b/pisshoff-server/src/server.rs
index ef29239..74389d8 100644
--- a/pisshoff-server/src/server.rs
+++ b/pisshoff-server/src/server.rs
@@ -2,6 +2,7 @@ use crate::audit::{
    ExecCommandEvent, SignalEvent, SubsystemRequestEvent, TcpIpForwardEvent, WindowAdjustedEvent,
    WindowChangeRequestEvent,
};
use crate::file_system::FileSystem;
use crate::{
    audit::{
        AuditLog, AuditLogAction, LoginAttemptEvent, OpenDirectTcpIpEvent, OpenX11Event,
@@ -74,6 +75,7 @@ impl thrussh::server::Server for Server {
                ..AuditLog::default()
            },
            username: None,
            file_system: None,
        }
    }
}
@@ -83,6 +85,7 @@ pub struct Connection {
    server: Server,
    audit_log: AuditLog,
    username: Option<String>,
    file_system: Option<FileSystem>,
}

impl Connection {
@@ -90,6 +93,14 @@ impl Connection {
        self.username.as_deref().unwrap_or("root")
    }

    pub fn file_system(&mut self) -> &mut FileSystem {
        if self.file_system.is_none() {
            self.file_system = Some(FileSystem::new(self.username()));
        }

        self.file_system.as_mut().unwrap()
    }

    fn try_login(&mut self, user: &str, password: &str) -> bool {
        self.username = Some(user.to_string());