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}