Skip to content

Commit 7670087

Browse files
claudiubeluneild
authored andcommitted
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: d14ca7f GitHub-Pull-Request: #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>
1 parent 348425a commit 7670087

File tree

3 files changed

+194
-1
lines changed

3 files changed

+194
-1
lines changed

windows/security_windows.go

+23-1
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,7 @@ type ACL struct {
894894
aclRevision byte
895895
sbz1 byte
896896
aclSize uint16
897-
aceCount uint16
897+
AceCount uint16
898898
sbz2 uint16
899899
}
900900

@@ -1087,6 +1087,27 @@ type EXPLICIT_ACCESS struct {
10871087
Trustee TRUSTEE
10881088
}
10891089

1090+
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
1091+
type ACE_HEADER struct {
1092+
AceType uint8
1093+
AceFlags uint8
1094+
AceSize uint16
1095+
}
1096+
1097+
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-access_allowed_ace
1098+
type ACCESS_ALLOWED_ACE struct {
1099+
Header ACE_HEADER
1100+
Mask ACCESS_MASK
1101+
SidStart uint32
1102+
}
1103+
1104+
const (
1105+
// Constants for AceType
1106+
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
1107+
ACCESS_ALLOWED_ACE_TYPE = 0
1108+
ACCESS_DENIED_ACE_TYPE = 1
1109+
)
1110+
10901111
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
10911112
type TrusteeValue uintptr
10921113

@@ -1158,6 +1179,7 @@ type OBJECTS_AND_NAME struct {
11581179
//sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD
11591180

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

11621184
// Control returns the security descriptor control bits.
11631185
func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) {

windows/syscall_windows_test.go

+162
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,168 @@ func TestBuildSecurityDescriptor(t *testing.T) {
359359
}
360360
}
361361

