Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

NT ↔ POSIX ACL Translation

Translating between Windows Security Descriptors and POSIX ACLs is the core problem in Samba, NFS-ACL, and CIFS-to-NFSv4 interoperability. The nt_posix_translate example demonstrates three approaches, from lossy to lossless.

Run the example:

cargo run -p bac-examples --example nt_posix_translate

The impedance mismatch

Windows NT ACLs and POSIX.1e ACLs model different permission universes:

AspectNTPOSIX
Permission granularity32-bit mask (14+ distinct rights)3-bit rwx
Deny supportExplicit deny ACEsNone
InheritancePer-ACE flags (CI, OI, NP, IO)Default ACL only
AuditSACL with audit ACEsNone
IntegrityMandatory integrity labelsNone
Principal identifierSID (structured binary)String (user/group name)

The mapping from NT to POSIX is inherently lossy — information is destroyed in both directions.

Path 1: Direct translation (lossy)

The simplest approach maps each allow ACE to a POSIX entry:

  • FILE_READ_DATA → read
  • FILE_WRITE_DATA | FILE_APPEND_DATA → write
  • FILE_EXECUTE → execute

SIDs are mapped to POSIX names via an identity map (analogous to Samba’s idmap or SSSD).

What’s lost: deny ACEs (no POSIX equivalent), standard rights (READ_CONTROL, WRITE_DAC, WRITE_OWNER, SYNCHRONIZE), extended attributes (FILE_READ_EA, FILE_WRITE_EA), FILE_DELETE_CHILD, inheritance flags, SACL, integrity labels.

Path 2: Out-of-band metadata (lossless)

Like Samba’s security.NTACL extended attribute: store the original NT SD binary alongside the POSIX ACL. The POSIX ACL is the live access control for POSIX clients, but the full SD is preserved for lossless restoration when a Windows client requests it.

┌─────────────┐    ┌──────────────────┐
│  POSIX ACL  │    │ security.NTACL   │
│  (live)     │    │ (268 bytes blob) │
│  user::rwx  │    │ Full SD with     │
│  group::rw- │    │ deny ACEs, SACL, │
│  other::r-- │    │ control flags... │
└─────────────┘    └──────────────────┘

Pros: Complete preservation of the original SD. Restore is always lossless.
Cons: Requires out-of-band storage. The POSIX ACL and NT SD can diverge if modified independently.

Path 3: PermissionSet with opaque masks (lossless per-ACE)

Encode the full 32-bit AccessMask per-ACE as nt_raw:SID:0xMASK inside the acls-rs PermissionSet, alongside the decomposed win:* permissions. No out-of-band storage needed — everything lives within the PermissionSet model.

PermissionSet {
    win:file_read_data        ← decomposed (for querying)
    win:read_control          ← decomposed
    ...
    nt_raw:S-1-5-32-544:0x001F01FF  ← original mask (for restoration)
    nt_raw:S-1-1-0:0x00000081       ← original mask
}

Pros: Self-contained, no out-of-band storage. Lossless for the ACEs that match the token.
Cons: Only preserves allow ACEs for the queried token’s SIDs (not the full SD). Deny ACEs and SACL are not captured.

Choosing an approach

ApproachFidelityStorageUse case
DirectLossyNoneQuick mapping, POSIX-only consumers
Out-of-bandFull SDxattr/sidecarSamba, dual-protocol file servers
PermissionSetPer-ACEIn-memoryApplication-level policy comparison