ACEs and Security Descriptors
ACE types
The AceType enum covers all 21 MS-DTYP ACE type variants:
| Category | Types | SDDL | Numeric |
|---|---|---|---|
| Basic | AccessAllowed, AccessDenied | A, D | 0x00, 0x01 |
| Audit | SystemAudit, SystemAlarm | AU, AL | 0x02, 0x03 |
| Object | AccessAllowedObject, AccessDeniedObject, SystemAuditObject, SystemAlarmObject | OA, OD, OU, OL | 0x05–0x08 |
| Callback | AccessAllowedCallback, AccessDeniedCallback, + Object variants | XA, XD, ZA, ZD, XU, XL, ZU, ZL | 0x09–0x10 |
| Special | SystemMandatoryLabel, SystemResourceAttribute, SystemScopedPolicyId | ML, RA, SP | 0x11–0x13 |
Classification methods: is_allow(), is_deny(), is_audit(),
is_object_type(), is_callback(), is_mandatory_label(),
is_dacl_type(), is_sacl_type().
ACE flags
Inheritance and audit flags on each ACE:
#![allow(unused)]
fn main() {
use win_sd::AceFlags;
let flags = AceFlags::CONTAINER_INHERIT | AceFlags::OBJECT_INHERIT;
assert!(flags.contains(AceFlags::CONTAINER_INHERIT));
assert!(!flags.is_inherited());
}
| Flag | Value | Meaning |
|---|---|---|
OBJECT_INHERIT | 0x01 | Non-container children inherit |
CONTAINER_INHERIT | 0x02 | Container children inherit |
NO_PROPAGATE_INHERIT | 0x04 | Stop propagation to grandchildren |
INHERIT_ONLY | 0x08 | Does not apply to this object |
INHERITED_ACE | 0x10 | Was inherited from parent |
SUCCESSFUL_ACCESS | 0x40 | Audit on success (SACL) |
FAILED_ACCESS | 0x80 | Audit on failure (SACL) |
ACE entries
An Ace carries type, flags, mask, SID, and optional GUID/application data:
#![allow(unused)]
fn main() {
use win_sd::{Ace, AccessMask, Sid};
// Convenience constructors
let allow = Ace::allow(Sid::everyone(), AccessMask::FILE_GENERIC_READ);
let deny = Ace::deny(Sid::anonymous(), AccessMask::FILE_ALL_ACCESS);
let audit = Ace::audit(Sid::everyone(), AccessMask::FILE_WRITE_DATA);
// Object ACE with GUID
let guid = "bf967aba-0de6-11d0-a285-00aa003049e2".parse().unwrap();
let obj_ace = Ace::allow_object(
Sid::administrators(),
AccessMask::new(0x0010), // ADS_RIGHT_DS_READ_PROP
Some(guid),
None,
);
assert!(obj_ace.ace_type().is_object_type());
assert!(obj_ace.object_type().is_some());
}
WinAcl
An ordered collection of ACEs, used for both DACLs and SACLs:
#![allow(unused)]
fn main() {
use win_sd::{WinAcl, Ace, AccessMask, Sid};
let mut acl = WinAcl::new();
acl.add_ace(Ace::deny(Sid::anonymous(), AccessMask::FILE_ALL_ACCESS));
acl.add_ace(Ace::allow(Sid::everyone(), AccessMask::FILE_GENERIC_READ));
assert!(acl.is_canonical()); // deny before allow
assert_eq!(acl.ace_count(), 2);
// Canonicalize sorts into MS-recommended order:
// explicit deny → explicit allow → inherited deny → inherited allow
acl.canonicalize();
}
SecurityDescriptor
The top-level container:
#![allow(unused)]
fn main() {
use win_sd::{SecurityDescriptor, SecurityDescriptorBuilder, AccessMask, Sid};
use win_sd::{IntegrityLevel, IntegrityPolicy};
let sd = SecurityDescriptorBuilder::new()
.owner(Sid::local_system())
.group(Sid::administrators())
.deny(Sid::anonymous(), AccessMask::FILE_ALL_ACCESS)
.allow(Sid::administrators(), AccessMask::FILE_ALL_ACCESS)
.allow(Sid::everyone(), AccessMask::FILE_GENERIC_READ)
.mandatory_label(IntegrityLevel::High, IntegrityPolicy::NO_WRITE_UP)
.protected_dacl(true)
.build();
assert!(sd.is_valid().is_ok());
assert!(sd.control().dacl_present());
assert!(sd.control().dacl_protected());
assert!(sd.dacl().unwrap().is_canonical());
assert!(sd.sacl().is_some()); // mandatory label is in the SACL
}
The builder automatically sets DACL_PRESENT/SACL_PRESENT flags and
canonicalizes ACE ordering.