1pub mod errors;
30pub mod runtime;
31pub mod securebits;
32
33mod ambient;
35mod base;
37mod bounding;
39mod nr;
41
42use crate::errors::CapsError;
43use std::iter::FromIterator;
44
45#[derive(Debug, Clone, Copy)]
50pub enum CapSet {
51 Ambient,
53 Bounding,
55 Effective,
57 Inheritable,
59 Permitted,
61}
62
63#[allow(clippy::manual_non_exhaustive)]
68#[allow(non_camel_case_types)]
69#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
70#[repr(u8)]
71#[cfg_attr(
72 feature = "serde_support",
73 derive(serde::Serialize, serde::Deserialize)
74)]
75pub enum Capability {
76 CAP_CHOWN = nr::CAP_CHOWN,
78 CAP_DAC_OVERRIDE = nr::CAP_DAC_OVERRIDE,
80 CAP_DAC_READ_SEARCH = nr::CAP_DAC_READ_SEARCH,
82 CAP_FOWNER = nr::CAP_FOWNER,
84 CAP_FSETID = nr::CAP_FSETID,
86 CAP_KILL = nr::CAP_KILL,
88 CAP_SETGID = nr::CAP_SETGID,
90 CAP_SETUID = nr::CAP_SETUID,
92 CAP_SETPCAP = nr::CAP_SETPCAP,
94 CAP_LINUX_IMMUTABLE = nr::CAP_LINUX_IMMUTABLE,
95 CAP_NET_BIND_SERVICE = nr::CAP_NET_BIND_SERVICE,
96 CAP_NET_BROADCAST = nr::CAP_NET_BROADCAST,
97 CAP_NET_ADMIN = nr::CAP_NET_ADMIN,
98 CAP_NET_RAW = nr::CAP_NET_RAW,
99 CAP_IPC_LOCK = nr::CAP_IPC_LOCK,
100 CAP_IPC_OWNER = nr::CAP_IPC_OWNER,
101 CAP_SYS_MODULE = nr::CAP_SYS_MODULE,
103 CAP_SYS_RAWIO = nr::CAP_SYS_RAWIO,
105 CAP_SYS_CHROOT = nr::CAP_SYS_CHROOT,
107 CAP_SYS_PTRACE = nr::CAP_SYS_PTRACE,
109 CAP_SYS_PACCT = nr::CAP_SYS_PACCT,
111 CAP_SYS_ADMIN = nr::CAP_SYS_ADMIN,
113 CAP_SYS_BOOT = nr::CAP_SYS_BOOT,
115 CAP_SYS_NICE = nr::CAP_SYS_NICE,
117 CAP_SYS_RESOURCE = nr::CAP_SYS_RESOURCE,
119 CAP_SYS_TIME = nr::CAP_SYS_TIME,
121 CAP_SYS_TTY_CONFIG = nr::CAP_SYS_TTY_CONFIG,
123 CAP_MKNOD = nr::CAP_MKNOD,
125 CAP_LEASE = nr::CAP_LEASE,
127 CAP_AUDIT_WRITE = nr::CAP_AUDIT_WRITE,
128 CAP_AUDIT_CONTROL = nr::CAP_AUDIT_CONTROL,
130 CAP_SETFCAP = nr::CAP_SETFCAP,
131 CAP_MAC_OVERRIDE = nr::CAP_MAC_OVERRIDE,
132 CAP_MAC_ADMIN = nr::CAP_MAC_ADMIN,
133 CAP_SYSLOG = nr::CAP_SYSLOG,
135 CAP_WAKE_ALARM = nr::CAP_WAKE_ALARM,
137 CAP_BLOCK_SUSPEND = nr::CAP_BLOCK_SUSPEND,
138 CAP_AUDIT_READ = nr::CAP_AUDIT_READ,
140 CAP_PERFMON = nr::CAP_PERFMON,
142 CAP_BPF = nr::CAP_BPF,
144 CAP_CHECKPOINT_RESTORE = nr::CAP_CHECKPOINT_RESTORE,
146 #[doc(hidden)]
147 __Nonexhaustive,
148}
149
150impl std::fmt::Display for Capability {
151 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
152 let name = match *self {
153 Capability::CAP_CHOWN => "CAP_CHOWN",
154 Capability::CAP_DAC_OVERRIDE => "CAP_DAC_OVERRIDE",
155 Capability::CAP_DAC_READ_SEARCH => "CAP_DAC_READ_SEARCH",
156 Capability::CAP_FOWNER => "CAP_FOWNER",
157 Capability::CAP_FSETID => "CAP_FSETID",
158 Capability::CAP_KILL => "CAP_KILL",
159 Capability::CAP_SETGID => "CAP_SETGID",
160 Capability::CAP_SETUID => "CAP_SETUID",
161 Capability::CAP_SETPCAP => "CAP_SETPCAP",
162 Capability::CAP_LINUX_IMMUTABLE => "CAP_LINUX_IMMUTABLE",
163 Capability::CAP_NET_BIND_SERVICE => "CAP_NET_BIND_SERVICE",
164 Capability::CAP_NET_BROADCAST => "CAP_NET_BROADCAST",
165 Capability::CAP_NET_ADMIN => "CAP_NET_ADMIN",
166 Capability::CAP_NET_RAW => "CAP_NET_RAW",
167 Capability::CAP_IPC_LOCK => "CAP_IPC_LOCK",
168 Capability::CAP_IPC_OWNER => "CAP_IPC_OWNER",
169 Capability::CAP_SYS_MODULE => "CAP_SYS_MODULE",
170 Capability::CAP_SYS_RAWIO => "CAP_SYS_RAWIO",
171 Capability::CAP_SYS_CHROOT => "CAP_SYS_CHROOT",
172 Capability::CAP_SYS_PTRACE => "CAP_SYS_PTRACE",
173 Capability::CAP_SYS_PACCT => "CAP_SYS_PACCT",
174 Capability::CAP_SYS_ADMIN => "CAP_SYS_ADMIN",
175 Capability::CAP_SYS_BOOT => "CAP_SYS_BOOT",
176 Capability::CAP_SYS_NICE => "CAP_SYS_NICE",
177 Capability::CAP_SYS_RESOURCE => "CAP_SYS_RESOURCE",
178 Capability::CAP_SYS_TIME => "CAP_SYS_TIME",
179 Capability::CAP_SYS_TTY_CONFIG => "CAP_SYS_TTY_CONFIG",
180 Capability::CAP_MKNOD => "CAP_MKNOD",
181 Capability::CAP_LEASE => "CAP_LEASE",
182 Capability::CAP_AUDIT_WRITE => "CAP_AUDIT_WRITE",
183 Capability::CAP_AUDIT_CONTROL => "CAP_AUDIT_CONTROL",
184 Capability::CAP_SETFCAP => "CAP_SETFCAP",
185 Capability::CAP_MAC_OVERRIDE => "CAP_MAC_OVERRIDE",
186 Capability::CAP_MAC_ADMIN => "CAP_MAC_ADMIN",
187 Capability::CAP_SYSLOG => "CAP_SYSLOG",
188 Capability::CAP_WAKE_ALARM => "CAP_WAKE_ALARM",
189 Capability::CAP_BLOCK_SUSPEND => "CAP_BLOCK_SUSPEND",
190 Capability::CAP_AUDIT_READ => "CAP_AUDIT_READ",
191 Capability::CAP_PERFMON => "CAP_PERFMON",
192 Capability::CAP_BPF => "CAP_BPF",
193 Capability::CAP_CHECKPOINT_RESTORE => "CAP_CHECKPOINT_RESTORE",
194 Capability::__Nonexhaustive => unreachable!("invalid capability"),
195 };
196 write!(f, "{}", name)
197 }
198}
199
200impl std::str::FromStr for Capability {
201 type Err = CapsError;
202
203 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
204 match s {
205 "CAP_CHOWN" => Ok(Capability::CAP_CHOWN),
206 "CAP_DAC_OVERRIDE" => Ok(Capability::CAP_DAC_OVERRIDE),
207 "CAP_DAC_READ_SEARCH" => Ok(Capability::CAP_DAC_READ_SEARCH),
208 "CAP_FOWNER" => Ok(Capability::CAP_FOWNER),
209 "CAP_FSETID" => Ok(Capability::CAP_FSETID),
210 "CAP_KILL" => Ok(Capability::CAP_KILL),
211 "CAP_SETGID" => Ok(Capability::CAP_SETGID),
212 "CAP_SETUID" => Ok(Capability::CAP_SETUID),
213 "CAP_SETPCAP" => Ok(Capability::CAP_SETPCAP),
214 "CAP_LINUX_IMMUTABLE" => Ok(Capability::CAP_LINUX_IMMUTABLE),
215 "CAP_NET_BIND_SERVICE" => Ok(Capability::CAP_NET_BIND_SERVICE),
216 "CAP_NET_BROADCAST" => Ok(Capability::CAP_NET_BROADCAST),
217 "CAP_NET_ADMIN" => Ok(Capability::CAP_NET_ADMIN),
218 "CAP_NET_RAW" => Ok(Capability::CAP_NET_RAW),
219 "CAP_IPC_LOCK" => Ok(Capability::CAP_IPC_LOCK),
220 "CAP_IPC_OWNER" => Ok(Capability::CAP_IPC_OWNER),
221 "CAP_SYS_MODULE" => Ok(Capability::CAP_SYS_MODULE),
222 "CAP_SYS_RAWIO" => Ok(Capability::CAP_SYS_RAWIO),
223 "CAP_SYS_CHROOT" => Ok(Capability::CAP_SYS_CHROOT),
224 "CAP_SYS_PTRACE" => Ok(Capability::CAP_SYS_PTRACE),
225 "CAP_SYS_PACCT" => Ok(Capability::CAP_SYS_PACCT),
226 "CAP_SYS_ADMIN" => Ok(Capability::CAP_SYS_ADMIN),
227 "CAP_SYS_BOOT" => Ok(Capability::CAP_SYS_BOOT),
228 "CAP_SYS_NICE" => Ok(Capability::CAP_SYS_NICE),
229 "CAP_SYS_RESOURCE" => Ok(Capability::CAP_SYS_RESOURCE),
230 "CAP_SYS_TIME" => Ok(Capability::CAP_SYS_TIME),
231 "CAP_SYS_TTY_CONFIG" => Ok(Capability::CAP_SYS_TTY_CONFIG),
232 "CAP_MKNOD" => Ok(Capability::CAP_MKNOD),
233 "CAP_LEASE" => Ok(Capability::CAP_LEASE),
234 "CAP_AUDIT_WRITE" => Ok(Capability::CAP_AUDIT_WRITE),
235 "CAP_AUDIT_CONTROL" => Ok(Capability::CAP_AUDIT_CONTROL),
236 "CAP_SETFCAP" => Ok(Capability::CAP_SETFCAP),
237 "CAP_MAC_OVERRIDE" => Ok(Capability::CAP_MAC_OVERRIDE),
238 "CAP_MAC_ADMIN" => Ok(Capability::CAP_MAC_ADMIN),
239 "CAP_SYSLOG" => Ok(Capability::CAP_SYSLOG),
240 "CAP_WAKE_ALARM" => Ok(Capability::CAP_WAKE_ALARM),
241 "CAP_BLOCK_SUSPEND" => Ok(Capability::CAP_BLOCK_SUSPEND),
242 "CAP_AUDIT_READ" => Ok(Capability::CAP_AUDIT_READ),
243 "CAP_PERFMON" => Ok(Capability::CAP_PERFMON),
244 "CAP_BPF" => Ok(Capability::CAP_BPF),
245 "CAP_CHECKPOINT_RESTORE" => Ok(Capability::CAP_CHECKPOINT_RESTORE),
246 _ => Err(format!("invalid capability: {}", s).into()),
247 }
248 }
249}
250
251impl Capability {
252 #[allow(clippy::trivially_copy_pass_by_ref)]
254 pub fn bitmask(&self) -> u64 {
255 1u64 << (*self as u8)
256 }
257
258 #[allow(clippy::trivially_copy_pass_by_ref)]
260 pub fn index(&self) -> u8 {
261 *self as u8
262 }
263}
264
265pub type CapsHashSet = std::collections::HashSet<Capability>;
267
268pub fn has_cap(tid: Option<i32>, cset: CapSet, cap: Capability) -> Result<bool, CapsError> {
274 let t = tid.unwrap_or(0);
275 match cset {
276 CapSet::Ambient if t == 0 => ambient::has_cap(cap),
277 CapSet::Bounding if t == 0 => bounding::has_cap(cap),
278 CapSet::Effective | CapSet::Inheritable | CapSet::Permitted => base::has_cap(t, cset, cap),
279 _ => Err("operation not supported".into()),
280 }
281}
282
283pub fn read(tid: Option<i32>, cset: CapSet) -> Result<CapsHashSet, CapsError> {
289 let t = tid.unwrap_or(0);
290 match cset {
291 CapSet::Ambient if t == 0 => ambient::read(),
292 CapSet::Bounding if t == 0 => bounding::read(),
293 CapSet::Effective | CapSet::Inheritable | CapSet::Permitted => base::read(t, cset),
294 _ => Err("operation not supported".into()),
295 }
296}
297
298pub fn set(tid: Option<i32>, cset: CapSet, value: &CapsHashSet) -> Result<(), CapsError> {
305 let t = tid.unwrap_or(0);
306 match cset {
307 CapSet::Ambient if t == 0 => ambient::set(value),
308 CapSet::Effective | CapSet::Inheritable | CapSet::Permitted => base::set(t, cset, value),
309 _ => Err("operation not supported".into()),
310 }
311}
312
313pub fn clear(tid: Option<i32>, cset: CapSet) -> Result<(), CapsError> {
319 let t = tid.unwrap_or(0);
320 match cset {
321 CapSet::Ambient if t == 0 => ambient::clear(),
322 CapSet::Bounding if t == 0 => bounding::clear(),
323 CapSet::Effective | CapSet::Permitted | CapSet::Inheritable => base::clear(t, cset),
324 _ => Err("operation not supported".into()),
325 }
326}
327
328pub fn raise(tid: Option<i32>, cset: CapSet, cap: Capability) -> Result<(), CapsError> {
335 let t = tid.unwrap_or(0);
336 match cset {
337 CapSet::Ambient if t == 0 => ambient::raise(cap),
338 CapSet::Effective | CapSet::Permitted | CapSet::Inheritable => base::raise(t, cset, cap),
339 _ => Err("operation not supported".into()),
340 }
341}
342
343pub fn drop(tid: Option<i32>, cset: CapSet, cap: Capability) -> Result<(), CapsError> {
349 let t = tid.unwrap_or(0);
350 match cset {
351 CapSet::Ambient if t == 0 => ambient::drop(cap),
352 CapSet::Bounding if t == 0 => bounding::drop(cap),
353 CapSet::Effective | CapSet::Permitted | CapSet::Inheritable => base::drop(t, cset, cap),
354 _ => Err("operation not supported".into()),
355 }
356}
357
358pub fn all() -> CapsHashSet {
360 let slice = vec![
361 Capability::CAP_CHOWN,
362 Capability::CAP_DAC_OVERRIDE,
363 Capability::CAP_DAC_READ_SEARCH,
364 Capability::CAP_FOWNER,
365 Capability::CAP_FSETID,
366 Capability::CAP_KILL,
367 Capability::CAP_SETGID,
368 Capability::CAP_SETUID,
369 Capability::CAP_SETPCAP,
370 Capability::CAP_LINUX_IMMUTABLE,
371 Capability::CAP_NET_BIND_SERVICE,
372 Capability::CAP_NET_BROADCAST,
373 Capability::CAP_NET_ADMIN,
374 Capability::CAP_NET_RAW,
375 Capability::CAP_IPC_LOCK,
376 Capability::CAP_IPC_OWNER,
377 Capability::CAP_SYS_MODULE,
378 Capability::CAP_SYS_RAWIO,
379 Capability::CAP_SYS_CHROOT,
380 Capability::CAP_SYS_PTRACE,
381 Capability::CAP_SYS_PACCT,
382 Capability::CAP_SYS_ADMIN,
383 Capability::CAP_SYS_BOOT,
384 Capability::CAP_SYS_NICE,
385 Capability::CAP_SYS_RESOURCE,
386 Capability::CAP_SYS_TIME,
387 Capability::CAP_SYS_TTY_CONFIG,
388 Capability::CAP_MKNOD,
389 Capability::CAP_LEASE,
390 Capability::CAP_AUDIT_WRITE,
391 Capability::CAP_AUDIT_CONTROL,
392 Capability::CAP_SETFCAP,
393 Capability::CAP_MAC_OVERRIDE,
394 Capability::CAP_MAC_ADMIN,
395 Capability::CAP_SYSLOG,
396 Capability::CAP_WAKE_ALARM,
397 Capability::CAP_BLOCK_SUSPEND,
398 Capability::CAP_AUDIT_READ,
399 Capability::CAP_PERFMON,
400 Capability::CAP_BPF,
401 Capability::CAP_CHECKPOINT_RESTORE,
402 ];
403 CapsHashSet::from_iter(slice)
404}
405
406pub fn to_canonical(name: &str) -> String {
415 let uppername = name.to_uppercase();
416 if uppername.starts_with("CAP_") {
417 uppername
418 } else {
419 ["CAP_", &uppername].concat()
420 }
421}
422
423#[cfg(test)]
424mod tests {
425 use super::*;
426 use std::str::FromStr;
427
428 #[test]
429 fn test_all_roundtrip() {
430 let all = all();
431 assert!(all.len() > 0);
432 for c in all {
433 let name = c.to_string();
434 let parsed: Capability = name.parse().unwrap();
435 assert_eq!(c, parsed);
436 }
437 }
438
439 #[test]
440 fn test_parse_invalid() {
441 let p1 = Capability::from_str("CAP_FOO");
442 let p1_err = p1.unwrap_err();
443 assert!(p1_err.to_string().contains("invalid"));
444 assert!(format!("{}", p1_err).contains("CAP_FOO"));
445 let p2: Result<Capability, CapsError> = "CAP_BAR".parse();
446 assert!(p2.is_err());
447 }
448
449 #[test]
450 fn test_to_canonical() {
451 let p1 = "foo";
452 assert!(Capability::from_str(&to_canonical(p1)).is_err());
453 let p2 = "sys_admin";
454 assert!(Capability::from_str(&to_canonical(p2)).is_ok());
455 let p3 = "CAP_SYS_CHROOT";
456 assert!(Capability::from_str(&to_canonical(p3)).is_ok());
457 }
458
459 #[test]
460 #[cfg(feature = "serde_support")]
461 fn test_serde() {
462 let p1 = Capability::from_str("CAP_CHOWN").unwrap();
463 let ser = serde_json::to_value(&p1).unwrap();
464 let deser: Capability = serde_json::from_value(ser).unwrap();
465 assert_eq!(deser, p1);
466 }
467}