use std::fmt;
#[cfg(feature = "audit_token_from_pid")]
use std::mem;
use endpoint_sec_sys::{
au_asid_t, audit_token_t, audit_token_to_asid, audit_token_to_auid, audit_token_to_egid, audit_token_to_euid,
audit_token_to_pid, audit_token_to_pidversion, audit_token_to_rgid, audit_token_to_ruid, gid_t, pid_t, uid_t,
};
#[cfg(feature = "audit_token_from_pid")]
use libc::{c_int, KERN_SUCCESS};
#[cfg(feature = "audit_token_from_pid")]
use mach2::kern_return::kern_return_t;
#[cfg(feature = "audit_token_from_pid")]
use mach2::port::mach_port_name_t;
#[cfg(feature = "audit_token_from_pid")]
use mach2::task_info::TASK_AUDIT_TOKEN;
#[derive(Clone, Copy)]
#[doc(alias = "audit_token_t")]
#[repr(transparent)]
pub struct AuditToken(pub audit_token_t);
impl fmt::LowerHex for AuditToken {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for v in self.0.val {
fmt::LowerHex::fmt(&v, f)?;
}
Ok(())
}
}
impl fmt::UpperHex for AuditToken {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for v in self.0.val {
fmt::UpperHex::fmt(&v, f)?;
}
Ok(())
}
}
impl AuditToken {
#[cfg(feature = "audit_token_from_pid")]
pub fn from_pid(pid: pid_t) -> Result<Self, kern_return_t> {
Ok(Self(mach_task_audit_token(mach_task_name(pid)?)?))
}
#[inline]
pub fn raw_token(&self) -> &audit_token_t {
&self.0
}
#[inline(always)]
pub fn auid(&self) -> uid_t {
unsafe { audit_token_to_auid(self.0) }
}
#[inline(always)]
pub fn euid(&self) -> uid_t {
unsafe { audit_token_to_euid(self.0) }
}
#[inline(always)]
pub fn egid(&self) -> gid_t {
unsafe { audit_token_to_egid(self.0) }
}
#[inline(always)]
pub fn ruid(&self) -> uid_t {
unsafe { audit_token_to_ruid(self.0) }
}
#[inline(always)]
pub fn rgid(&self) -> gid_t {
unsafe { audit_token_to_rgid(self.0) }
}
#[inline(always)]
pub fn pid(&self) -> pid_t {
unsafe { audit_token_to_pid(self.0) }
}
#[inline(always)]
pub fn asid(&self) -> au_asid_t {
unsafe { audit_token_to_asid(self.0) }
}
#[inline(always)]
pub fn pidversion(&self) -> i32 {
unsafe { audit_token_to_pidversion(self.0) }
}
}
impl AuditToken {
#[inline(always)]
pub(crate) fn new(token: audit_token_t) -> Self {
AuditToken(token)
}
#[inline(always)]
pub(crate) fn get_raw_ref(&self) -> &audit_token_t {
&self.0
}
}
#[cfg(feature = "static_assertions")]
static_assertions::assert_impl_all!(AuditToken: Send);
impl_debug_eq_hash_with_functions!(
AuditToken;
auid,
euid,
egid,
ruid,
rgid,
pid,
asid,
pidversion,
);
#[cfg(feature = "audit_token_from_pid")]
fn mach_task_name(pid: pid_t) -> Result<mach_port_name_t, kern_return_t> {
let mut task_name = mach_port_name_t::default();
let res = unsafe { task_name_for_pid(mach2::traps::mach_task_self(), pid, &mut task_name) };
if res == KERN_SUCCESS {
Ok(task_name)
} else {
Err(res)
}
}
#[cfg(feature = "audit_token_from_pid")]
fn mach_task_audit_token(task_name: mach_port_name_t) -> Result<audit_token_t, kern_return_t> {
let mut audit_token = audit_token_t::default();
let mut audit_token_size = mem::size_of_val(&audit_token.val) as u32;
let res = unsafe {
libc::task_info(
task_name,
TASK_AUDIT_TOKEN,
audit_token.val.as_mut_ptr().cast(),
&mut audit_token_size,
)
};
if res == KERN_SUCCESS {
Ok(audit_token)
} else {
Err(res)
}
}
#[cfg(feature = "audit_token_from_pid")]
extern "C" {
fn task_name_for_pid(target_tport: mach_port_name_t, pid: c_int, tn: *mut mach_port_name_t) -> kern_return_t;
}
#[cfg(test)]
#[cfg(feature = "audit_token_from_pid")]
mod test {
use sysinfo::{PidExt, ProcessExt, ProcessRefreshKind, RefreshKind, System, SystemExt};
use super::*;
#[test]
fn audit_token_from_pid() {
let s = System::new_with_specifics(RefreshKind::new().with_processes(ProcessRefreshKind::everything()));
for (pid, process) in s.processes() {
let audit_token = AuditToken::from_pid(pid.as_u32() as pid_t).unwrap();
assert_eq!(process.user_id().map_or(0, |x| **x), audit_token.euid());
assert_eq!(process.group_id().map_or(0, |x| *x), audit_token.egid());
assert_eq!(process.pid().as_u32(), audit_token.pid() as u32);
}
}
}