chore(linux-client): make headless client / IPC service logs group-readable (#4825)

```[tasklist]
# Before merging
- [x] Add CI test to check that the Unix domain socket is owned by `root:firezone` (#4832 will do this)
```

This allows the GUI (running as a normal user who belongs to the
`firezone` group) to read back the connlib logs and export them in the
zip file.

<img width="716" alt="image"
src="https://github.com/firezone/firezone/assets/13400041/59cb7cc5-fd6a-4b27-a311-1b9c56b7b23e">
This commit is contained in:
Reactor Scram
2024-05-01 10:06:25 -05:00
committed by GitHub
parent dee9883054
commit 438469f3ac
3 changed files with 21 additions and 8 deletions

View File

@@ -120,9 +120,29 @@ impl Inner {
}
let file = new_file?;
Self::set_permissions(&file)?;
Ok((file, filename))
}
/// Make the logs group-readable so that the GUI, running as a user in the `firezone`
/// group, can zip them up when exporting logs.
#[cfg(target_os = "linux")]
fn set_permissions(f: &fs::File) -> io::Result<()> {
// I would put this at the top of the file, but it only exists on Linux
use std::os::unix::fs::PermissionsExt;
// user read/write, group read-only, others nothing
let perms = fs::Permissions::from_mode(0o640);
f.set_permissions(perms)?;
Ok(())
}
/// Does nothing on non-Linux systems
#[cfg(not(target_os = "linux"))]
#[allow(clippy::unnecessary_wraps)]
fn set_permissions(_f: &fs::File) -> io::Result<()> {
Ok(())
}
}
impl io::Write for Appender {

View File

@@ -44,6 +44,7 @@ ExecStart=firezone-client-ipc
Type=notify
# Unfortunately we may need root to control DNS
User=root
Group=firezone
[Install]
WantedBy=default.target

View File

@@ -185,18 +185,10 @@ pub(crate) fn run_ipc_service(cli: Cli) -> Result<()> {
}
async fn ipc_listen(cli: Cli) -> Result<()> {
// Find the `firezone` group
let fz_gid = nix::unistd::Group::from_name("firezone")
.context("can't get group by name")?
.context("firezone group must exist on the system")?
.gid;
// Remove the socket if a previous run left it there
let sock_path = sock_path();
tokio::fs::remove_file(&sock_path).await.ok();
let listener = UnixListener::bind(&sock_path).context("Couldn't bind UDS")?;
std::os::unix::fs::chown(&sock_path, Some(ROOT_USER), Some(fz_gid.into()))
.context("can't set firezone as the group for the UDS")?;
let perms = std::fs::Permissions::from_mode(0o660);
std::fs::set_permissions(sock_path, perms)?;
sd_notify::notify(true, &[sd_notify::NotifyState::Ready])?;