From 12eed4d557dcc2c98e38091766d0a7831d5e1be1 Mon Sep 17 00:00:00 2001 From: Bruce Leidl Date: Tue, 14 Dec 2021 06:04:02 -0500 Subject: [PATCH] Add use-media-dir config option and implement feature. If enabled this will mount /run/media/citadel directory into Realm as ~/Media directory. This makes mounted storage devices visible inside of Realms. By default this option is enabled only for the main realm. --- Cargo.lock | 44 +++++++++++++++++++++++++++ citadel-tool/Cargo.toml | 1 + citadel-tool/src/install/installer.rs | 1 + libcitadel/Cargo.toml | 1 + libcitadel/src/realm/config.rs | 11 +++++++ libcitadel/src/realm/launcher.rs | 4 +++ libcitadel/src/realm/manager.rs | 17 +++++++++++ 7 files changed, 79 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index aad5d1d..62c61b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "acl-sys" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc079f9bdd3124fd18df23c67f7e0f79d24751ae151dcffd095fcade07a3eb2" +dependencies = [ + "libc", +] + [[package]] name = "addr2line" version = "0.15.2" @@ -336,6 +345,7 @@ dependencies = [ "rpassword", "serde", "serde_derive", + "tempfile", "toml 0.5.8", ] @@ -1092,6 +1102,7 @@ dependencies = [ "lazy_static", "libc", "nix 0.17.0", + "posix-acl", "serde", "serde_derive", "sodiumoxide", @@ -1395,6 +1406,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "posix-acl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ea5dae99e4365fa738533b43f4c649c0450ba7fbb81a984a4fba6a42ce91812" +dependencies = [ + "acl-sys", + "libc", +] + [[package]] name = "ppv-lite86" version = "0.2.10" @@ -1645,6 +1666,15 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "rpassword" version = "4.0.5" @@ -1961,6 +1991,20 @@ dependencies = [ "version-compare 0.0.11", ] +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "rand 0.8.4", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "termion" version = "1.5.6" diff --git a/citadel-tool/Cargo.toml b/citadel-tool/Cargo.toml index 71ed183..95efff3 100644 --- a/citadel-tool/Cargo.toml +++ b/citadel-tool/Cargo.toml @@ -18,3 +18,4 @@ hex = "0.4" byteorder = "1" dbus = "0.8.4" pwhash = "0.3.1" +tempfile = "3" diff --git a/citadel-tool/src/install/installer.rs b/citadel-tool/src/install/installer.rs index 759ec42..bedcc62 100644 --- a/citadel-tool/src/install/installer.rs +++ b/citadel-tool/src/install/installer.rs @@ -49,6 +49,7 @@ extra-bindmounts-ro = [ '/usr/share/apt-cacher-ng' ] const MAIN_CONFIG: &str = "\ terminal-scheme = '$SCHEME' +use-media-dir = true "; const MAIN_TERMINAL_SCHEME: &str = "embers"; diff --git a/libcitadel/Cargo.toml b/libcitadel/Cargo.toml index f32719c..8770628 100644 --- a/libcitadel/Cargo.toml +++ b/libcitadel/Cargo.toml @@ -17,6 +17,7 @@ byteorder = "1" bincode = "1.2" walkdir = "2" dbus = "0.6" +posix-acl = "1.0.0" [dependencies.inotify] version = "0.8" diff --git a/libcitadel/src/realm/config.rs b/libcitadel/src/realm/config.rs index 71add87..441ef94 100644 --- a/libcitadel/src/realm/config.rs +++ b/libcitadel/src/realm/config.rs @@ -50,6 +50,9 @@ pub struct RealmConfig { #[serde(rename="use-shared-dir")] pub use_shared_dir: Option, + #[serde(rename="use-media-dir")] + pub use_media_dir: Option, + #[serde(rename="use-ephemeral-home")] pub use_ephemeral_home: Option, @@ -187,6 +190,7 @@ impl RealmConfig { pub fn default() -> Self { RealmConfig { use_shared_dir: Some(true), + use_media_dir: Some(false), use_ephemeral_home: Some(false), use_sound: Some(true), use_x11: Some(true), @@ -217,6 +221,7 @@ impl RealmConfig { pub fn empty() -> Self { RealmConfig { use_shared_dir: None, + use_media_dir: None, use_ephemeral_home: None, use_sound: None, use_x11: None, @@ -272,6 +277,12 @@ impl RealmConfig { self.bool_value(|c| c.use_shared_dir) } + /// If `true` the mount directory for external storage devices will be bind mounted as /Media + /// + pub fn media_dir(&self) -> bool { + self.bool_value(|c| c.use_media_dir) + } + /// If `true` the home directory of this realm will be set up in ephemeral mode. /// /// The ephemeral home directory is set up with the following steps: diff --git a/libcitadel/src/realm/launcher.rs b/libcitadel/src/realm/launcher.rs index 1b37721..55e336e 100644 --- a/libcitadel/src/realm/launcher.rs +++ b/libcitadel/src/realm/launcher.rs @@ -127,6 +127,10 @@ impl <'a> RealmLauncher <'a> { writeln!(s, "Bind=/realms/Shared:/home/user/Shared")?; } + if config.media_dir() && Path::new("/run/media/citadel").exists() { + writeln!(s, "Bind=/run/media/citadel:/home/user/Media")?; + } + for dev in &self.devices { writeln!(s, "Bind={}", dev)?; } diff --git a/libcitadel/src/realm/manager.rs b/libcitadel/src/realm/manager.rs index 945d06d..81f3b94 100644 --- a/libcitadel/src/realm/manager.rs +++ b/libcitadel/src/realm/manager.rs @@ -1,6 +1,7 @@ use std::collections::HashSet; use std::path::{Path, PathBuf}; use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use posix_acl::{ACL_EXECUTE, ACL_READ, PosixACL, Qualifier}; use crate::{Mountpoint, Result, Realms, RealmFS, Realm, util}; use crate::realmfs::realmfs_set::RealmFSSet; @@ -197,6 +198,18 @@ impl RealmManager { Ok(()) } + fn ensure_run_media_directory(&self) -> Result<()> { + let dir = Path::new("/run/media/citadel"); + if !dir.exists() { + util::create_dir(dir)?; + let mut acl = PosixACL::new(0o750); + acl.set(Qualifier::User(1000), ACL_READ|ACL_EXECUTE); + acl.write_acl(dir) + .map_err(context!("Failed writinf ACL to {}", dir.display()))?; + } + Ok(()) + } + fn _start_realm(&self, realm: &Realm, starting: &mut HashSet) -> Result<()> { self.start_realm_dependencies(realm, starting)?; @@ -212,6 +225,10 @@ impl RealmManager { realm.update_timestamp()?; + if realm.config().media_dir() { + self.ensure_run_media_directory()?; + } + self.systemd.start_realm(realm, &rootfs)?; self.create_realm_namefile(realm)?;