diff --git a/Cargo.lock b/Cargo.lock index 11fd40b..ba51d60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3172,6 +3172,7 @@ dependencies = [ "egui_material_icons", "evdev", "itertools 0.14.0", + "libc", "opener", "pipewire", "rfd", diff --git a/Cargo.toml b/Cargo.toml index 4b619aa..075298b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ eframe = { version = "0.34.2", default-features = false, features = [ egui_extras = "0.34.1" egui_material_icons = "0.6.0" egui_dnd = "0.15.0" +libc = "0.2.186" [[bin]] name = "pwsp-daemon" diff --git a/src/bin/daemon.rs b/src/bin/daemon.rs index 78e17ba..e6eb153 100644 --- a/src/bin/daemon.rs +++ b/src/bin/daemon.rs @@ -39,7 +39,11 @@ async fn main() -> Result<()> { let runtime_dir = get_runtime_dir(); - let lock_file = fs::File::create(runtime_dir.join("daemon.lock"))?; + let lock_file = fs::OpenOptions::new() + .create(true) + .write(true) + .truncate(false) + .open(runtime_dir.join("daemon.lock"))?; lock_file.lock()?; let socket_path = runtime_dir.join("daemon.sock"); diff --git a/src/utils/daemon.rs b/src/utils/daemon.rs index 864d155..36569f9 100644 --- a/src/utils/daemon.rs +++ b/src/utils/daemon.rs @@ -5,7 +5,7 @@ use crate::types::{ }; use anyhow::Result; -use std::os::unix::fs::PermissionsExt; +use std::os::unix::fs::{DirBuilderExt, MetadataExt, PermissionsExt}; use std::path::PathBuf; use std::{error::Error, fs}; use tokio::{ @@ -37,22 +37,52 @@ pub fn get_daemon_config() -> DaemonConfig { }) } +fn get_current_uid() -> u32 { + unsafe { libc::geteuid() } +} + pub fn get_runtime_dir() -> PathBuf { - dirs::runtime_dir().unwrap_or(PathBuf::from("/run/pwsp")) + dirs::runtime_dir().unwrap_or_else(|| { + let uid = get_current_uid(); + std::env::temp_dir().join(format!("pwsp-{}", uid)) + }) } pub fn create_runtime_dir() -> Result<()> { let runtime_dir = get_runtime_dir(); - if !runtime_dir.exists() { - fs::create_dir_all(&runtime_dir)?; + + if runtime_dir.exists() { + let meta = fs::symlink_metadata(&runtime_dir)?; + if meta.is_symlink() { + return Err(anyhow::anyhow!("Runtime directory is a symlink")); + } + let uid = get_current_uid(); + if meta.uid() != uid { + return Err(anyhow::anyhow!( + "Runtime directory is owned by another user" + )); + } + if meta.permissions().mode() & 0o777 != 0o700 { + return Err(anyhow::anyhow!( + "Runtime directory has incorrect permissions" + )); + } + } else { + fs::DirBuilder::new() + .recursive(true) + .mode(0o700) + .create(&runtime_dir)?; } - fs::set_permissions(&runtime_dir, fs::Permissions::from_mode(0o700))?; Ok(()) } pub fn is_daemon_running() -> Result { - let lock_file = fs::File::create(get_runtime_dir().join("daemon.lock"))?; + let lock_file = fs::OpenOptions::new() + .create(true) + .write(true) + .truncate(false) + .open(get_runtime_dir().join("daemon.lock"))?; match lock_file.try_lock() { Ok(_) => Ok(false), Err(_) => Ok(true),