summaryrefslogtreecommitdiff
path: root/src/authentication.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/authentication.rs')
-rw-r--r--src/authentication.rs52
1 files changed, 52 insertions, 0 deletions
diff --git a/src/authentication.rs b/src/authentication.rs
new file mode 100644
index 0000000..5312792
--- /dev/null
+++ b/src/authentication.rs
@@ -0,0 +1,52 @@
+use anyhow::{Context, Result};
+use std::{
+ io::Read,
+ os::fd::AsRawFd,
+ process::{Child, Command, Stdio},
+ time::Duration,
+};
+
+pub struct TerminalAgent(Option<Child>);
+impl TerminalAgent {
+ pub fn start(interactive: bool) -> Result<Self> {
+ if !interactive || unsafe { libc::geteuid() } == 0 {
+ return Ok(Self(None));
+ }
+ let (mut reader, writer) = std::os::unix::net::UnixStream::pair()?;
+ reader.set_read_timeout(Some(Duration::from_secs(5)))?;
+ let fd = writer.as_raw_fd();
+ // SAFETY: fd belongs to writer and remains open until after spawning the agent.
+ unsafe {
+ libc::fcntl(fd, libc::F_SETFD, 0);
+ }
+ let mut child = Command::new("/usr/bin/pkttyagent")
+ .args([
+ "--process",
+ &std::process::id().to_string(),
+ "--notify-fd",
+ &fd.to_string(),
+ "--fallback",
+ ])
+ .stdin(Stdio::inherit())
+ .stdout(Stdio::inherit())
+ .stderr(Stdio::inherit())
+ .spawn()
+ .context("Could not start terminal polkit agent; install polkit")?;
+ drop(writer);
+ let mut buffer = [0u8; 1];
+ if let Err(error) = reader.read(&mut buffer) {
+ let _ = child.kill();
+ let _ = child.wait();
+ return Err(error).context("Terminal authentication agent did not become ready");
+ }
+ Ok(Self(Some(child)))
+ }
+}
+impl Drop for TerminalAgent {
+ fn drop(&mut self) {
+ if let Some(child) = &mut self.0 {
+ let _ = child.kill();
+ let _ = child.wait();
+ }
+ }
+}