use std::os::raw::c_int;
use crate::Error;
use crate::ffi::{self, Data, Header};
use crate::set::Set;
use crate::sys::{Cmd, ambient, bounding, capget, capset};
#[repr(u8)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Cap {
Chown = ffi::CAP_CHOWN,
DacOverride = ffi::CAP_DAC_OVERRIDE,
DacReadSearch = ffi::CAP_DAC_READ_SEARCH,
FOwner = ffi::CAP_FOWNER,
FSetId = ffi::CAP_FSETID,
Kill = ffi::CAP_KILL,
SetGid = ffi::CAP_SETGID,
SetUid = ffi::CAP_SETUID,
SetPcap = ffi::CAP_SETPCAP,
LinuxImmutable = ffi::CAP_LINUX_IMMUTABLE,
NetBindService = ffi::CAP_NET_BIND_SERVICE,
NetBroadcast = ffi::CAP_NET_BROADCAST,
NetAdmin = ffi::CAP_NET_ADMIN,
NetRaw = ffi::CAP_NET_RAW,
IpcLock = ffi::CAP_IPC_LOCK,
IpcOwner = ffi::CAP_IPC_OWNER,
SysModule = ffi::CAP_SYS_MODULE,
SysRawIO = ffi::CAP_SYS_RAWIO,
SysChroot = ffi::CAP_SYS_CHROOT,
SysPtrace = ffi::CAP_SYS_PTRACE,
SysPacct = ffi::CAP_SYS_PACCT,
SysAdmin = ffi::CAP_SYS_ADMIN,
SysBoot = ffi::CAP_SYS_BOOT,
SysNice = ffi::CAP_SYS_NICE,
SysResource = ffi::CAP_SYS_RESOURCE,
SysTime = ffi::CAP_SYS_TIME,
SysTTYConfig = ffi::CAP_SYS_TTY_CONFIG,
Mknod = ffi::CAP_MKNOD,
Lease = ffi::CAP_LEASE,
AuditWrite = ffi::CAP_AUDIT_WRITE,
AuditControl = ffi::CAP_AUDIT_CONTROL,
Setfcap = ffi::CAP_SETFCAP,
MacOverride = ffi::CAP_MAC_OVERRIDE,
MacAdmin = ffi::CAP_MAC_ADMIN,
Syslog = ffi::CAP_SYSLOG,
WakeAlarm = ffi::CAP_WAKE_ALARM,
BlockSuspend = ffi::CAP_BLOCK_SUSPEND,
AuditRead = ffi::CAP_AUDIT_READ,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Caps {
pub effective: Set,
pub permitted: Set,
pub inheritable: Set,
}
pub struct Ambient;
pub struct Bounding;
impl Caps {
pub fn empty() -> Self {
Self {
effective: Set::empty(),
permitted: Set::empty(),
inheritable: Set::empty(),
}
}
pub fn get() -> Result<Self, Error> {
Self::fetch(0)
}
pub fn set(&self) -> Result<(), Error> {
self.apply(0)
}
pub fn fetch(pid: c_int) -> Result<Self, Error> {
let head = Header::v3(pid);
let mut data = data();
capget(&head, &mut data)?;
Ok(Self::from(data))
}
pub fn apply(&self, pid: c_int) -> Result<(), Error> {
let head = Header::v3(pid);
let mut data = data();
self.shift(&mut data);
Ok(capset(&head, &data)?)
}
pub fn shift(&self, [low, high]: &mut [Data; 2]) {
self.effective.shift(&mut high.effective, &mut low.effective);
self.permitted.shift(&mut high.permitted, &mut low.permitted);
self.inheritable.shift(&mut high.inheritable, &mut low.inheritable);
}
}
impl Ambient {
pub fn raise(cap: Cap) -> Result<(), Error> {
ambient(Cmd::AMBIENT_RAISE, cap)?;
Ok(())
}
pub fn lower(cap: Cap) -> Result<(), Error> {
ambient(Cmd::AMBIENT_LOWER, cap)?;
Ok(())
}
pub fn is_set(cap: Cap) -> Result<bool, Error> {
Ok(ambient(Cmd::AMBIENT_IS_SET, cap)? == 1)
}
pub fn clear_all() -> Result<(), Error> {
ambient(Cmd::AMBIENT_CLEAR_ALL, 0)?;
Ok(())
}
}
impl Bounding {
pub fn read(cap: Cap) -> Result<bool, Error> {
Ok(bounding(Cmd::BOUNDING_READ, cap)? == 1)
}
pub fn drop(cap: Cap) -> Result<(), Error> {
bounding(Cmd::BOUNDING_DROP, cap)?;
Ok(())
}
}
impl From<Cap> for u64 {
fn from(cap: Cap) -> u64 {
1 << u64::from(cap as u8)
}
}
impl From<Cap> for c_int {
fn from(cap: Cap) -> c_int {
c_int::from(cap as u8)
}
}
impl From<[Data; 2]> for Caps {
fn from([low, high]: [Data; 2]) -> Self {
Self {
effective: Set::from((high.effective, low.effective)),
permitted: Set::from((high.permitted, low.permitted)),
inheritable: Set::from((high.inheritable, low.inheritable)),
}
}
}
fn data() -> [Data; 2] {
Default::default()
}
#[test]
fn test() -> Result<(), Error> {
let effective = Caps::get()?.effective;
assert!(!effective.contains(Cap::SysAdmin));
assert!(!Ambient::is_set(Cap::SysAdmin)?);
assert!(Bounding::read(Cap::SysAdmin)?);
Ok(())
}