Skip to content

Commit

Permalink
Add lookup of account names by SID
Browse files Browse the repository at this point in the history
This commit adds a new function LookupNameBySid that wraps
LookupAccountSidW and works as an inverse of the already existing
LookupSidByName. In addition to offering new functionality, this
fixes #202.

Signed-off-by: Michael Hofmann <michael.hofmann@bitgestalt.com>
  • Loading branch information
mversiotech committed Feb 9, 2022
1 parent 01a3671 commit c5190c0
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 3 deletions.
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.UTF16FromString(sid)
if err != nil {
return "", &AccountLookupError{sid, err}
}

var sidPtr *byte
if err = convertStringSidToSid(&sidBuffer[0], &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
}

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.

0 comments on commit c5190c0

Please sign in to comment.