1// +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} 99