use std::fs::File;
use std::os::linux::fs::MetadataExt;
use std::path::Path;
use std::process::Command;
use std::thread::sleep;
use std::time::Duration;
use daemonize::Daemonize;
use runas::Command as SudoCommand;
use structopt::StructOpt;
use oramfs::ORAMConfig;
use oramfs::ORAMManager;
use oramfs::Oramfs;
use oramfs::{start, CLISubCommand};
use oramfs::{CLIArgs, BIG_FILE_NAME};
fn start_oram(args: &mut ORAMConfig) {
let args_clone = args.clone();
if args.disable_encryption {
println!("*****************************************************************************");
println!("[WARNING]: Encryption is disabled. This is not secure. You have been warned!");
println!("*****************************************************************************");
}
println!("Starting ORAM...");
let oramfs = Oramfs::new(&args);
if !args.foreground {
let stdout_log_path = "/tmp/oramfs.out";
let stderr_log_path = "/tmp/oramfs.err";
let stdout = File::create(stdout_log_path)
.unwrap_or_else(|_| panic!("Failed to create stdout log file: {}", stdout_log_path));
let stderr = File::create(stderr_log_path)
.unwrap_or_else(|_| panic!("Failed to create stderr log file: {}", stderr_log_path));
let daemonize = Daemonize::new()
.stdout(stdout)
.stderr(stderr)
.working_directory(".")
.exit_action(move || automount(args_clone));
println!("Running as a daemon...");
match daemonize.start() {
Ok(_) => {
println!("Successfully started daemon...");
start(args.clone(), oramfs);
}
Err(e) => eprintln!("Failed to start daemon: {}", e),
}
} else {
println!("Running in foreground...");
start(args.clone(), oramfs);
}
}
pub fn automount(args: ORAMConfig) {
if !args.manual {
sleep(Duration::from_millis(500));
println!("Mounting filesystem to private directory...");
mount_filesystem(args);
}
}
pub fn mount_filesystem(args: ORAMConfig) {
let oram_file_path = String::from(
Path::new(&args.mountpoint)
.join(BIG_FILE_NAME)
.to_str()
.unwrap(),
);
if args.init {
println!("Formatting EXT4 filesystem...");
if !Command::new("/usr/bin/mkfs.ext4")
.arg("-F")
.arg(oram_file_path.clone())
.status()
.unwrap()
.success()
{
cleanup(args);
panic!("Failed to format filesystem");
}
}
let private = args.private_directory.clone();
std::fs::create_dir_all(Path::new(&private)).expect("Failed to create private directory");
println!("Mounting directory...");
if !SudoCommand::new("/usr/bin/mount")
.arg("-o")
.arg("sync")
.arg(oram_file_path)
.arg(private.clone())
.status()
.unwrap()
.success()
{
cleanup(args);
panic!("Failed to mount directory");
}
let meta =
std::fs::metadata(private.clone()).expect("Failed to read private directory metadata");
let private_uid = meta.st_uid();
let current_uid = users::get_current_uid();
if private_uid != current_uid {
println!("Setting private directory owner...");
let current_user = users::get_user_by_uid(current_uid).unwrap();
if !SudoCommand::new("/usr/bin/chown")
.arg("-R")
.arg(current_user.name())
.arg(private.clone())
.status()
.unwrap()
.success()
{
cleanup(args);
panic!("Failed to mount directory");
}
}
println!(
"Setup complete! ORAM filesystem mounted to private directory at: {}",
private
);
}
pub fn cleanup(args: ORAMConfig) {
println!("Unmounting private ORAM directory...");
SudoCommand::new("/usr/bin/umount")
.arg(args.private_directory)
.status()
.expect("Failed to umount private ORAM directory");
sleep(Duration::from_millis(500));
println!("Unmounting FUSE mountpoint...");
Command::new("/usr/bin/umount")
.arg(args.mountpoint)
.status()
.expect("Failed to unmount FUSE mountpoint");
println!("Cleanup complete!");
}
pub fn oram_mount(oram_name: String, cmd: CLISubCommand) {
let mut config = ORAMManager::get_config();
let mut found = false;
for mut c in config.orams.iter_mut() {
if c.name == oram_name {
found = true;
if let CLISubCommand::Mount {
oram_name: _,
foreground,
init,
manual,
} = cmd
{
c.foreground = foreground;
c.manual = manual;
if !c.init {
println!("It looks like this ORAM is mounting for the first time. Initializing it first...");
c.init = true;
let passphrase = ORAMManager::get_passphrase_first_time();
c.encryption_passphrase = passphrase.clone();
c.encrypted_encryption_key = ORAMManager::generate_encryption_key(
c.name.clone(),
passphrase,
c.salt.clone(),
c.cipher.clone(),
);
ORAMManager::mark_init(c.name.clone());
c.init = true;
} else {
c.init = init;
let passphrase = ORAMManager::get_passphrase();
c.encryption_passphrase = passphrase.clone();
let valid_passphrase = ORAMManager::is_passphrase_valid(
passphrase,
c.salt.clone(),
c.encrypted_encryption_key.clone(),
);
if !valid_passphrase {
eprintln!("[Error] Invalid passphrase. Aborting.");
return;
}
}
break;
}
}
}
if !found {
eprintln!(
"No such ORAM: {}. \nDid you want to add an ORAM first?",
oram_name
);
} else {
for mut oram_config in config.orams {
if oram_config.name == oram_name {
start_oram(&mut oram_config);
}
}
}
}
fn oram_umount(oram_name: String) {
let config = ORAMManager::get_config();
let oram_config: ORAMConfig;
for c in config.orams {
if c.name == oram_name {
oram_config = c;
cleanup(oram_config);
return;
}
}
eprintln!(
"No such ORAM: {}. \nDid you want to add an ORAM first?",
oram_name
);
}
pub fn main() {
env_logger::init();
let args = CLIArgs::from_args();
match args.cmd.clone() {
CLISubCommand::List { oneline } => ORAMManager::list_orams(oneline),
CLISubCommand::Add { oram_name, .. } => ORAMManager::add_oram(oram_name, args.cmd),
CLISubCommand::Remove { oram_name } => ORAMManager::remove_oram(oram_name),
CLISubCommand::Mount { oram_name, .. } => oram_mount(oram_name, args.cmd),
CLISubCommand::Umount { oram_name } => oram_umount(oram_name),
CLISubCommand::Enlarge { oram_name: _, .. } => ORAMManager::double(args.cmd),
}
}