1#![deny(warnings)]
8#![deny(missing_docs)]
9
10use std::ffi::CStr;
35use std::io;
36use std::os::raw::c_char;
37
38mod ffi;
39mod privileges;
40
41pub use crate::privileges::Privilege;
43
44pub enum PrivPtype {
46 Effective,
48 Inheritable,
50 Permitted,
52 Limit,
55}
56
57impl PrivPtype {
58 fn as_str(&self) -> &str {
59 match self {
60 PrivPtype::Effective => "Effective\0",
61 PrivPtype::Inheritable => "Inheritable\0",
62 PrivPtype::Permitted => "Permitted\0",
63 PrivPtype::Limit => "Limit\0",
64 }
65 }
66
67 fn as_ptr(&self) -> *const c_char {
68 CStr::from_bytes_with_nul(self.as_str().as_bytes())
69 .expect("all variants should be nul terminated")
70 .as_ptr()
71 }
72}
73
74#[repr(C)]
76pub enum PrivOp {
77 On = 0,
79 Off,
81 Set,
83}
84
85pub struct PrivSet {
88 inner: *mut ffi::OpaquePrivSet,
89}
90
91impl PrivSet {
92 pub fn new_empty() -> io::Result<Self> {
94 unsafe {
95 let inner = ptr_or_err(ffi::priv_allocset())?;
96 ffi::priv_emptyset(inner);
97 Ok(PrivSet { inner })
98 }
99 }
100
101 pub fn new_basic() -> io::Result<Self> {
104 unsafe {
105 let inner = ptr_or_err(ffi::priv_allocset())?;
106 ffi::priv_basicset(inner);
107 Ok(PrivSet { inner })
108 }
109 }
110
111 pub fn basic(&mut self) {
113 unsafe {
114 ffi::priv_basicset(self.inner);
115 }
116 }
117
118 pub fn empty(&mut self) {
120 unsafe {
121 ffi::priv_emptyset(self.inner);
122 }
123 }
124
125 pub fn addset(&mut self, p: Privilege) -> io::Result<()> {
127 unsafe { ret_or_err(ffi::priv_addset(self.inner, p.as_ptr())) }
128 }
129
130 pub fn delset(&mut self, p: Privilege) -> io::Result<()> {
132 unsafe { ret_or_err(ffi::priv_delset(self.inner, p.as_ptr())) }
133 }
134
135 pub fn is_empty(&self) -> bool {
137 unsafe { true_or_false(ffi::priv_isemptyset(self.inner)) }
138 }
139
140 pub fn is_member(&self, p: Privilege) -> bool {
142 unsafe { true_or_false(ffi::priv_ismember(self.inner, p.as_ptr())) }
143 }
144
145 pub fn is_equal(&self, dst: &PrivSet) -> bool {
147 unsafe { true_or_false(ffi::priv_isequalset(self.inner, dst.inner)) }
148 }
149}
150
151impl PartialEq for PrivSet {
152 fn eq(&self, other: &Self) -> bool {
153 self.is_equal(other)
154 }
155}
156
157pub fn setppriv(op: PrivOp, ptype: PrivPtype, sp: &PrivSet) -> io::Result<()> {
159 unsafe { ret_or_err(ffi::setppriv(op as i32, ptype.as_ptr(), sp.inner)) }
160}
161
162pub fn getppriv(ptype: PrivPtype) -> io::Result<PrivSet> {
164 unsafe {
165 let inner = ptr_or_err(ffi::priv_allocset())?;
166 let sp = PrivSet { inner };
169 ret_or_err(ffi::getppriv(ptype.as_ptr(), sp.inner))?;
170 Ok(sp)
171 }
172}
173
174impl Drop for PrivSet {
175 fn drop(&mut self) {
176 if !self.inner.is_null() {
177 unsafe {
178 ffi::priv_freeset(self.inner);
179 }
180 }
181 }
182}
183
184fn ptr_or_err<T>(ptr: *mut T) -> io::Result<*mut T> {
187 if ptr.is_null() {
188 Err(io::Error::last_os_error())
189 } else {
190 Ok(ptr)
191 }
192}
193
194fn ret_or_err(ret: i32) -> io::Result<()> {
195 match ret {
196 -1 => Err(io::Error::last_os_error()),
197 _ => Ok(()),
198 }
199}
200
201fn true_or_false(ret: i32) -> bool {
202 matches!(ret, 1)
203}
204
205#[cfg(test)]
208mod tests {
209 use super::*;
210 use std::process::Command;
211
212 #[test]
213 fn empty_set_test() {
214 let set = PrivSet::new_empty().unwrap();
215 assert_eq!(true, set.is_empty(), "set is empty");
216 }
217
218 #[test]
219 fn empty_test() {
220 let mut set = PrivSet::new_basic().unwrap();
221 assert_eq!(false, set.is_empty(), "set is not empty");
222 set.empty();
223 assert_eq!(true, set.is_empty(), "set is empty");
224 }
225
226 #[test]
227 fn is_equal_test() {
228 let src = PrivSet::new_basic().unwrap();
229 let mut dst = PrivSet::new_empty().unwrap();
230 assert_eq!(false, src.is_equal(&dst), "PrivSets are not equal");
231 dst.basic();
232 assert_eq!(true, src.is_equal(&dst), "PrivSets are equal");
233 assert!(src == dst, "PrivSets are equal");
235 }
236
237 #[test]
238 fn is_member_test() {
239 let set = PrivSet::new_basic().unwrap();
240 assert_eq!(
241 true,
242 set.is_member(Privilege::ProcFork),
243 "PRIV_PROC_FORK is in the set"
244 );
245 }
246
247 #[test]
248 fn add_priv_test() {
249 let mut set = PrivSet::new_empty().unwrap();
250 assert_eq!(
251 false,
252 set.is_member(Privilege::ProcFork),
253 "PRIV_PROC_FORK is not in the set"
254 );
255 let _ = set
256 .addset(Privilege::ProcFork)
257 .expect("failed to add to the set");
258 assert_eq!(
259 true,
260 set.is_member(Privilege::ProcFork),
261 "PRIV_PROC_FORK is in the set"
262 );
263 }
264
265 #[test]
266 fn del_priv_test() {
267 let mut set = PrivSet::new_basic().unwrap();
268 assert_eq!(
269 true,
270 set.is_member(Privilege::ProcFork),
271 "PRIV_PROC_FORK is in the set"
272 );
273 let _ = set
274 .delset(Privilege::ProcFork)
275 .expect("failed to delete from set");
276 assert_eq!(
277 false,
278 set.is_member(Privilege::ProcFork),
279 "PRIV_PROC_FORK is not in the set"
280 );
281 }
282
283 #[test]
284 fn getppriv_test() {
285 let orig = getppriv(PrivPtype::Effective).unwrap();
286 let mut src = PrivSet::new_basic().unwrap();
287 let _ = src
288 .delset(Privilege::ProcFork)
289 .expect("failed to delete from set");
290 setppriv(PrivOp::Set, PrivPtype::Effective, &src).unwrap();
291
292 let dst = getppriv(PrivPtype::Effective).unwrap();
293 assert!(src == dst, "getpprive PrivSet matches the one we just set");
294 setppriv(PrivOp::Set, PrivPtype::Effective, &orig).unwrap();
296 }
297
298 #[test]
299 fn drop_fork_test() {
300 let orig = getppriv(PrivPtype::Effective).unwrap();
301 let mut set = PrivSet::new_basic().unwrap();
302 let _ = set
303 .delset(Privilege::ProcFork)
304 .expect("failed to delete from set");
305
306 let res = Command::new("ls").output();
307 assert!(res.is_ok(), "successfully ran ls");
308
309 setppriv(PrivOp::Set, PrivPtype::Effective, &set).unwrap();
311
312 let res = Command::new("ls").output();
313 assert!(res.is_err(), "can no longer run ls");
314 let err = res.unwrap_err();
315 assert_eq!(
316 std::io::ErrorKind::PermissionDenied,
317 err.kind(),
318 "got permission denied when attempting to run ls"
319 );
320
321 setppriv(PrivOp::Set, PrivPtype::Effective, &orig).unwrap();
323 }
324}