Skip to content

windows: add GetAce Windows API #191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion windows/security_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,7 @@ type ACL struct {
aclRevision byte
sbz1 byte
aclSize uint16
aceCount uint16
AceCount uint16
sbz2 uint16
}

Expand Down Expand Up @@ -1086,6 +1086,27 @@ type EXPLICIT_ACCESS struct {
Trustee TRUSTEE
}

// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
type ACE_HEADER struct {
AceType uint8
AceFlags uint8
AceSize uint16
}

// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-access_allowed_ace
type ACCESS_ALLOWED_ACE struct {
Header ACE_HEADER
Mask ACCESS_MASK
SidStart uint32
}

const (
// Constants for AceType
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
ACCESS_ALLOWED_ACE_TYPE = 0
ACCESS_DENIED_ACE_TYPE = 1
)

// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
type TrusteeValue uintptr

Expand Down Expand Up @@ -1157,6 +1178,7 @@ type OBJECTS_AND_NAME struct {
//sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD

//sys setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) = advapi32.SetEntriesInAclW
//sys GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (ret error) = advapi32.GetAce

// Control returns the security descriptor control bits.
func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) {
Expand Down
162 changes: 162 additions & 0 deletions windows/syscall_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,168 @@ func TestBuildSecurityDescriptor(t *testing.T) {
}
}

// getEntriesFromACL returns a list of explicit access control entries associated with the given ACL.
func getEntriesFromACL(acl *windows.ACL) (aces []*windows.ACCESS_ALLOWED_ACE, err error) {
aces = make([]*windows.ACCESS_ALLOWED_ACE, acl.AceCount)

for i := uint16(0); i < acl.AceCount; i++ {
err = windows.GetAce(acl, uint32(i), &aces[i])
if err != nil {
return nil, err
}
}

return aces, nil
}

func TestGetACEsFromACL(t *testing.T) {
// Create a temporary file to set ACLs on and test getting the ACEs from the ACL.
f, err := os.CreateTemp("", "foo.lish")
defer os.Remove(f.Name())

if err = f.Close(); err != nil {
t.Fatal(err)
}

// Well-known SID Strings:
// https://support.microsoft.com/en-us/help/243330/well-known-security-identifiers-in-windows-operating-systems
ownerSid, err := windows.StringToSid("S-1-3-2")
if err != nil {
t.Fatal(err)
}
groupSid, err := windows.StringToSid("S-1-3-3")
if err != nil {
t.Fatal(err)
}
worldSid, err := windows.StringToSid("S-1-1-0")
if err != nil {
t.Fatal(err)
}

ownerPermissions := windows.ACCESS_MASK(windows.GENERIC_ALL)
groupPermissions := windows.ACCESS_MASK(windows.GENERIC_READ | windows.GENERIC_EXECUTE)
worldPermissions := windows.ACCESS_MASK(windows.GENERIC_READ)

access := []windows.EXPLICIT_ACCESS{
{
AccessPermissions: ownerPermissions,
AccessMode: windows.GRANT_ACCESS,
Trustee: windows.TRUSTEE{
TrusteeForm: windows.TRUSTEE_IS_SID,
TrusteeValue: windows.TrusteeValueFromSID(ownerSid),
},
},
{
AccessPermissions: groupPermissions,
AccessMode: windows.GRANT_ACCESS,
Trustee: windows.TRUSTEE{
TrusteeForm: windows.TRUSTEE_IS_SID,
TrusteeType: windows.TRUSTEE_IS_GROUP,
TrusteeValue: windows.TrusteeValueFromSID(groupSid),
},
},
{
AccessPermissions: worldPermissions,
AccessMode: windows.GRANT_ACCESS,
Trustee: windows.TRUSTEE{
TrusteeForm: windows.TRUSTEE_IS_SID,
TrusteeType: windows.TRUSTEE_IS_GROUP,
TrusteeValue: windows.TrusteeValueFromSID(worldSid),
},
},
}

acl, err := windows.ACLFromEntries(access, nil)
if err != nil {
t.Fatal(err)
}

// Set new ACL.
err = windows.SetNamedSecurityInfo(
f.Name(),
windows.SE_FILE_OBJECT,
windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION,
nil,
nil,
acl,
nil,
)
if err != nil {
t.Fatal(err)
}

descriptor, err := windows.GetNamedSecurityInfo(
f.Name(),
windows.SE_FILE_OBJECT,
windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION|windows.OWNER_SECURITY_INFORMATION|windows.GROUP_SECURITY_INFORMATION,
)
if err != nil {
t.Fatal(err)
}

dacl, _, err := descriptor.DACL()
if err != nil {
t.Fatal(err)
}

owner, _, err := descriptor.Owner()
if err != nil {
t.Fatal(err)
}

group, _, err := descriptor.Group()
if err != nil {
t.Fatal(err)
}

entries, err := getEntriesFromACL(dacl)
if err != nil {
t.Fatal(err)
}

if len(entries) != 3 {
t.Fatalf("Expected newly set ACL to only have 3 entries.")
}

// https://docs.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
read := uint32(windows.FILE_READ_DATA | windows.FILE_READ_ATTRIBUTES)
write := uint32(windows.FILE_WRITE_DATA | windows.FILE_APPEND_DATA | windows.FILE_WRITE_ATTRIBUTES | windows.FILE_WRITE_EA)
execute := uint32(windows.FILE_READ_DATA | windows.FILE_EXECUTE)

// Check the set ACEs. We should have the equivalent of 754.
for _, entry := range entries {
mask := uint32(entry.Mask)
actual := 0

if mask&read == read {
actual |= 4
}
if mask&write == write {
actual |= 2
}
if mask&execute == execute {
actual |= 1
}

entrySid := (*windows.SID)(unsafe.Pointer(&entry.SidStart))
if owner.Equals(entrySid) {
if actual != 7 {
t.Fatalf("Expected owner to have FullAccess permissions.")
}
} else if group.Equals(entrySid) {
if actual != 5 {
t.Fatalf("Expected group to have only Read and Execute permissions.")
}
} else if worldSid.Equals(entrySid) {
if actual != 4 {
t.Fatalf("Expected the World to have only Read permissions.")
}
} else {
t.Fatalf("Unexpected SID in ACEs: %s", entrySid.String())
}
}
}

func TestGetDiskFreeSpaceEx(t *testing.T) {
cwd, err := windows.UTF16PtrFromString(".")
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions windows/zsyscall_windows.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.