use crate::PrivilegedOutput;
use crate::error::{PrivescError, Result};
use std::path::Path;
use std::process::{Child, Command, ExitStatus, Stdio};
pub struct PrivilegedChildInner {
child: Child,
}
impl PrivilegedChildInner {
pub fn wait(self) -> Result<PrivilegedOutput> {
let output = self.child.wait_with_output()?;
Ok(PrivilegedOutput {
status: output.status,
stdout: Some(output.stdout),
stderr: Some(output.stderr),
})
}
pub fn try_wait(&mut self) -> Result<Option<ExitStatus>> {
Ok(self.child.try_wait()?)
}
pub fn id(&self) -> Option<u32> {
Some(self.child.id())
}
}
fn spawn_gui(program: &Path, args: &[&str]) -> Result<PrivilegedChildInner> {
let pkexec_path = which::which("pkexec")
.map_err(|_| PrivescError::PrivilegeEscalationToolNotFound("pkexec".to_string()))?;
let process = Command::new(pkexec_path)
.arg(program)
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
Ok(PrivilegedChildInner { child: process })
}
fn spawn_cli(program: &Path, args: &[&str], prompt: Option<&str>) -> Result<PrivilegedChildInner> {
let mut command = Command::new("sudo");
if let Some(prompt) = prompt {
command.arg("-p").arg(prompt);
}
let process = command
.arg("--")
.arg(program)
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
Ok(PrivilegedChildInner { child: process })
}
pub fn spawn(
program: &Path,
args: &[&str],
gui: bool,
prompt: Option<&str>,
) -> Result<PrivilegedChildInner> {
if gui {
spawn_gui(program, args)
} else {
spawn_cli(program, args, prompt)
}
}
pub fn run(
program: &Path,
args: &[&str],
gui: bool,
prompt: Option<&str>,
) -> Result<PrivilegedOutput> {
spawn(program, args, gui, prompt)?.wait()
}