1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
use binrw::{BinRead, BinReaderExt, BinWrite, BinWriterExt};
use bitflags::bitflags;
use constants::{
FILE_ALL, FILE_EXECUTE, FILE_READ, FILE_WRITE, KEY_ALL, KEY_EXECUTE, KEY_READ, KEY_WRITE,
};
use serde::Serialize;
use crate::sddl_h::*;
pub mod constants {
use super::AccessMask;
use lazy_static::lazy_static;
/// A principal with a lower mandatory level than the object cannot
/// write to the object.
pub const SYSTEM_MANDATORY_LABEL_NO_WRITE_UP: AccessMask = AccessMask::CREATE_CHILD;
/// A principal with a lower mandatory level than the object cannot
/// read the object.
pub const SYSTEM_MANDATORY_LABEL_NO_READ_UP: AccessMask = AccessMask::DELETE_CHILD;
/// A principal with a lower mandatory level than the object cannot
/// execute the object.
pub const SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP: AccessMask = AccessMask::LIST_CHILDREN;
/// The ObjectType GUID identifies a type of child object. The ACE
/// controls the trustee's right to create this type of child object.
pub const ADS_RIGHT_DS_CREATE_CHILD: AccessMask = AccessMask::CREATE_CHILD;
/// The ObjectType GUID identifies a type of child object. The ACE
/// controls the trustee's right to delete this type of child object.
pub const ADS_RIGHT_DS_DELETE_CHILD: AccessMask = AccessMask::DELETE_CHILD;
pub const ADS_RIGHT_ACTRL_DS_LIST: AccessMask = AccessMask::LIST_CHILDREN;
/// The ObjectType GUID identifies a validated write.
pub const ADS_RIGHT_DS_SELF: AccessMask = AccessMask::SELF_WRITE;
/// The ObjectType GUID identifies a property set or property of the
/// object. The ACE controls the trustee's right to read the property
/// or property set.
pub const ADS_RIGHT_DS_READ_PROP: AccessMask = AccessMask::READ_PROPERTY;
/// The ObjectType GUID identifies a property set or property of the
/// object. The ACE controls the trustee's right to write the property
/// or property set.
pub const ADS_RIGHT_DS_WRITE_PROP: AccessMask = AccessMask::WRITE_PROPERTY;
pub const ADS_RIGHT_DS_DELETE_TREE: AccessMask = AccessMask::DELETE_TREE;
pub const ADS_RIGHT_DS_LIST_OBJECT: AccessMask = AccessMask::LIST_OBJECT;
/// The ObjectType GUID identifies an extended access right.
pub const ADS_RIGHT_DS_CONTROL_ACCESS: AccessMask = AccessMask::CONTROL_ACCESS;
lazy_static! {
pub static ref FILE_ALL: AccessMask = AccessMask::SYNCHRONIZE
| AccessMask::WRITE_OWNER
| AccessMask::WRITE_DACL
| AccessMask::READ_CONTROL
| AccessMask::DELETE
| AccessMask::CONTROL_ACCESS
| AccessMask::LIST_OBJECT
| AccessMask::DELETE_TREE
| AccessMask::WRITE_PROPERTY
| AccessMask::READ_PROPERTY
| AccessMask::SELF_WRITE
| AccessMask::LIST_CHILDREN
| AccessMask::DELETE_CHILD
| AccessMask::CREATE_CHILD;
pub static ref FILE_EXECUTE: AccessMask = AccessMask::SYNCHRONIZE
| AccessMask::READ_CONTROL
| AccessMask::LIST_OBJECT
| AccessMask::WRITE_PROPERTY;
pub static ref FILE_WRITE: AccessMask = AccessMask::SYNCHRONIZE
| AccessMask::READ_CONTROL
| AccessMask::CONTROL_ACCESS
| AccessMask::READ_PROPERTY
| AccessMask::LIST_CHILDREN
| AccessMask::DELETE_CHILD;
pub static ref FILE_READ: AccessMask = AccessMask::SYNCHRONIZE
| AccessMask::READ_CONTROL
| AccessMask::LIST_OBJECT
| AccessMask::SELF_WRITE
| AccessMask::CREATE_CHILD;
pub static ref KEY_ALL: AccessMask = AccessMask::WRITE_OWNER
| AccessMask::WRITE_DACL
| AccessMask::READ_CONTROL
| AccessMask::DELETE
| AccessMask::WRITE_PROPERTY
| AccessMask::READ_PROPERTY
| AccessMask::SELF_WRITE
| AccessMask::LIST_CHILDREN
| AccessMask::DELETE_CHILD
| AccessMask::CREATE_CHILD;
pub static ref KEY_READ: AccessMask = AccessMask::READ_CONTROL
| AccessMask::READ_PROPERTY
| AccessMask::SELF_WRITE
| AccessMask::CREATE_CHILD;
pub static ref KEY_WRITE: AccessMask =
AccessMask::READ_CONTROL | AccessMask::LIST_CHILDREN | AccessMask::DELETE_CHILD;
pub static ref KEY_EXECUTE: AccessMask = AccessMask::READ_CONTROL
| AccessMask::READ_PROPERTY
| AccessMask::SELF_WRITE
| AccessMask::CREATE_CHILD;
}
}
bitflags! {
#[derive(Eq, PartialEq, Debug, Copy, Clone, Serialize)]
pub struct AccessMask: u32 {
/// **When used in an Access Request operation:** When read access to an
/// object is requested, this bit is translated to a combination of
/// bits. These are most often set in the lower 16 bits of the
/// ACCESS_MASK. (Individual protocol specifications MAY specify a
/// different configuration.) The bits that are set are implementation
/// dependent. During this translation, the GR bit is cleared. The
/// resulting ACCESS_MASK bits are the actual permissions that are
/// checked against the ACE structures in the security descriptor that
/// attached to the object.
///
/// **When used to set the Security Descriptor on an object:** When the
/// GR bit is set in an ACE that is to be attached to an object, it is
/// translated into a combination of bits, which are usually set in the
/// lower 16 bits of the ACCESS_MASK. (Individual protocol
/// specifications MAY specify a different configuration.) The bits
/// that are set are implementation dependent. During this translation,
/// the GR bit is cleared. The resulting ACCESS_MASK bits are the actual
/// permissions that are granted by this ACE.
const GENERIC_READ = 0x80000000;
/// **When used in an Access Request operation:** When write access to
/// an object is requested, this bit is translated to a combination of
/// bits, which are usually set in the lower 16 bits of the ACCESS_MASK.
/// (Individual protocol specifications MAY specify a different
/// configuration.) The bits that are set are implementation dependent.
/// During this translation, the GW bit is cleared. The resulting
/// ACCESS_MASK bits are the actual permissions that are checked against
/// the ACE structures in the security descriptor that attached to the
/// object.
///
/// **When used to set the Security Descriptor on an object:** When the
/// GW bit is set in an ACE that is to be attached to an object, it is
/// translated into a combination of bits, which are usually set in the
/// lower 16 bits of the ACCESS_MASK. (Individual protocol
/// specifications MAY specify a different configuration.) The bits that
/// are set are implementation dependent. During this translation, the
/// GW bit is cleared. The resulting ACCESS_MASK bits are the actual
/// permissions that are granted by this ACE.
const GENERIC_WRITE = 0x4000000;
/// **When used in an Access Request operation:** When execute access to
/// an object is requested, this bit is translated to a combination of
/// bits, which are usually set in the lower 16 bits of the ACCESS_MASK.
/// (Individual protocol specifications MAY specify a different
/// configuration.) The bits that are set are implementation dependent.
/// During this translation, the GX bit is cleared. The resulting
/// ACCESS_MASK bits are the actual permissions that are checked against
/// the ACE structures in the security descriptor that attached to the
/// object.
///
/// **When used to set the Security Descriptor on an object:** When the
/// GX bit is set in an ACE that is to be attached to an object, it is
/// translated into a combination of bits, which are usually set in the
/// lower 16 bits of the ACCESS_MASK. (Individual protocol
/// specifications MAY specify a different configuration.) The bits that
/// are set are implementation AdsAccessMaskdependent. During this
/// translation, the GX bit is cleared. The resulting ACCESS_MASK bits
/// are the actual permissions that are granted by this ACE.
const GENERIC_EXECUTE = 0x20000000;
/// **When used in an Access Request operation:** When all access
/// permissions to an object are requested, this bit is translated to a
/// combination of bits, which are usually set in the lower 16 bits of
/// the ACCESS_MASK. (Individual protocol specifications MAY specify a
/// different configuration.) Objects are free to include bits from the
/// upper 16 bits in that translation as required by the objects
/// semantics. The bits that are set are implementation dependent.
/// During this translation, the GA bit is cleared. The resulting
/// ACCESS_MASK bits are the actual permissions that are checked against
/// the ACE structures in the security descriptor that attached to the
/// object.
///
/// **When used to set the Security Descriptor on an object:** When the
/// GA bit is set in an ACE that is to be attached to an object, it is
/// translated into a combination of bits, which are usually set in the
/// lower 16 bits of the ACCESS_MASK. (Individual protocol
/// specifications MAY specify a different configuration.) Objects are
/// free to include bits from the upper 16 bits in that translation, if
/// required by the objects semantics. The bits that are set are
/// implementation dependent. During this translation, the GA bit is
/// cleared. The resulting ACCESS_MASK bits are the actual permissions
/// that are granted by this ACE.
const GENERIC_ALL = 0x10000000;
/// **When used in an Access Request operation:** When requested, this
/// bit grants the requestor the maximum permissions allowed to the
/// object through the Access Check Algorithm. This bit can only be
/// requested; it cannot be set in an ACE.
///
/// **When used to set the Security Descriptor on an object:**
/// Specifying the Maximum Allowed bit in the SECURITY_DESCRIPTOR has no
/// meaning. The MA bit SHOULD NOT be set and SHOULD be ignored when
/// part of a SECURITY_DESCRIPTOR structure.
const MAXIMUM_ALLOWED = 0x02000000;
/// **When used in an Access Request operation:** When requested, this
/// bit grants the requestor the right to change the SACL of an object.
/// This bit MUST NOT be set in an ACE that is part of a DACL. When set
/// in an ACE that is part of a SACL, this bit controls auditing of
/// accesses to the SACL itself.
const ACCESS_SYSTEM_SECURITY = 0x01000000;
/// Specifies access to the object sufficient to synchronize or wait on
/// the object.
const SYNCHRONIZE = 0x00100000;
/// Specifies access to change the owner of the object as listed in the
/// security descriptor.
const WRITE_OWNER = 0x00080000;
/// Specifies access to change the discretionary access control list of
/// the security descriptor of an object.
const WRITE_DACL = 0x00040000;
/// Specifies access to read the security descriptor of an object.
const READ_CONTROL = 0x00020000;
/// Specifies access to delete an object.
const DELETE = 0x00010000;
const CONTROL_ACCESS = 0x00000100;
const LIST_OBJECT = 0x00000080;
const DELETE_TREE = 0x00000040;
const WRITE_PROPERTY = 0x00000020;
const READ_PROPERTY = 0x00000010;
const SELF_WRITE = 0x00000008;
const LIST_CHILDREN = 0x00000004;
const DELETE_CHILD = 0x00000002;
const CREATE_CHILD = 0x00000001;
// The source may set any bits
const _ = !0;
}
}
impl AccessMask {
pub fn sddl_string(&self) -> String {
if *self == *FILE_ALL {
SDDL_FILE_ALL.into()
} else if *self == *FILE_READ {
SDDL_FILE_READ.into()
} else if *self == *FILE_WRITE {
SDDL_FILE_WRITE.into()
} else if *self == *FILE_EXECUTE {
SDDL_FILE_EXECUTE.into()
} else if *self == *KEY_ALL {
SDDL_KEY_ALL.into()
} else if *self == *KEY_READ {
SDDL_KEY_READ.into()
} else if *self == *KEY_WRITE {
SDDL_KEY_WRITE.into()
} else if *self == *KEY_EXECUTE {
SDDL_KEY_EXECUTE.into()
} else {
let mut sddl = String::with_capacity(32);
let mut flag = |mask: AccessMask, s: &str| {
if self.contains(mask) {
sddl.push_str(s);
}
};
flag(Self::GENERIC_READ, SDDL_GENERIC_READ);
flag(Self::GENERIC_WRITE, SDDL_GENERIC_WRITE);
flag(Self::GENERIC_EXECUTE, SDDL_GENERIC_EXECUTE);
flag(Self::GENERIC_ALL, SDDL_GENERIC_ALL);
flag(Self::MAXIMUM_ALLOWED, "MA");
flag(Self::ACCESS_SYSTEM_SECURITY, "AS");
flag(Self::SYNCHRONIZE, "SY");
flag(Self::WRITE_OWNER, SDDL_WRITE_OWNER);
flag(Self::WRITE_DACL, SDDL_WRITE_DAC);
flag(Self::READ_CONTROL, SDDL_READ_CONTROL);
flag(Self::DELETE, SDDL_STANDARD_DELETE);
sddl
}
}
}
impl BinRead for AccessMask {
type Args<'a> = ();
fn read_options<R: std::io::Read + std::io::Seek>(
reader: &mut R,
endian: binrw::Endian,
args: Self::Args<'_>,
) -> binrw::BinResult<Self> {
let raw_value: u32 = reader.read_type_args(endian, args)?;
Ok(AccessMask::from_bits(raw_value).unwrap())
}
}
impl From<u32> for AccessMask {
fn from(value: u32) -> Self {
AccessMask::from_bits(value).unwrap()
}
}
impl<'input> TryFrom<&'input str> for AccessMask {
type Error = crate::Error;
fn try_from(value: &'input str) -> Result<Self, Self::Error> {
Ok(crate::parser::AccessMaskParser::new().parse(None, value)?)
}
}
impl BinWrite for AccessMask {
type Args<'a> = ();
fn write_options<W: std::io::Write + std::io::Seek>(
&self,
writer: &mut W,
endian: binrw::Endian,
args: Self::Args<'_>,
) -> binrw::BinResult<()> {
let raw_value = self.bits();
writer.write_type_args(&raw_value, endian, args)
}
}
#[cfg(test)]
mod tests {
use crate::AccessMask;
use super::constants::*;
#[test]
fn test_simple_mask() {
assert_eq!(
AccessMask::try_from("0x80000000").unwrap(),
AccessMask::GENERIC_READ
);
assert_ne!(
AccessMask::try_from("0x80000001").unwrap(),
AccessMask::GENERIC_READ
);
}
#[test]
fn test_complex_mask1() {
assert_eq!(
AccessMask::try_from("GRGXWP").unwrap(),
AccessMask::GENERIC_READ | AccessMask::GENERIC_EXECUTE | AccessMask::WRITE_PROPERTY
);
}
#[test]
fn test_complex_mask2() {
assert_eq!(AccessMask::try_from("FA").unwrap(), *FILE_ALL);
}
#[test]
fn test_statics() {
assert_eq!(FILE_ALL.bits(), 0x001F01FF);
assert_eq!(FILE_EXECUTE.bits(), 0x001200A0);
assert_eq!(FILE_WRITE.bits(), 0x00120116);
assert_eq!(FILE_READ.bits(), 0x00120089);
assert_eq!(KEY_ALL.bits(), 0x000F003F);
assert_eq!(KEY_READ.bits(), 0x00020019);
assert_eq!(KEY_EXECUTE.bits(), 0x00020019);
assert_eq!(KEY_WRITE.bits(), 0x00020006);
}
}