Skip to main content

dolang_vfs/
nfs4_acl.rs

1use serde::{Deserialize, Serialize};
2
3bitflags::bitflags! {
4    /// Permission bits used by NFSv4 ACL entries.
5    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
6    pub struct Nfs4AceMask: u32 {
7        /// Read the data of a file, or list the entries of a directory.
8        const READ_DATA = 0x00000008;
9        /// Write the data of a file, or add a new file to a directory.
10        const WRITE_DATA = 0x00000010;
11        /// Append data to a file, or add a new subdirectory to a directory.
12        const APPEND_DATA = 0x00000020;
13        /// Read the named attributes of a file or directory.
14        const READ_NAMED_ATTRS = 0x00000040;
15        /// Write the named attributes of a file or directory.
16        const WRITE_NAMED_ATTRS = 0x00000080;
17        /// Execute a file, or search a directory.
18        const EXECUTE = 0x00000001;
19        /// Delete a file or directory within a directory.
20        const DELETE_CHILD = 0x00000100;
21        /// Read the (non-ACL) attributes of a file or directory.
22        const READ_ATTRIBUTES = 0x00000200;
23        /// Write the (non-ACL) attributes of a file or directory.
24        const WRITE_ATTRIBUTES = 0x00000400;
25        /// Delete the file or directory.
26        const DELETE = 0x00000800;
27        /// Read the ACL.
28        const READ_ACL = 0x00001000;
29        /// Write the ACL.
30        const WRITE_ACL = 0x00002000;
31        /// Change the owner.
32        const WRITE_OWNER = 0x00004000;
33        /// Synchronize I/O.
34        const SYNCHRONIZE = 0x00008000;
35    }
36}
37
38bitflags::bitflags! {
39    /// Inheritance and audit/alarm flags used by NFSv4 ACL entries.
40    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
41    pub struct Nfs4AceFlags: u32 {
42        /// Inherited by files created within a directory.
43        const FILE_INHERIT = 0x0001;
44        /// Inherited by subdirectories created within a directory.
45        const DIRECTORY_INHERIT = 0x0002;
46        /// Inherited only by direct children, not further descendants.
47        const NO_PROPAGATE_INHERIT = 0x0004;
48        /// Present only to be inherited; does not apply to the entry's own object.
49        const INHERIT_ONLY = 0x0008;
50        /// Log successful accesses (audit/alarm entries).
51        const SUCCESSFUL_ACCESS = 0x0010;
52        /// Log failed accesses (audit/alarm entries).
53        const FAILED_ACCESS = 0x0020;
54        /// The entry was created by inheritance from a parent directory.
55        const INHERITED = 0x0080;
56    }
57}
58
59/// The kind of an NFSv4 ACL entry.
60#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
61pub enum Nfs4AceType {
62    /// Grants the permissions in the entry's mask.
63    Allow,
64    /// Denies the permissions in the entry's mask.
65    Deny,
66    /// Generates an audit log entry when accessed.
67    Audit,
68    /// Generates an alarm when accessed.
69    Alarm,
70}
71
72/// The principal selected by an NFSv4 ACL entry.
73#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
74pub enum Nfs4AceQualifier {
75    /// The `OWNER@` special principal: the file's owning user.
76    Owner,
77    /// The `GROUP@` special principal: the file's owning group.
78    OwningGroup,
79    /// The `EVERYONE@` special principal.
80    Everyone,
81    /// A named user.
82    User(u32),
83    /// A named group.
84    Group(u32),
85}
86
87/// A portable NFSv4 ACL entry.
88#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
89pub struct Nfs4Ace {
90    /// Whether this entry allows, denies, audits, or alarms.
91    pub(crate) ace_type: Nfs4AceType,
92    /// Principal controlled by this entry.
93    pub(crate) qualifier: Nfs4AceQualifier,
94    /// Permissions named by this entry.
95    pub(crate) mask: Nfs4AceMask,
96    /// Inheritance and audit/alarm flags.
97    pub(crate) flags: Nfs4AceFlags,
98}
99
100impl Nfs4Ace {
101    /// Creates an NFSv4 ACL entry.
102    pub const fn new(
103        ace_type: Nfs4AceType,
104        qualifier: Nfs4AceQualifier,
105        mask: Nfs4AceMask,
106        flags: Nfs4AceFlags,
107    ) -> Self {
108        Self {
109            ace_type,
110            qualifier,
111            mask,
112            flags,
113        }
114    }
115    /// Returns whether this entry allows or denies access.
116    pub const fn ace_type(self) -> Nfs4AceType {
117        self.ace_type
118    }
119    /// Returns the principal to which this entry applies.
120    pub const fn qualifier(self) -> Nfs4AceQualifier {
121        self.qualifier
122    }
123    /// Returns the access-rights mask.
124    pub const fn mask(self) -> Nfs4AceMask {
125        self.mask
126    }
127    /// Returns the inheritance and qualifier flags.
128    pub const fn flags(self) -> Nfs4AceFlags {
129        self.flags
130    }
131}
132
133/// A portable NFSv4 access-control list.
134///
135/// Unlike [`PosixAcl`](crate::security::PosixAcl), NFSv4 ACLs are an ordered,
136/// first-match list with no completeness requirement, so there is nothing to
137/// validate beyond the shape of the individual entries.
138#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
139pub struct Nfs4Acl {
140    entries: Vec<Nfs4Ace>,
141}
142
143impl Nfs4Acl {
144    /// Constructs an access-control list from `entries`, in evaluation order.
145    pub fn new(entries: Vec<Nfs4Ace>) -> Self {
146        Self { entries }
147    }
148
149    /// Returns the ACL entries in their stored (evaluation) order.
150    pub fn entries(&self) -> &[Nfs4Ace] {
151        &self.entries
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158
159    #[test]
160    fn serde_round_trip_preserves_entries() {
161        let acl = Nfs4Acl::new(vec![
162            Nfs4Ace {
163                ace_type: Nfs4AceType::Allow,
164                qualifier: Nfs4AceQualifier::Owner,
165                mask: Nfs4AceMask::READ_DATA | Nfs4AceMask::WRITE_DATA,
166                flags: Nfs4AceFlags::empty(),
167            },
168            Nfs4Ace {
169                ace_type: Nfs4AceType::Deny,
170                qualifier: Nfs4AceQualifier::User(1000),
171                mask: Nfs4AceMask::WRITE_DATA,
172                flags: Nfs4AceFlags::FILE_INHERIT | Nfs4AceFlags::DIRECTORY_INHERIT,
173            },
174        ]);
175        let bytes = postcard::to_stdvec(&acl).unwrap();
176        assert_eq!(postcard::from_bytes::<Nfs4Acl>(&bytes).unwrap(), acl);
177    }
178}