1 //! Implementation of the calls to handle POSIX access control lists
3 // see C header file <sys/acl.h> for reference
7 use std
::marker
::PhantomData
;
8 use std
::os
::unix
::ffi
::OsStrExt
;
9 use std
::os
::unix
::io
::RawFd
;
13 use libc
::{c_char, c_int, c_uint, c_void}
;
14 use nix
::errno
::Errno
;
17 // from: acl/include/acl.h
18 pub const ACL_UNDEFINED_ID
: u32 = 0xffffffff;
20 pub type ACLPerm
= c_uint
;
21 pub const ACL_READ
: ACLPerm
= 0x04;
22 pub const ACL_WRITE
: ACLPerm
= 0x02;
23 pub const ACL_EXECUTE
: ACLPerm
= 0x01;
26 pub type ACLTag
= c_int
;
27 pub const ACL_UNDEFINED_TAG
: ACLTag
= 0x00;
28 pub const ACL_USER_OBJ
: ACLTag
= 0x01;
29 pub const ACL_USER
: ACLTag
= 0x02;
30 pub const ACL_GROUP_OBJ
: ACLTag
= 0x04;
31 pub const ACL_GROUP
: ACLTag
= 0x08;
32 pub const ACL_MASK
: ACLTag
= 0x10;
33 pub const ACL_OTHER
: ACLTag
= 0x20;
36 pub type ACLType
= c_uint
;
37 pub const ACL_TYPE_ACCESS
: ACLType
= 0x8000;
38 pub const ACL_TYPE_DEFAULT
: ACLType
= 0x4000;
40 // acl entry constants
41 pub const ACL_FIRST_ENTRY
: c_int
= 0;
42 pub const ACL_NEXT_ENTRY
: c_int
= 1;
44 // acl to extended attribute names constants
45 // from: acl/include/acl_ea.h
46 pub const ACL_EA_ACCESS
: &str = "system.posix_acl_access";
47 pub const ACL_EA_DEFAULT
: &str = "system.posix_acl_default";
48 pub const ACL_EA_VERSION
: u32 = 0x0002;
52 fn acl_get_file(path
: *const c_char
, acl_type
: ACLType
) -> *mut c_void
;
53 fn acl_set_file(path
: *const c_char
, acl_type
: ACLType
, acl
: *mut c_void
) -> c_int
;
54 fn acl_get_fd(fd
: RawFd
) -> *mut c_void
;
55 fn acl_get_entry(acl
: *const c_void
, entry_id
: c_int
, entry
: *mut *mut c_void
) -> c_int
;
56 fn acl_create_entry(acl
: *mut *mut c_void
, entry
: *mut *mut c_void
) -> c_int
;
57 fn acl_get_tag_type(entry
: *mut c_void
, tag_type
: *mut ACLTag
) -> c_int
;
58 fn acl_set_tag_type(entry
: *mut c_void
, tag_type
: ACLTag
) -> c_int
;
59 fn acl_get_permset(entry
: *mut c_void
, permset
: *mut *mut c_void
) -> c_int
;
60 fn acl_clear_perms(permset
: *mut c_void
) -> c_int
;
61 fn acl_get_perm(permset
: *mut c_void
, perm
: ACLPerm
) -> c_int
;
62 fn acl_add_perm(permset
: *mut c_void
, perm
: ACLPerm
) -> c_int
;
63 fn acl_get_qualifier(entry
: *mut c_void
) -> *mut c_void
;
64 fn acl_set_qualifier(entry
: *mut c_void
, qualifier
: *const c_void
) -> c_int
;
65 fn acl_init(count
: c_int
) -> *mut c_void
;
66 fn acl_valid(ptr
: *const c_void
) -> c_int
;
67 fn acl_free(ptr
: *mut c_void
) -> c_int
;
77 let ret
= unsafe { acl_free(self.ptr) }
;
79 panic
!("invalid pointer encountered while dropping ACL - {}", Errno
::last());
85 pub fn init(count
: usize) -> Result
<ACL
, nix
::errno
::Errno
> {
86 let ptr
= unsafe { acl_init(count as i32 as c_int) }
;
88 return Err(Errno
::last());
94 pub fn get_file
<P
: AsRef
<Path
>>(path
: P
, acl_type
: ACLType
) -> Result
<ACL
, nix
::errno
::Errno
> {
95 let path_cstr
= CString
::new(path
.as_ref().as_os_str().as_bytes()).unwrap();
96 let ptr
= unsafe { acl_get_file(path_cstr.as_ptr(), acl_type) }
;
98 return Err(Errno
::last());
104 pub fn set_file
<P
: NixPath
+ ?Sized
>(&self, path
: &P
, acl_type
: ACLType
) -> nix
::Result
<()> {
105 path
.with_nix_path(|path
| {
106 Errno
::result(unsafe { acl_set_file(path.as_ptr(), acl_type, self.ptr) }
)
111 pub fn get_fd(fd
: RawFd
) -> Result
<ACL
, nix
::errno
::Errno
> {
112 let ptr
= unsafe { acl_get_fd(fd) }
;
114 return Err(Errno
::last());
120 pub fn create_entry(&mut self) -> Result
<ACLEntry
, nix
::errno
::Errno
> {
121 let mut ptr
= ptr
::null_mut() as *mut c_void
;
122 let res
= unsafe { acl_create_entry(&mut self.ptr, &mut ptr) }
;
124 return Err(Errno
::last());
129 _phantom
: PhantomData
,
133 pub fn is_valid(&self) -> bool
{
134 let res
= unsafe { acl_valid(self.ptr) }
;
142 pub fn entries(self) -> ACLEntriesIterator
{
145 current
: ACL_FIRST_ENTRY
,
149 pub fn add_entry_full(&mut self, tag
: ACLTag
, qualifier
: Option
<u64>, permissions
: u64)
150 -> Result
<(), nix
::errno
::Errno
>
152 let mut entry
= self.create_entry()?
;
153 entry
.set_tag_type(tag
)?
;
154 if let Some(qualifier
) = qualifier
{
155 entry
.set_qualifier(qualifier
)?
;
157 entry
.set_permissions(permissions
)?
;
164 pub struct ACLEntry
<'a
> {
166 _phantom
: PhantomData
<&'a
mut ()>,
169 impl<'a
> ACLEntry
<'a
> {
170 pub fn get_tag_type(&self) -> Result
<ACLTag
, nix
::errno
::Errno
> {
171 let mut tag
= ACL_UNDEFINED_TAG
;
172 let res
= unsafe { acl_get_tag_type(self.ptr, &mut tag as *mut ACLTag) }
;
174 return Err(Errno
::last());
180 pub fn set_tag_type(&mut self, tag
: ACLTag
) -> Result
<(), nix
::errno
::Errno
> {
181 let res
= unsafe { acl_set_tag_type(self.ptr, tag) }
;
183 return Err(Errno
::last());
189 pub fn get_permissions(&self) -> Result
<u64, nix
::errno
::Errno
> {
190 let mut permissions
= 0;
191 let mut permset
= ptr
::null_mut() as *mut c_void
;
192 let mut res
= unsafe { acl_get_permset(self.ptr, &mut permset) }
;
194 return Err(Errno
::last());
197 for &perm
in &[ACL_READ
, ACL_WRITE
, ACL_EXECUTE
] {
198 res
= unsafe { acl_get_perm(permset, perm) }
;
200 return Err(Errno
::last());
204 permissions
|= perm
as u64;
211 pub fn set_permissions(&mut self, permissions
: u64) -> Result
<u64, nix
::errno
::Errno
> {
212 let mut permset
= ptr
::null_mut() as *mut c_void
;
213 let mut res
= unsafe { acl_get_permset(self.ptr, &mut permset) }
;
215 return Err(Errno
::last());
218 res
= unsafe { acl_clear_perms(permset) }
;
220 return Err(Errno
::last());
223 for &perm
in &[ACL_READ
, ACL_WRITE
, ACL_EXECUTE
] {
224 if permissions
& perm
as u64 == perm
as u64 {
225 res
= unsafe { acl_add_perm(permset, perm) }
;
227 return Err(Errno
::last());
235 pub fn get_qualifier(&self) -> Result
<u64, nix
::errno
::Errno
> {
236 let qualifier
= unsafe { acl_get_qualifier(self.ptr) }
;
237 if qualifier
.is_null() {
238 return Err(Errno
::last());
240 let result
= unsafe { *(qualifier as *const u32) as u64 }
;
241 let ret
= unsafe { acl_free(qualifier) }
;
243 panic
!("invalid pointer encountered while dropping ACL qualifier - {}", Errno
::last());
249 pub fn set_qualifier(&mut self, qualifier
: u64) -> Result
<(), nix
::errno
::Errno
> {
250 let val
= qualifier
as u32;
251 let val_ptr
: *const u32 = &val
;
252 let res
= unsafe { acl_set_qualifier(self.ptr, val_ptr as *const c_void) }
;
254 return Err(Errno
::last());
262 pub struct ACLEntriesIterator
{
267 impl<'a
> Iterator
for &'a
mut ACLEntriesIterator
{
268 type Item
= ACLEntry
<'a
>;
270 fn next(&mut self) -> Option
<Self::Item
> {
271 let mut entry_ptr
= ptr
::null_mut();
272 let res
= unsafe { acl_get_entry(self.acl.ptr, self.current, &mut entry_ptr) }
;
273 self.current
= ACL_NEXT_ENTRY
;
275 return Some(ACLEntry { ptr: entry_ptr, _phantom: PhantomData }
);
282 /// Helper to transform `PxarEntry`s user mode to acl permissions.
283 pub fn mode_user_to_acl_permissions(mode
: u64) -> u64 {
287 /// Helper to transform `PxarEntry`s group mode to acl permissions.
288 pub fn mode_group_to_acl_permissions(mode
: u64) -> u64 {
292 /// Helper to transform `PxarEntry`s other mode to acl permissions.
293 pub fn mode_other_to_acl_permissions(mode
: u64) -> u64 {
297 /// Buffer to compose ACLs as extended attribute.
298 pub struct ACLXAttrBuffer
{
302 impl ACLXAttrBuffer
{
303 /// Create a new buffer to write ACLs as extended attribute.
305 /// `version` defines the ACL_EA_VERSION found in acl/include/acl_ea.h
306 pub fn new(version
: u32) -> Self {
307 let mut buffer
= Vec
::new();
308 buffer
.extend_from_slice(&version
.to_le_bytes());
312 /// Add ACL entry to buffer.
313 pub fn add_entry(&mut self, tag
: ACLTag
, qualifier
: Option
<u64>, permissions
: u64) {
314 self.buffer
.extend_from_slice(&(tag
as u16).to_le_bytes());
315 self.buffer
.extend_from_slice(&(permissions
as u16).to_le_bytes());
317 Some(qualifier
) => self.buffer
.extend_from_slice(&(qualifier
as u32).to_le_bytes()),
318 None
=> self.buffer
.extend_from_slice(&ACL_UNDEFINED_ID
.to_le_bytes()),
322 /// Length of the buffer in bytes.
323 pub fn len(&self) -> usize {
327 /// The buffer always contains at least the version, it is never empty
328 pub const fn is_empty(&self) -> bool { false }
330 /// Borrow raw buffer as mut slice.
331 pub fn as_mut_slice(&mut self) -> &mut [u8] {
332 self.buffer
.as_mut_slice()