diff options
author | qkzk <qu3nt1n@gmail.com> | 2023-01-15 16:05:17 +0100 |
---|---|---|
committer | qkzk <qu3nt1n@gmail.com> | 2023-01-15 16:05:17 +0100 |
commit | e691e175b50223c1b9add6a7dbe47322f498378d (patch) | |
tree | a0e4657c09311bbbef7ef605581e4d2e274cb7ee /src | |
parent | 71b59e229df9da4ac48b64465baa21b7d4d1d088 (diff) |
doesn't work
Diffstat (limited to 'src')
-rw-r--r-- | src/fm_error.rs | 7 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/luks.rs | 187 | ||||
-rw-r--r-- | src/main.rs | 19 |
4 files changed, 213 insertions, 1 deletions
diff --git a/src/fm_error.rs b/src/fm_error.rs index e071621..bc7352f 100644 --- a/src/fm_error.rs +++ b/src/fm_error.rs @@ -29,6 +29,7 @@ pub enum ErrorVariant { IMAGEERROR, SERDEYAML, CHRONO, + UTF8ERROR, CUSTOM(String), } @@ -180,5 +181,11 @@ impl From<chrono::ParseError> for FmError { } } +impl From<std::string::FromUtf8Error> for FmError { + fn from(error: std::string::FromUtf8Error) -> Self { + Self::new(ErrorVariant::UTF8ERROR, &error.to_string()) + } +} + /// A Result with type `T` and `FmError`. pub type FmResult<T> = Result<T, FmError>; @@ -19,6 +19,7 @@ pub mod help; pub mod input; pub mod keybindings; pub mod log; +pub mod luks; pub mod marks; pub mod mode; pub mod opener; diff --git a/src/luks.rs b/src/luks.rs new file mode 100644 index 0000000..941303b --- /dev/null +++ b/src/luks.rs @@ -0,0 +1,187 @@ +use std::io::Write; +use std::process::{Command, Stdio}; + +use crate::fm_error::{FmError, FmResult}; + +/// get devices list from lsblk +/// Return the output of +/// ```bash +/// lsblk -l -o FSTYPE,PATH,UUID,FSVER,MOUNTPOINT,PARTLABEL +/// ``` +/// as a String. +pub fn get_devices() -> FmResult<String> { + let output = Command::new("lsblk") + .args(&vec!["-l", "-o", "FSTYPE,PATH,UUID,FSVER,MOUNTPOINT"]) + .stdin(Stdio::null()) + .stderr(Stdio::null()) + .output()?; + Ok(String::from_utf8(output.stdout)?) +} + +/// Parse the output of an lsblk detailed output and filter the line +/// Containing "crypto" aka Luks encrypted crypto devices +pub fn filter_crypto_devices_lines(output: String) -> Vec<String> { + output + .lines() + .filter(|line| line.contains("crypto")) + .map(|line| line.into()) + .collect() +} + +#[derive(Debug, Default)] +pub struct CryptoDevice { + fs_type: String, + path: String, + uuid: String, + fs_ver: String, + mountpoints: Option<String>, + sudo_password: Option<String>, + luks_passphrase: Option<String>, +} + +impl CryptoDevice { + /// Parse the output of a lsblk formated line into a struct + pub fn from_line(line: &str) -> FmResult<Self> { + let mut strings = line.split_whitespace(); + let mut params: Vec<Option<String>> = vec![None; 5]; + let mut count = 0; + while let Some(param) = strings.next() { + params[count] = Some(param.to_owned()); + count += 1; + } + Ok(Self { + fs_type: params + .remove(0) + .ok_or_else(|| FmError::custom("CryptoDevice", "parameter shouldn't be None"))?, + path: params + .remove(0) + .ok_or_else(|| FmError::custom("CryptoDevice", "parameter shouldn't be None"))?, + uuid: params + .remove(0) + .ok_or_else(|| FmError::custom("CryptoDevice", "parameter shouldn't be None"))?, + fs_ver: params + .remove(0) + .ok_or_else(|| FmError::custom("CryptoDevice", "parameter shouldn't be None"))?, + mountpoints: params.remove(0), + sudo_password: None, + luks_passphrase: None, + }) + } + + pub fn is_already_mounted(&self) -> bool { + self.mountpoints.is_some() + } + + pub fn format_luksopen_parameters(&self) -> [String; 5] { + [ + "-S".to_owned(), + "cryptsetup".to_owned(), + "luksOpen".to_owned(), + self.path.clone(), + self.uuid.clone(), + ] + } + + pub fn format_mkdir_parameters(&self, username: &str) -> [String; 4] { + [ + "-S".to_owned(), + "mkdir".to_owned(), + "-p".to_owned(), + format!("/run/media/{}/{}", username, self.uuid), + ] + } + + pub fn format_mount_parameters(&self, username: &str) -> [String; 6] { + [ + "-S".to_owned(), + "cryptsetup".to_owned(), + "-t".to_owned(), + "ext4".to_owned(), // TODO! other fs ??? + format!("/dev/mapper/{}", self.uuid), + format!("/run/media/mapper/{}/{}", username, self.uuid), + ] + } + + pub fn format_umount_parameters(&self, username: &str) -> [String; 1] { + [format!("/run/media/mapper/{}/{}", username, self.uuid)] + } + + pub fn format_luksclose_parameters(&self) -> [String; 1] { + [self.uuid.to_owned()] + } + + pub fn set_sudo_password(&mut self, password: &str) { + self.sudo_password = Some(password.to_owned()) + } + + pub fn set_luks_passphrase(&mut self, passphrase: &str) { + self.luks_passphrase = Some(passphrase.to_owned()) + } + + pub fn open_mount(&self, username: &str) -> FmResult<()> { + if self.is_already_mounted() { + Err(FmError::custom( + "luks open mount", + "device is already mounted", + )) + } else if let Some(password) = &self.sudo_password { + if let Some(passphrase) = &self.luks_passphrase { + let password = password.to_owned(); + let password2 = password.clone(); + let passphrase = passphrase.to_owned(); + let passphrase2 = passphrase.clone(); + + let mut child = Command::new("sudo") + .args(&self.format_luksopen_parameters()) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + let mut stdin = child.stdin.take().expect("Failed to open stdin"); + std::thread::spawn(move || { + stdin + .write_all(format!("{}\n{}", &password, &passphrase).as_bytes()) + .expect("Failed to write to stdin"); + }); + child.wait_with_output()?; + + let mut child = Command::new("sudo") + .args(&self.format_mkdir_parameters(username)) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + let mut stdin = child.stdin.take().expect("Failed to open stdin"); + std::thread::spawn(move || { + stdin + .write_all(password2.as_bytes()) + .expect("Failed to write to stdin"); + }); + child.wait_with_output()?; + + let mut child = Command::new("sudo") + .args(&self.format_mount_parameters(username)) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + let mut stdin = child.stdin.take().expect("Failed to open stdin"); + std::thread::spawn(move || { + stdin + .write_all(passphrase2.as_bytes()) + .expect("Failed to write to stdin"); + }); + child.wait_with_output()?; + + Ok(()) + } else { + Err(FmError::custom( + "luks open mount", + "missing a password or passphrase", + )) + } + } else { + Err(FmError::custom( + "luks open mount", + "missing a password or passphrase", + )) + } + } +} diff --git a/src/main.rs b/src/main.rs index 3c9aa08..71bf208 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use clap::Parser; +use fm::luks::CryptoDevice; use log::info; use fm::args::Args; @@ -18,7 +19,7 @@ use fm::utils::{drop_everything, init_term, print_on_quit}; /// Init the status and display and listen to events (keyboard, mouse, resize, custom...). /// The application is redrawn after every event. /// When the user issues a quit event, the main loop is broken and we reset the cursor. -fn main() -> FmResult<()> { +fn main2() -> FmResult<()> { set_logger()?; info!("fm is starting"); @@ -48,3 +49,19 @@ fn main() -> FmResult<()> { info!("fm is shutting down"); Ok(()) } + +fn main() -> FmResult<()> { + use fm::luks::{filter_crypto_devices_lines, get_devices}; + + let ret_val = get_devices()?; + println!("{:?}", ret_val); + let output = filter_crypto_devices_lines(ret_val); + println!("{:?}", output); + let mut crypto_device = CryptoDevice::from_line(&output[0])?; + crypto_device.set_sudo_password("123"); + crypto_device.set_luks_passphrase("123"); + println!("{:?}", crypto_device); + crypto_device.open_mount("quentin")?; + + Ok(()) +} |