From bce5619b74fd5a98c439939b2200abff2c11ae00 Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Mon, 23 Mar 2026 13:49:52 +0000 Subject: [PATCH] Fix control socket path detection for non-group users (#30) Check /run/fips/ directory existence instead of the socket file inside it. Users not in the fips group can stat the directory but not traverse it, so the socket file check silently returned false and fell back to $XDG_RUNTIME_DIR with a misleading "No such file" error. --- CHANGELOG.md | 9 +++++++++ src/bin/fipsctl.rs | 4 +++- src/bin/fipstop/main.rs | 4 +++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e91365..a038073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Control socket path detection in fipsctl and fipstop now checks for + the `/run/fips/` directory instead of the socket file inside it, so + users not yet in the `fips` group get a clear "Permission denied" + error instead of a misleading "No such file" fallback to + `$XDG_RUNTIME_DIR` ([#30](https://github.com/jmcorgan/fips/issues/30), + reported by [@Sebastix](https://github.com/Sebastix)) + ## [0.2.0] - 2026-03-22 ### Added diff --git a/src/bin/fipsctl.rs b/src/bin/fipsctl.rs index c2ca2aa..2c3bc79 100644 --- a/src/bin/fipsctl.rs +++ b/src/bin/fipsctl.rs @@ -113,8 +113,10 @@ impl ShowCommands { /// /// Checks the system-wide path first (used when the daemon runs as a /// systemd service), then falls back to the user's XDG runtime directory. +/// Uses directory existence rather than socket file existence so the check +/// works even when the user lacks traverse permission on /run/fips/ (0750). fn default_socket_path() -> PathBuf { - if Path::new("/run/fips/control.sock").exists() { + if Path::new("/run/fips").exists() { PathBuf::from("/run/fips/control.sock") } else if let Ok(runtime_dir) = std::env::var("XDG_RUNTIME_DIR") { PathBuf::from(format!("{runtime_dir}/fips/control.sock")) diff --git a/src/bin/fipstop/main.rs b/src/bin/fipstop/main.rs index d16ac62..8b19879 100644 --- a/src/bin/fipstop/main.rs +++ b/src/bin/fipstop/main.rs @@ -34,8 +34,10 @@ struct Cli { /// /// Checks the system-wide path first (used when the daemon runs as a /// systemd service), then falls back to the user's XDG runtime directory. +/// Uses directory existence rather than socket file existence so the check +/// works even when the user lacks traverse permission on /run/fips/ (0750). fn default_socket_path() -> PathBuf { - if Path::new("/run/fips/control.sock").exists() { + if Path::new("/run/fips").exists() { PathBuf::from("/run/fips/control.sock") } else if let Ok(runtime_dir) = std::env::var("XDG_RUNTIME_DIR") { PathBuf::from(format!("{runtime_dir}/fips/control.sock"))