1#[cfg(test)]
2mod tests {
3 #[test]
4 fn it_works() {
5 use crate::*;
6 let mut acl = Acl::init(10).unwrap();
7 assert_eq!(acl.valid().unwrap(), Some(nix::errno::Errno::EINVAL));
8
9 let mut entry = acl.create_entry().unwrap();
10 let tag = AclTag::UserObj;
11 entry.set_tag_type(&tag).unwrap();
12 let mut permset = entry.get_permset().unwrap();
13 permset.add_perm(AclPerm::Read).unwrap();
14 assert_eq!(entry.get_tag_type().unwrap(), tag);
15
16 let mut entry = acl.create_entry().unwrap();
17 let tag = AclTag::GroupObj;
18 entry.set_tag_type(&tag).unwrap();
19 let mut permset = entry.get_permset().unwrap();
20 permset.add_perm(AclPerm::Write).unwrap();
21 assert_eq!(entry.get_tag_type().unwrap(), tag);
22
23 let mut entry = acl.create_entry().unwrap();
24 let tag = AclTag::Other;
25 entry.set_tag_type(&tag).unwrap();
26 let mut permset = entry.get_permset().unwrap();
27 permset.add_perm(AclPerm::Execute).unwrap();
28 assert_eq!(entry.get_tag_type().unwrap(), tag);
29
30 let mut entry = acl.create_entry().unwrap();
31 let tag = AclTag::User;
32 entry.set_tag_type(&tag).unwrap();
33 entry
34 .set_qualifier(&Qualifier::User(nix::unistd::Uid::from_raw(0)))
35 .unwrap();
36 let mut permset = entry.get_permset().unwrap();
37 permset.add_perm(AclPerm::Execute).unwrap();
38 permset.add_perm(AclPerm::Read).unwrap();
39 permset.add_perm(AclPerm::Write).unwrap();
40 assert_eq!(entry.get_tag_type().unwrap(), tag);
41
42 acl.calc_mask().unwrap();
44 assert_eq!(entry.get_tag_type().unwrap(), tag);
45 assert_eq!(acl.valid().unwrap(), None);
46
47 let path = std::path::PathBuf::from("./file_to_test_acls");
48 if !path.exists() {
49 std::fs::File::create(&path).unwrap();
50 }
51 acl.set_for_file(&path, &AclType::TypeAccess).unwrap();
52
53 let new_acl = Acl::for_file(&path, &AclType::TypeAccess).unwrap();
54 std::fs::remove_file(&path).unwrap();
55 let new_alc_str = String::from_utf8(new_acl.to_text().unwrap()).unwrap();
56 assert_eq!(
57 "user::r--\nuser:root:rwx\ngroup::-w-\nmask::rwx\nother::--x\n",
58 &new_alc_str
59 );
60
61 let entry1 = new_acl.get_entry(&EntryId::FirstEntry).unwrap().unwrap();
64 let _permset1 = entry1.get_permset().unwrap();
65
66 let entry2 = new_acl.get_entry(&EntryId::NextEntry).unwrap().unwrap();
67 let _permset2 = entry2.get_permset().unwrap();
68
69 let entry3 = new_acl.get_entry(&EntryId::NextEntry).unwrap().unwrap();
70 let _permset3 = entry3.get_permset().unwrap();
71
72 let entry4 = new_acl.get_entry(&EntryId::NextEntry).unwrap().unwrap();
73 let _permset4 = entry4.get_permset().unwrap();
74
75 let entry5 = new_acl.get_entry(&EntryId::NextEntry).unwrap().unwrap();
76 let _permset5 = entry5.get_permset().unwrap();
77
78 let err_entry = new_acl.get_entry(&EntryId::NextEntry).unwrap();
79 assert_eq!(err_entry, None);
80 }
81}
82
83extern crate acl_sys;
84extern crate nix;
85
86use std::cell::RefCell;
87use std::rc::Rc;
88
89#[derive(PartialEq, Eq, Debug)]
90pub struct AclEntry {
91 raw_ptr: acl_sys::acl_entry_t,
92 is_valid: Rc<RefCell<bool>>,
94}
95
96pub enum AclPerm {
97 Read,
98 Write,
99 Execute,
100}
101
102impl AclPerm {
103 pub fn to_raw(&self) -> u32 {
104 match self {
105 AclPerm::Read => acl_sys::ACL_READ,
106 AclPerm::Write => acl_sys::ACL_WRITE,
107 AclPerm::Execute => acl_sys::ACL_EXECUTE,
108 }
109 }
110}
111
112pub struct AclPermSet {
113 raw_ptr: acl_sys::acl_permset_t,
114 is_valid: Rc<RefCell<bool>>,
116}
117
118#[derive(Copy, Clone, PartialEq, Eq, Debug)]
119pub enum AclType {
120 TypeAccess,
121 TypeDefault,
122}
123
124impl AclType {
125 pub fn to_raw(&self) -> u32 {
126 match self {
127 AclType::TypeAccess => acl_sys::ACL_TYPE_ACCESS,
128 AclType::TypeDefault => acl_sys::ACL_TYPE_DEFAULT,
129 }
130 }
131}
132
133#[derive(Copy, Clone, PartialEq, Eq, Debug)]
134pub enum AclTag {
135 UserObj,
136 User,
137 GroupObj,
138 Group,
139 Mask,
140 Other,
141 Invalid,
142}
143
144impl AclTag {
145 pub fn to_raw(&self) -> i32 {
146 match self {
147 AclTag::UserObj => acl_sys::ACL_USER_OBJ,
148 AclTag::User => acl_sys::ACL_USER,
149 AclTag::GroupObj => acl_sys::ACL_GROUP_OBJ,
150 AclTag::Group => acl_sys::ACL_GROUP,
151 AclTag::Mask => acl_sys::ACL_MASK,
152 AclTag::Other => acl_sys::ACL_OTHER,
153 AclTag::Invalid => acl_sys::ACL_UNDEFINED_TAG,
154 }
155 }
156 pub fn from_raw(raw: i32) -> Self {
157 match raw {
158 acl_sys::ACL_USER_OBJ => AclTag::UserObj,
159 acl_sys::ACL_USER => AclTag::User,
160 acl_sys::ACL_GROUP_OBJ => AclTag::GroupObj,
161 acl_sys::ACL_GROUP => AclTag::Group,
162 acl_sys::ACL_MASK => AclTag::Mask,
163 acl_sys::ACL_OTHER => AclTag::Other,
164 _ => AclTag::Invalid,
165 }
166 }
167}
168
169#[derive(Debug)]
170pub struct Acl {
171 raw_ptr: acl_sys::acl_t,
172
173 is_valid: Rc<RefCell<bool>>,
176}
177
178#[derive(Clone, Copy, Debug)]
179pub enum AclError {
180 Errno(nix::errno::Errno),
181 UnknownReturn(i32),
182 WasMoved,
183}
184
185#[derive(Clone, Copy, Debug)]
186pub enum EntryId {
187 NextEntry,
188 FirstEntry,
189}
190
191pub enum Qualifier {
192 User(nix::unistd::Uid),
193 Group(nix::unistd::Gid),
194}
195
196impl EntryId {
197 fn to_raw(&self) -> i32 {
198 match self {
199 EntryId::NextEntry => 1,
201 EntryId::FirstEntry => 0,
202 }
203 }
204}
205
206impl Acl {
207 pub fn init(count: i32) -> Result<Self, AclError> {
208 let raw_ptr = unsafe { acl_sys::acl_init(count as i32) };
209 if raw_ptr.is_null() {
210 let errno = nix::errno::errno();
211 Err(AclError::Errno(nix::errno::from_i32(errno)))
212 } else {
213 Ok(Acl {
214 raw_ptr,
215 is_valid: Rc::new(RefCell::new(true)),
216 })
217 }
218 }
219
220 pub fn from_text(text: &str) -> Result<Self, AclError> {
221 let text_i8 = text.bytes().map(|x| x as i8).collect::<Vec<_>>();
222 let raw_ptr = unsafe { acl_sys::acl_from_text(text_i8.as_ptr()) };
223 if raw_ptr.is_null() {
224 let errno = nix::errno::errno();
225 Err(AclError::Errno(nix::errno::from_i32(errno)))
226 } else {
227 Ok(Acl {
228 raw_ptr,
229 is_valid: Rc::new(RefCell::new(true)),
230 })
231 }
232 }
233
234 pub fn to_text(&self) -> Result<Vec<u8>, AclError> {
235 let mut len = 0;
236 let raw_text = unsafe { acl_sys::acl_to_text(self.raw_ptr, &mut len) };
237
238 if raw_text.is_null() {
239 let errno = nix::errno::errno();
240 Err(AclError::Errno(nix::errno::from_i32(errno)))
241 } else {
242 let mut text_bytes = Vec::new();
243 let mut iter_ptr = raw_text;
244 for _idx in 0..len {
245 let byte = unsafe { *iter_ptr } as u8;
246 text_bytes.push(byte);
247 iter_ptr = unsafe { iter_ptr.add(1) };
248 }
249
250 unsafe { acl_sys::acl_free(std::mem::transmute(raw_text)) };
251
252 Ok(text_bytes)
253 }
254 }
255
256 pub fn for_fd(fd: i32) -> Result<Self, AclError> {
257 let raw_ptr = unsafe { acl_sys::acl_get_fd(fd) };
258 if raw_ptr.is_null() {
259 let errno = nix::errno::errno();
260 Err(AclError::Errno(nix::errno::from_i32(errno)))
261 } else {
262 Ok(Acl {
263 raw_ptr,
264 is_valid: Rc::new(RefCell::new(true)),
265 })
266 }
267 }
268
269 pub fn set_for_fd(&self, fd: i32) -> Result<(), AclError> {
270 let result = unsafe { acl_sys::acl_set_fd(fd, self.raw_ptr) };
271 match result {
272 0 => Ok(()),
273 -1 => {
274 let errno = nix::errno::errno();
275 Err(AclError::Errno(nix::errno::from_i32(errno)))
276 }
277 _ => Err(AclError::UnknownReturn(result)),
278 }
279 }
280
281 pub fn for_file(file_path: &std::path::PathBuf, typ: &AclType) -> Result<Self, AclError> {
282 use std::os::unix::ffi::OsStrExt;
283 let path_bytes = file_path.as_os_str().as_bytes().to_vec();
284 let path_i8 = path_bytes.into_iter().map(|x| x as i8).collect::<Vec<_>>();
285 let raw_ptr = unsafe { acl_sys::acl_get_file(path_i8.as_ptr(), typ.to_raw()) };
286 if raw_ptr.is_null() {
287 let errno = nix::errno::errno();
288 Err(AclError::Errno(nix::errno::from_i32(errno)))
289 } else {
290 Ok(Acl {
291 raw_ptr,
292 is_valid: Rc::new(RefCell::new(true)),
293 })
294 }
295 }
296
297 pub fn set_for_file(
298 &self,
299 file_path: &std::path::PathBuf,
300 typ: &AclType,
301 ) -> Result<(), AclError> {
302 use std::os::unix::ffi::OsStrExt;
303 let path_bytes = file_path.as_os_str().as_bytes().to_vec();
304 let path_i8 = path_bytes.into_iter().map(|x| x as i8).collect::<Vec<_>>();
305 let result = unsafe { acl_sys::acl_set_file(path_i8.as_ptr(), typ.to_raw(), self.raw_ptr) };
306 match result {
307 0 => Ok(()),
308 -1 => {
309 let errno = nix::errno::errno();
310 Err(AclError::Errno(nix::errno::from_i32(errno)))
311 }
312 _ => Err(AclError::UnknownReturn(result)),
313 }
314 }
315
316 pub fn get_entry(&self, id: &EntryId) -> Result<Option<AclEntry>, AclError> {
317 let mut entry_ptr = std::ptr::null_mut();
318 let entry_ptr_ptr = &mut entry_ptr as *mut acl_sys::acl_entry_t;
319 let result = unsafe { acl_sys::acl_get_entry(self.raw_ptr, id.to_raw(), entry_ptr_ptr) };
320
321 match result {
322 0 => Ok(None),
323 1 => Ok(Some(AclEntry {
324 raw_ptr: entry_ptr,
325 is_valid: self.is_valid.clone(),
326 })),
327 -1 => {
328 let errno = nix::errno::errno();
329 Err(AclError::Errno(nix::errno::from_i32(errno)))
330 }
331 _ => Err(AclError::UnknownReturn(result)),
332 }
333 }
334
335 pub fn create_entry(&mut self) -> Result<AclEntry, AclError> {
340 let mut entry_ptr = std::ptr::null_mut();
341 let entry_ptr_ptr = &mut entry_ptr as *mut acl_sys::acl_entry_t;
342
343 let acl_ptr_before = self.raw_ptr;
344 let result = unsafe { acl_sys::acl_create_entry(&mut self.raw_ptr, entry_ptr_ptr) };
345
346 if !acl_ptr_before.eq(&self.raw_ptr) {
347 *self.is_valid.borrow_mut() = false;
349 self.is_valid = Rc::new(RefCell::new(true));
351 }
352
353 match result {
354 0 => Ok(AclEntry {
355 raw_ptr: entry_ptr,
356 is_valid: self.is_valid.clone(),
357 }),
358 -1 => {
359 let errno = nix::errno::errno();
360 Err(AclError::Errno(nix::errno::from_i32(errno)))
361 }
362 _ => Err(AclError::UnknownReturn(result)),
363 }
364 }
365
366 pub fn delete_entry(&mut self, entry: AclEntry) -> Result<(), (AclEntry, AclError)> {
368 let result = unsafe { acl_sys::acl_delete_entry(self.raw_ptr, entry.raw_ptr) };
369
370 match result {
371 0 => Ok(()),
372 -1 => {
373 let errno = nix::errno::errno();
374 Err((entry, AclError::Errno(nix::errno::from_i32(errno))))
375 }
376 _ => Err((entry, AclError::UnknownReturn(result))),
377 }
378 }
379
380 pub fn free(mut self) -> Result<(), (Self, AclError)> {
383 let result = unsafe { acl_sys::acl_free(self.raw_ptr) };
384 match result {
385 0 => {
386 self.raw_ptr = std::ptr::null_mut();
387 Ok(())
388 }
389 -1 => {
390 let errno = nix::errno::errno();
391 Err((self, AclError::Errno(nix::errno::from_i32(errno))))
392 }
393 _ => Err((self, AclError::UnknownReturn(result))),
394 }
395 }
396
397 pub fn calc_mask(&mut self) -> Result<(), AclError> {
398 let result = unsafe { acl_sys::acl_calc_mask(&mut self.raw_ptr) };
399 match result {
400 0 => Ok(()),
401 -1 => {
402 let errno = nix::errno::errno();
403 Err(AclError::Errno(nix::errno::from_i32(errno)))
404 }
405 _ => Err(AclError::UnknownReturn(result)),
406 }
407 }
408
409 pub fn dup(&self) -> Result<Acl, AclError> {
410 let new_acl = unsafe { acl_sys::acl_dup(self.raw_ptr) };
411
412 if new_acl.is_null() {
413 let errno = nix::errno::errno();
414 Err(AclError::Errno(nix::errno::from_i32(errno)))
415 } else {
416 Ok(Acl {
417 raw_ptr: new_acl,
418 is_valid: self.is_valid.clone(),
419 })
420 }
421 }
422
423 pub fn size(&self) -> Result<usize, AclError> {
424 let result = unsafe { acl_sys::acl_size(self.raw_ptr) };
425 match result {
426 -1 => {
427 let errno = nix::errno::errno();
428 Err(AclError::Errno(nix::errno::from_i32(errno)))
429 }
430 _ => Ok(result as usize),
431 }
432 }
433
434 pub fn valid(&self) -> Result<Option<nix::errno::Errno>, AclError> {
435 let result = unsafe { acl_sys::acl_valid(self.raw_ptr) };
436 match result {
437 0 => Ok(None),
438 -1 => Ok(Some(nix::errno::from_i32(nix::errno::errno()))),
439 _ => Err(AclError::UnknownReturn(result)),
440 }
441 }
442}
443
444impl Drop for Acl {
445 fn drop(&mut self) {
446 unsafe { acl_sys::acl_free(self.raw_ptr) };
447 self.raw_ptr = std::ptr::null_mut();
448 }
449}
450
451impl AclPermSet {
452 pub fn check_valid(&self) -> Result<(), AclError> {
453 if *self.is_valid.borrow() == true {
454 Ok(())
455 } else {
456 Err(AclError::WasMoved)
457 }
458 }
459
460 pub fn add_perm(&mut self, perm: AclPerm) -> Result<(), AclError> {
461 self.check_valid()?;
462 let result = unsafe { acl_sys::acl_add_perm(self.raw_ptr, perm.to_raw()) };
463 match result {
464 0 => Ok(()),
465 -1 => {
466 let errno = nix::errno::errno();
467 Err(AclError::Errno(nix::errno::from_i32(errno)))
468 }
469 _ => Err(AclError::UnknownReturn(result)),
470 }
471 }
472
473 pub fn delete_perms(&mut self, perm: AclPerm) -> Result<(), AclError> {
474 self.check_valid()?;
475 let result = unsafe { acl_sys::acl_delete_perms(self.raw_ptr, perm.to_raw()) };
476 match result {
477 0 => Ok(()),
478 -1 => {
479 let errno = nix::errno::errno();
480 Err(AclError::Errno(nix::errno::from_i32(errno)))
481 }
482 _ => Err(AclError::UnknownReturn(result)),
483 }
484 }
485
486 pub fn clear_perms(&mut self) -> Result<(), AclError> {
487 self.check_valid()?;
488 let result = unsafe { acl_sys::acl_clear_perms(self.raw_ptr) };
489 match result {
490 0 => Ok(()),
491 -1 => {
492 let errno = nix::errno::errno();
493 Err(AclError::Errno(nix::errno::from_i32(errno)))
494 }
495 _ => Err(AclError::UnknownReturn(result)),
496 }
497 }
498}
499
500impl AclEntry {
501 pub fn check_valid(&self) -> Result<(), AclError> {
502 if *self.is_valid.borrow() == true {
503 Ok(())
504 } else {
505 Err(AclError::WasMoved)
506 }
507 }
508
509 pub fn copy_to(&self, dest: &mut AclEntry) -> Result<(), AclError> {
510 self.check_valid()?;
511 let result = unsafe { acl_sys::acl_copy_entry(dest.raw_ptr, self.raw_ptr) };
512 match result {
513 0 => Ok(()),
514 -1 => {
515 let errno = nix::errno::errno();
516 Err(AclError::Errno(nix::errno::from_i32(errno)))
517 }
518 _ => Err(AclError::UnknownReturn(result)),
519 }
520 }
521
522 pub fn get_permset(&self) -> Result<AclPermSet, AclError> {
523 self.check_valid()?;
524 let mut permset_ptr = std::ptr::null_mut();
525 let permset_ptr_ptr = &mut permset_ptr as *mut acl_sys::acl_entry_t;
526 let result = unsafe { acl_sys::acl_get_permset(self.raw_ptr, permset_ptr_ptr) };
527
528 match result {
529 0 => Ok(AclPermSet {
530 raw_ptr: permset_ptr,
531 is_valid: self.is_valid.clone(),
532 }),
533 -1 => {
534 let errno = nix::errno::errno();
535 Err(AclError::Errno(nix::errno::from_i32(errno)))
536 }
537 _ => Err(AclError::UnknownReturn(result)),
538 }
539 }
540
541 pub fn set_permset(&mut self, permset: &AclPermSet) -> Result<(), AclError> {
542 self.check_valid()?;
543 let result = unsafe { acl_sys::acl_set_permset(self.raw_ptr, permset.raw_ptr) };
544
545 match result {
546 0 => Ok(()),
547 -1 => {
548 let errno = nix::errno::errno();
549 Err(AclError::Errno(nix::errno::from_i32(errno)))
550 }
551 _ => Err(AclError::UnknownReturn(result)),
552 }
553 }
554
555 pub fn get_tag_type(&self) -> Result<AclTag, AclError> {
556 self.check_valid()?;
557 let mut raw = 0 as acl_sys::acl_tag_t;
558 let raw_ptr = &mut raw as *mut acl_sys::acl_tag_t;
559 let result = unsafe { acl_sys::acl_get_tag_type(self.raw_ptr, raw_ptr) };
560
561 match result {
562 0 => Ok(AclTag::from_raw(raw)),
563 -1 => {
564 let errno = nix::errno::errno();
565 Err(AclError::Errno(nix::errno::from_i32(errno)))
566 }
567 _ => Err(AclError::UnknownReturn(result)),
568 }
569 }
570
571 pub fn set_tag_type(&mut self, tag_type: &AclTag) -> Result<(), AclError> {
572 self.check_valid()?;
573 let result = unsafe { acl_sys::acl_set_tag_type(self.raw_ptr, tag_type.to_raw()) };
574
575 match result {
576 0 => Ok(()),
577 -1 => {
578 let errno = nix::errno::errno();
579 Err(AclError::Errno(nix::errno::from_i32(errno)))
580 }
581 _ => Err(AclError::UnknownReturn(result)),
582 }
583 }
584
585 pub fn get_qualifier(&self) -> Result<Qualifier, AclError> {
586 self.check_valid()?;
587 match self.get_tag_type()? {
588 AclTag::User => {
589 let raw_ptr = unsafe { acl_sys::acl_get_qualifier(self.raw_ptr) };
590 if raw_ptr.is_null() {
591 let errno = nix::errno::errno();
592 Err(AclError::Errno(nix::errno::from_i32(errno)))
593 } else {
594 let raw: u32 = unsafe { *(std::mem::transmute::<_, *const u32>(raw_ptr)) };
595 Ok(Qualifier::User(nix::unistd::Uid::from_raw(raw)))
596 }
597 }
598 AclTag::Group => {
599 let raw_ptr = unsafe { acl_sys::acl_get_qualifier(self.raw_ptr) };
600 if raw_ptr.is_null() {
601 let errno = nix::errno::errno();
602 Err(AclError::Errno(nix::errno::from_i32(errno)))
603 } else {
604 let raw: u32 = unsafe { *(std::mem::transmute::<_, *const u32>(raw_ptr)) };
605 Ok(Qualifier::User(nix::unistd::Uid::from_raw(raw)))
606 }
607 }
608 _ => return Err(AclError::Errno(nix::errno::Errno::EINVAL)),
609 }
610 }
611
612 pub fn set_qualifier(&mut self, qual: &Qualifier) -> Result<(), AclError> {
613 self.check_valid()?;
614 let result = match qual {
615 Qualifier::User(id) => {
616 let raw = id.as_raw();
617 let raw_ptr = &raw;
618 unsafe { acl_sys::acl_set_qualifier(self.raw_ptr, std::mem::transmute(raw_ptr)) }
619 }
620 Qualifier::Group(id) => unsafe {
621 acl_sys::acl_set_qualifier(self.raw_ptr, std::mem::transmute(&id.as_raw()))
622 },
623 };
624 match result {
625 0 => Ok(()),
626 -1 => {
627 let errno = nix::errno::errno();
628 Err(AclError::Errno(nix::errno::from_i32(errno)))
629 }
630 _ => Err(AclError::UnknownReturn(result)),
631 }
632 }
633}
634
635pub fn delete_def_file(file_path: &std::path::PathBuf) -> Result<(), AclError> {
636 use std::os::unix::ffi::OsStrExt;
637 let path_bytes = file_path.as_os_str().as_bytes().to_vec();
638 let path_i8 = path_bytes.into_iter().map(|x| x as i8).collect::<Vec<_>>();
639 let path_ptr = path_i8.as_ptr();
640
641 let result = unsafe { acl_sys::acl_delete_def_file(path_ptr) };
642 match result {
643 0 => Ok(()),
644 -1 => {
645 let errno = nix::errno::errno();
646 Err(AclError::Errno(nix::errno::from_i32(errno)))
647 }
648 _ => Err(AclError::UnknownReturn(result)),
649 }
650}