Skip to content
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

Add lookup of account names by SID #228

Merged
merged 1 commit into from Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 41 additions & 0 deletions sd.go
Expand Up @@ -5,17 +5,22 @@ package winio
import (
"syscall"
"unsafe"

"golang.org/x/sys/windows"
)

//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
//sys lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountSidW
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
//sys convertStringSidToSid(str *uint16, sid **byte) (err error) = advapi32.ConvertStringSidToSidW
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
//sys localFree(mem uintptr) = LocalFree
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength

const (
cERROR_NONE_MAPPED = syscall.Errno(1332)
cERROR_INVALID_SID = syscall.Errno(1337)
)

type AccountLookupError struct {
Expand All @@ -29,6 +34,8 @@ func (e *AccountLookupError) Error() string {
}
var s string
switch e.Err {
case cERROR_INVALID_SID:
s = "the security ID structure is invalid"
case cERROR_NONE_MAPPED:
s = "not found"
default:
Expand Down Expand Up @@ -73,6 +80,40 @@ func LookupSidByName(name string) (sid string, err error) {
return sid, nil
}

// LookupNameBySid looks up the name of an account by SID
func LookupNameBySid(sid string) (name string, err error) {
if sid == "" {
return "", &AccountLookupError{sid, cERROR_NONE_MAPPED}
}

sidBuffer, err := windows.UTF16PtrFromString(sid)
if err != nil {
return "", &AccountLookupError{sid, err}
}

var sidPtr *byte
if err = convertStringSidToSid(sidBuffer, &sidPtr); err != nil {
return "", &AccountLookupError{sid, err}
}
defer localFree(uintptr(unsafe.Pointer(sidPtr)))

var nameSize, refDomainSize, sidNameUse uint32
err = lookupAccountSid(nil, sidPtr, nil, &nameSize, nil, &refDomainSize, &sidNameUse)
if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER {
return "", &AccountLookupError{sid, err}
}

nameBuffer := make([]uint16, nameSize)
refDomainBuffer := make([]uint16, refDomainSize)
err = lookupAccountSid(nil, sidPtr, &nameBuffer[0], &nameSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
if err != nil {
return "", &AccountLookupError{sid, err}
}

name = windows.UTF16ToString(nameBuffer)
return name, nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I thought we decided to change this to return windows.UTF16ToString(nameBuffer), nil?

}

func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
var sdBuffer uintptr
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
Expand Down
20 changes: 17 additions & 3 deletions sd_test.go
Expand Up @@ -12,10 +12,24 @@ func TestLookupInvalidSid(t *testing.T) {
}
}

func TestLookupInvalidName(t *testing.T) {
_, err := LookupNameBySid("notasid")
aerr, ok := err.(*AccountLookupError)
if !ok || aerr.Err != cERROR_INVALID_SID {
t.Fatalf("expected AccountLookupError with ERROR_INVALID_SID got %s", err)
}
}

func TestLookupValidSid(t *testing.T) {
sid, err := LookupSidByName("Everyone")
if err != nil || sid != "S-1-1-0" {
t.Fatalf("expected S-1-1-0, got %s, %s", sid, err)
everyone := "S-1-1-0"
name, err := LookupNameBySid(everyone)
if err != nil {
t.Fatalf("expected a valid account name, got %v", err)
}

sid, err := LookupSidByName(name)
if err != nil || sid != everyone {
t.Fatalf("expected %s, got %s, %s", everyone, sid, err)
}
}

Expand Down
18 changes: 18 additions & 0 deletions zsyscall_windows.go

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