mirror of
https://github.com/rwinkhart/sys.git
synced 2026-09-05 08:37:31 -04:00
windows: add GetAce Windows API
GetAce obtains a pointer to an access control entry (ACE) in an discretionary access control list (DACL), which controls access to an object. Adds the ACE_HEADER and ACCESS_ALLOWED_ACE structs. Adds GetEntriesFromACL function which returns an array of ACEs from the given ACL if no errors have been encountered. References: - https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header - https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-access_allowed_ace - https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-getace Fixes golang/go#66850 Change-Id: I98306ff7e947e586a58d563d364169a2555492f4 GitHub-Last-Rev: d14ca7fb0b8103294fd7c09ee3469ff6f9556508 GitHub-Pull-Request: golang/sys#191 Reviewed-on: https://go-review.googlesource.com/c/sys/+/578976 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
This commit is contained in:
committed by
Damien Neil
parent
348425aa18
commit
76700875df
@@ -894,7 +894,7 @@ type ACL struct {
|
|||||||
aclRevision byte
|
aclRevision byte
|
||||||
sbz1 byte
|
sbz1 byte
|
||||||
aclSize uint16
|
aclSize uint16
|
||||||
aceCount uint16
|
AceCount uint16
|
||||||
sbz2 uint16
|
sbz2 uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1087,6 +1087,27 @@ type EXPLICIT_ACCESS struct {
|
|||||||
Trustee TRUSTEE
|
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.
|
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
|
||||||
type TrusteeValue uintptr
|
type TrusteeValue uintptr
|
||||||
|
|
||||||
@@ -1158,6 +1179,7 @@ type OBJECTS_AND_NAME struct {
|
|||||||
//sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD
|
//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 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.
|
// Control returns the security descriptor control bits.
|
||||||
func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) {
|
func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) {
|
||||||
|
|||||||
@@ -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) {
|
func TestGetDiskFreeSpaceEx(t *testing.T) {
|
||||||
cwd, err := windows.UTF16PtrFromString(".")
|
cwd, err := windows.UTF16PtrFromString(".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ var (
|
|||||||
procEnumServicesStatusExW = modadvapi32.NewProc("EnumServicesStatusExW")
|
procEnumServicesStatusExW = modadvapi32.NewProc("EnumServicesStatusExW")
|
||||||
procEqualSid = modadvapi32.NewProc("EqualSid")
|
procEqualSid = modadvapi32.NewProc("EqualSid")
|
||||||
procFreeSid = modadvapi32.NewProc("FreeSid")
|
procFreeSid = modadvapi32.NewProc("FreeSid")
|
||||||
|
procGetAce = modadvapi32.NewProc("GetAce")
|
||||||
procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
|
procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
|
||||||
procGetNamedSecurityInfoW = modadvapi32.NewProc("GetNamedSecurityInfoW")
|
procGetNamedSecurityInfoW = modadvapi32.NewProc("GetNamedSecurityInfoW")
|
||||||
procGetSecurityDescriptorControl = modadvapi32.NewProc("GetSecurityDescriptorControl")
|
procGetSecurityDescriptorControl = modadvapi32.NewProc("GetSecurityDescriptorControl")
|
||||||
@@ -1224,6 +1225,14 @@ func setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCE
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (ret error) {
|
||||||
|
r0, _, _ := syscall.Syscall(procGetAce.Addr(), 3, uintptr(unsafe.Pointer(acl)), uintptr(aceIndex), uintptr(unsafe.Pointer(pAce)))
|
||||||
|
if r0 == 0 {
|
||||||
|
ret = GetLastError()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func SetKernelObjectSecurity(handle Handle, securityInformation SECURITY_INFORMATION, securityDescriptor *SECURITY_DESCRIPTOR) (err error) {
|
func SetKernelObjectSecurity(handle Handle, securityInformation SECURITY_INFORMATION, securityDescriptor *SECURITY_DESCRIPTOR) (err error) {
|
||||||
r1, _, e1 := syscall.Syscall(procSetKernelObjectSecurity.Addr(), 3, uintptr(handle), uintptr(securityInformation), uintptr(unsafe.Pointer(securityDescriptor)))
|
r1, _, e1 := syscall.Syscall(procSetKernelObjectSecurity.Addr(), 3, uintptr(handle), uintptr(securityInformation), uintptr(unsafe.Pointer(securityDescriptor)))
|
||||||
if r1 == 0 {
|
if r1 == 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user