mod error;
#[cfg(target_os = "macos")]
mod privesc_darwin;
#[cfg(target_os = "linux")]
mod privesc_linux;
#[cfg(windows)]
mod privesc_windows;
use std::{path::PathBuf, process::ExitStatus};
pub use crate::error::{PrivescError, Result};
#[cfg(target_os = "macos")]
use privesc_darwin::PrivilegedChildInner;
#[cfg(target_os = "linux")]
use privesc_linux::PrivilegedChildInner;
#[cfg(windows)]
use privesc_windows::PrivilegedChildInner;
pub struct PrivilegedChild {
inner: PrivilegedChildInner,
}
impl PrivilegedChild {
pub fn wait(self) -> Result<PrivilegedOutput> {
self.inner.wait()
}
pub fn try_wait(&mut self) -> Result<Option<ExitStatus>> {
self.inner.try_wait()
}
pub fn id(&self) -> Option<u32> {
self.inner.id()
}
}
#[derive(Debug, Clone)]
pub struct PrivilegedOutput {
pub status: ExitStatus,
pub stdout: Option<Vec<u8>>,
pub stderr: Option<Vec<u8>>,
}
impl PrivilegedOutput {
pub fn success(&self) -> bool {
self.status.success()
}
pub fn stdout_str(&self) -> Option<&str> {
self.stdout
.as_ref()
.and_then(|b| std::str::from_utf8(b).ok())
}
pub fn stderr_str(&self) -> Option<&str> {
self.stderr
.as_ref()
.and_then(|b| std::str::from_utf8(b).ok())
}
}
#[derive(Debug, Clone)]
pub struct PrivilegedCommand {
program: PathBuf,
args: Vec<String>,
gui: bool,
prompt: Option<String>,
}
impl PrivilegedCommand {
pub fn new(program: impl Into<PathBuf>) -> Self {
Self {
program: program.into(),
args: Vec::new(),
gui: false,
prompt: None,
}
}
pub fn arg(mut self, arg: impl Into<String>) -> Self {
self.args.push(arg.into());
self
}
pub fn args<I, S>(mut self, args: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.args.extend(args.into_iter().map(Into::into));
self
}
pub fn gui(mut self, gui: bool) -> Self {
self.gui = gui;
self
}
pub fn prompt(mut self, prompt: impl Into<String>) -> Self {
self.prompt = Some(prompt.into());
self
}
pub fn run(&self) -> Result<PrivilegedOutput> {
if !self.program.is_absolute() {
return Err(PrivescError::InvalidProgramPath(self.program.clone()));
}
let args: Vec<&str> = self.args.iter().map(String::as_str).collect();
let prompt = self.prompt.as_deref();
#[cfg(target_os = "macos")]
{
privesc_darwin::run(&self.program, &args, self.gui, prompt)
}
#[cfg(windows)]
{
privesc_windows::run(&self.program, &args, self.gui, prompt)
}
#[cfg(target_os = "linux")]
{
privesc_linux::run(&self.program, &args, self.gui, prompt)
}
}
pub fn spawn(&self) -> Result<PrivilegedChild> {
if !self.program.is_absolute() {
return Err(PrivescError::InvalidProgramPath(self.program.clone()));
}
let args: Vec<&str> = self.args.iter().map(String::as_str).collect();
let prompt = self.prompt.as_deref();
#[cfg(target_os = "macos")]
let inner = privesc_darwin::spawn(&self.program, &args, self.gui, prompt)?;
#[cfg(windows)]
let inner = privesc_windows::spawn(&self.program, &args, self.gui, prompt)?;
#[cfg(target_os = "linux")]
let inner = privesc_linux::spawn(&self.program, &args, self.gui, prompt)?;
Ok(PrivilegedChild { inner })
}
}