blob: db1b370a1b57d1f92ac674f786cb76bec79129c3 [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001// +build windows
2
3package winio
4
5import (
6 "syscall"
7 "unsafe"
8)
9
10//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
11//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
12//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
13//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
14//sys localFree(mem uintptr) = LocalFree
15//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
16
17const (
18 cERROR_NONE_MAPPED = syscall.Errno(1332)
19)
20
21type AccountLookupError struct {
22 Name string
23 Err error
24}
25
26func (e *AccountLookupError) Error() string {
27 if e.Name == "" {
28 return "lookup account: empty account name specified"
29 }
30 var s string
31 switch e.Err {
32 case cERROR_NONE_MAPPED:
33 s = "not found"
34 default:
35 s = e.Err.Error()
36 }
37 return "lookup account " + e.Name + ": " + s
38}
39
40type SddlConversionError struct {
41 Sddl string
42 Err error
43}
44
45func (e *SddlConversionError) Error() string {
46 return "convert " + e.Sddl + ": " + e.Err.Error()
47}
48
49// LookupSidByName looks up the SID of an account by name
50func LookupSidByName(name string) (sid string, err error) {
51 if name == "" {
52 return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
53 }
54
55 var sidSize, sidNameUse, refDomainSize uint32
56 err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
57 if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
58 return "", &AccountLookupError{name, err}
59 }
60 sidBuffer := make([]byte, sidSize)
61 refDomainBuffer := make([]uint16, refDomainSize)
62 err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
63 if err != nil {
64 return "", &AccountLookupError{name, err}
65 }
66 var strBuffer *uint16
67 err = convertSidToStringSid(&sidBuffer[0], &strBuffer)
68 if err != nil {
69 return "", &AccountLookupError{name, err}
70 }
71 sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
72 localFree(uintptr(unsafe.Pointer(strBuffer)))
73 return sid, nil
74}
75
76func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
77 var sdBuffer uintptr
78 err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
79 if err != nil {
80 return nil, &SddlConversionError{sddl, err}
81 }
82 defer localFree(sdBuffer)
83 sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
84 copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
85 return sd, nil
86}
87
88func SecurityDescriptorToSddl(sd []byte) (string, error) {
89 var sddl *uint16
90 // The returned string length seems to including an aribtrary number of terminating NULs.
91 // Don't use it.
92 err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
93 if err != nil {
94 return "", err
95 }
96 defer localFree(uintptr(unsafe.Pointer(sddl)))
97 return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil
98}