1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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();
}
}
}
|