#![cfg(any(target_os = "macos", test))]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(super) struct TokenResult {
pub ret: i32,
pub optlen: u32,
pub at_pid: u32,
pub at_euid: u32,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(super) struct PidResult {
pub ret: i32,
pub optlen: u32,
pub pid: i32,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(super) struct CredResult {
pub ret: i32,
pub optlen: u32,
pub cr_uid: u32,
}
const AUDIT_TOKEN_SIZE: u32 = 32;
const I32_SIZE: u32 = 4;
const XUCRED_MIN_RETURN: u32 = 8;
pub(super) fn pid_uid_from_results(
token: TokenResult,
pid: PidResult,
cred: CredResult,
) -> (u32, u32) {
if token.ret == 0 && token.optlen >= AUDIT_TOKEN_SIZE {
return (token.at_pid, token.at_euid);
}
let resolved_pid = if pid.ret == 0 && pid.optlen >= I32_SIZE && pid.pid > 0 {
pid.pid as u32
} else {
0
};
let resolved_uid = if cred.ret == 0 && cred.optlen >= XUCRED_MIN_RETURN {
cred.cr_uid
} else {
0
};
(resolved_pid, resolved_uid)
}
#[cfg(test)]
mod tests {
use super::*;
fn ok_token(pid: u32, euid: u32) -> TokenResult {
TokenResult {
ret: 0,
optlen: AUDIT_TOKEN_SIZE,
at_pid: pid,
at_euid: euid,
}
}
fn fail_token() -> TokenResult {
TokenResult {
ret: -1,
optlen: 0,
at_pid: 0,
at_euid: 0,
}
}
fn ok_pid(pid: i32) -> PidResult {
PidResult {
ret: 0,
optlen: I32_SIZE,
pid,
}
}
fn fail_pid() -> PidResult {
PidResult {
ret: -1,
optlen: 0,
pid: 0,
}
}
fn ok_cred(uid: u32) -> CredResult {
CredResult {
ret: 0,
optlen: XUCRED_MIN_RETURN,
cr_uid: uid,
}
}
fn fail_cred() -> CredResult {
CredResult {
ret: -1,
optlen: 0,
cr_uid: 0,
}
}
#[test]
fn token_success_wins_over_fallbacks() {
let result = pid_uid_from_results(ok_token(4321, 1500), ok_pid(9999), ok_cred(9999));
assert_eq!(result, (4321, 1500), "token success must be returned");
}
#[test]
fn token_short_return_falls_back_to_pid_and_cred() {
let short_token = TokenResult {
ret: 0,
optlen: AUDIT_TOKEN_SIZE - 1,
at_pid: 9999,
at_euid: 9999,
};
let result = pid_uid_from_results(short_token, ok_pid(4321), ok_cred(1500));
assert_eq!(result, (4321, 1500));
}
#[test]
fn token_fails_pid_succeeds_cred_succeeds() {
let result = pid_uid_from_results(fail_token(), ok_pid(4321), ok_cred(1500));
assert_eq!(result, (4321, 1500));
}
#[test]
fn token_fails_pid_zero_resolves_to_sentinel_pid() {
let result = pid_uid_from_results(fail_token(), ok_pid(0), ok_cred(1500));
assert_eq!(result, (0, 1500));
}
#[test]
fn token_fails_pid_negative_resolves_to_sentinel_pid() {
let result = pid_uid_from_results(fail_token(), ok_pid(-1), ok_cred(1500));
assert_eq!(result, (0, 1500));
}
#[test]
fn token_fails_pid_fails_cred_succeeds_returns_zero_pid() {
let result = pid_uid_from_results(fail_token(), fail_pid(), ok_cred(1500));
assert_eq!(result, (0, 1500));
}
#[test]
fn token_fails_pid_succeeds_cred_fails_returns_zero_uid() {
let result = pid_uid_from_results(fail_token(), ok_pid(4321), fail_cred());
assert_eq!(result, (4321, 0));
}
#[test]
fn all_three_fail_returns_zero_zero_sentinel() {
let result = pid_uid_from_results(fail_token(), fail_pid(), fail_cred());
assert_eq!(result, (0, 0));
}
}