362+
// getEntriesFromACL returns a list of explicit access control entries associated with the given ACL.
363+
func getEntriesFromACL(acl *windows.ACL) (aces []*windows.ACCESS_ALLOWED_ACE, err error) {
364+
aces = make([]*windows.ACCESS_ALLOWED_ACE, acl.AceCount)
365+
366+
for i := uint16(0); i < acl.AceCount; i++ {
367+
err = windows.GetAce(acl, uint32(i), &aces[i])
368+
if err != nil {
369+
return nil, err
370+
}
371+
}
372+
373+
return aces, nil
374+
}
375+
376+
func TestGetACEsFromACL(t *testing.T) {
377+
// Create a temporary file to set ACLs on and test getting the ACEs from the ACL.
378+
f, err := os.CreateTemp("", "foo.lish")
379+
defer os.Remove(f.Name())
380+
381+
if err = f.Close(); err != nil {
382+
t.Fatal(err)
383+
}
384+
385+
// Well-known SID Strings:
386+
// https://support.microsoft.com/en-us/help/243330/well-known-security-identifiers-in-windows-operating-systems
387+
ownerSid, err := windows.StringToSid("S-1-3-2")
388+
if err != nil {
389+
t.Fatal(err)
390+
}
391+
groupSid, err := windows.StringToSid("S-1-3-3")
392+
if err != nil {
393+
t.Fatal(err)
394+
}
395+
worldSid, err := windows.StringToSid("S-1-1-0")
396+
if err != nil {
397+
t.Fatal(err)
398+
}
399+
400+
ownerPermissions := windows.ACCESS_MASK(windows.GENERIC_ALL)
401+
groupPermissions := windows.ACCESS_MASK(windows.GENERIC_READ | windows.GENERIC_EXECUTE)
402+
worldPermissions := windows.ACCESS_MASK(windows.GENERIC_READ)
403+
404+
access := []windows.EXPLICIT_ACCESS{
405+
{
406+
AccessPermissions: ownerPermissions,
407+
AccessMode: windows.GRANT_ACCESS,
408+
Trustee: windows.TRUSTEE{
409+
TrusteeForm: windows.TRUSTEE_IS_SID,
410+
TrusteeValue: windows.TrusteeValueFromSID(ownerSid),
411+
},
412+
},
413+
{
414+
AccessPermissions: groupPermissions,
415+
AccessMode: windows.GRANT_ACCESS,
416+
Trustee: windows.TRUSTEE{
417+
TrusteeForm: windows.TRUSTEE_IS_SID,
418+
TrusteeType: windows.TRUSTEE_IS_GROUP,
419+
TrusteeValue: windows.TrusteeValueFromSID(groupSid),
420+
},
421+
},
422+
{
423+
AccessPermissions: worldPermissions,
424+
AccessMode: windows.GRANT_ACCESS,
425+
Trustee: windows.TRUSTEE{
426+
TrusteeForm: windows.TRUSTEE_IS_SID,
427+
TrusteeType: windows.TRUSTEE_IS_GROUP,
428+
TrusteeValue: windows.TrusteeValueFromSID(worldSid),
429+
},
430+
},
431+
}
432+
433+
acl, err := windows.ACLFromEntries(access, nil)
434+
if err != nil {
435+
t.Fatal(err)
436+
}
437+
438+
// Set new ACL.
439+
err = windows.SetNamedSecurityInfo(
440+
f.Name(),
441+
windows.SE_FILE_OBJECT,
442+
windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION,
443+
nil,
444+
nil,
445+
acl,
446+
nil,
447+
)
448+
if err != nil {
449+
t.Fatal(err)
450+
}
451+
452+
descriptor, err := windows.GetNamedSecurityInfo(
453+
f.Name(),
454+
windows.SE_FILE_OBJECT,
455+
windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION|windows.OWNER_SECURITY_INFORMATION|windows.GROUP_SECURITY_INFORMATION,
456+
)
457+
if err != nil {
458+
t.Fatal(err)
459+
}
460+
461+
dacl, _, err := descriptor.DACL()
462+
if err != nil {
463+
t.Fatal(err)
464+
}
465+
466+
owner, _, err := descriptor.Owner()
467+
if err != nil {
468+
t.Fatal(err)
469+
}
470+
471+
group, _, err := descriptor.Group()
472+
if err != nil {
473+
t.Fatal(err)
474+
}
475+
476+
entries, err := getEntriesFromACL(dacl)
477+
if err != nil {
478+
t.Fatal(err)
479+
}
480+
481+
if len(entries) != 3 {
482+
t.Fatalf("Expected newly set ACL to only have 3 entries.")
483+
}
484+
485+
// https://docs.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
486+
read := uint32(windows.FILE_READ_DATA | windows.FILE_READ_ATTRIBUTES)
487+
write := uint32(windows.FILE_WRITE_DATA | windows.FILE_APPEND_DATA | windows.FILE_WRITE_ATTRIBUTES | windows.FILE_WRITE_EA)
488+
execute := uint32(windows.FILE_READ_DATA | windows.FILE_EXECUTE)
489+
490+
// Check the set ACEs. We should have the equivalent of 754.
491+
for _, entry := range entries {
492+
mask := uint32(entry.Mask)
493+
actual := 0
494+
495+
if mask&read == read {
496+
actual |= 4
497+
}
498+
if mask&write == write {
499+
actual |= 2
500+
}
501+
if mask&execute == execute {
502+
actual |= 1
503+
}
504+
505+
entrySid := (*windows.SID)(unsafe.Pointer(&entry.SidStart))
506+
if owner.Equals(entrySid) {
507+
if actual != 7 {
508+
t.Fatalf("Expected owner to have FullAccess permissions.")
509+
}
510+
} else if group.Equals(entrySid) {
511+
if actual != 5 {
512+
t.Fatalf("Expected group to have only Read and Execute permissions.")
513+
}
514+
} else if worldSid.Equals(entrySid) {
515+
if actual != 4 {
516+
t.Fatalf("Expected the World to have only Read permissions.")
517+
}
518+
} else {
519+
t.Fatalf("Unexpected SID in ACEs: %s", entrySid.String())
520+
}
521+
}
522+
}
523+
362524
func TestGetDiskFreeSpaceEx(t *testing.T) {
363525
cwd, err := windows.UTF16PtrFromString(".")
364526
if err != nil {

windows/zsyscall_windows.go

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)