Skip to content
11 changes: 2 additions & 9 deletions windows/env_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package windows

import (
"syscall"
"unicode/utf16"
"unsafe"
)

Expand Down Expand Up @@ -40,17 +39,11 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) {
defer DestroyEnvironmentBlock(block)
blockp := uintptr(unsafe.Pointer(block))
for {
entry := (*[(1 << 30) - 1]uint16)(unsafe.Pointer(blockp))[:]
for i, v := range entry {
if v == 0 {
entry = entry[:i]
break
}
}
entry := UTF16PtrToString((*uint16)(unsafe.Pointer(blockp)))
if len(entry) == 0 {
break
}
env = append(env, string(utf16.Decode(entry)))
env = append(env, entry)
blockp += 2 * (uintptr(len(entry)) + 1)
}
return env, nil
Expand Down
20 changes: 15 additions & 5 deletions windows/security_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package windows
import (
"syscall"
"unsafe"

"golang.org/x/sys/internal/unsafeheader"
)

const (
Expand Down Expand Up @@ -1229,7 +1231,7 @@ func (sd *SECURITY_DESCRIPTOR) String() string {
return ""
}
defer LocalFree(Handle(unsafe.Pointer(sddl)))
return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(sddl))[:])
return UTF16PtrToString(sddl)
}

// ToAbsolute converts a self-relative security descriptor into an absolute one.
Expand Down Expand Up @@ -1307,9 +1309,17 @@ func (absoluteSD *SECURITY_DESCRIPTOR) ToSelfRelative() (selfRelativeSD *SECURIT
}

func (selfRelativeSD *SECURITY_DESCRIPTOR) copySelfRelativeSecurityDescriptor() *SECURITY_DESCRIPTOR {
sdBytes := make([]byte, selfRelativeSD.Length())
copy(sdBytes, (*[(1 << 31) - 1]byte)(unsafe.Pointer(selfRelativeSD))[:len(sdBytes)])
return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&sdBytes[0]))
sdLen := (int)(selfRelativeSD.Length())

var src []byte
h := (*unsafeheader.Slice)(unsafe.Pointer(&src))
h.Data = unsafe.Pointer(selfRelativeSD)
h.Len = sdLen
h.Cap = sdLen

dst := make([]byte, sdLen)
copy(dst, src)
return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&dst[0]))
}

// SecurityDescriptorFromString converts an SDDL string describing a security descriptor into a
Expand Down Expand Up @@ -1391,6 +1401,6 @@ func ACLFromEntries(explicitEntries []EXPLICIT_ACCESS, mergedACL *ACL) (acl *ACL
}
defer LocalFree(Handle(unsafe.Pointer(winHeapACL)))
aclBytes := make([]byte, winHeapACL.aclSize)
copy(aclBytes, (*[(1 << 31) - 1]byte)(unsafe.Pointer(winHeapACL))[:len(aclBytes)])
copy(aclBytes, (*[(1 << 31) - 1]byte)(unsafe.Pointer(winHeapACL))[:len(aclBytes):len(aclBytes)])
return (*ACL)(unsafe.Pointer(&aclBytes[0])), nil
}
40 changes: 16 additions & 24 deletions windows/svc/mgr/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package mgr

import (
"syscall"
"unicode/utf16"
"unsafe"

"golang.org/x/sys/windows"
Expand Down Expand Up @@ -46,28 +45,21 @@ type Config struct {
DelayedAutoStart bool // the service is started after other auto-start services are started plus a short delay
}

func toString(p *uint16) string {
if p == nil {
return ""
}
return syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(p))[:])
}

func toStringSlice(ps *uint16) []string {
if ps == nil {
return nil
}
r := make([]string, 0)
for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(ps)); true; i++ {
if p[i] == 0 {
// empty string marks the end
if i <= from {
break
}
r = append(r, string(utf16.Decode(p[from:i])))
from = i + 1
p := unsafe.Pointer(ps)

for {
s := windows.UTF16PtrToString((*uint16)(p))
if len(s) == 0 {
break
}

r = append(r, s)
offset := unsafe.Sizeof(uint16(0)) * (uintptr)(len(s)+1)
p = unsafe.Pointer(uintptr(p) + offset)
}

return r
}

Expand Down Expand Up @@ -110,13 +102,13 @@ func (s *Service) Config() (Config, error) {
ServiceType: p.ServiceType,
StartType: p.StartType,
ErrorControl: p.ErrorControl,
BinaryPathName: toString(p.BinaryPathName),
LoadOrderGroup: toString(p.LoadOrderGroup),
BinaryPathName: windows.UTF16PtrToString(p.BinaryPathName),
LoadOrderGroup: windows.UTF16PtrToString(p.LoadOrderGroup),
TagId: p.TagId,
Dependencies: toStringSlice(p.Dependencies),
ServiceStartName: toString(p.ServiceStartName),
DisplayName: toString(p.DisplayName),
Description: toString(p2.Description),
ServiceStartName: windows.UTF16PtrToString(p.ServiceStartName),
DisplayName: windows.UTF16PtrToString(p.DisplayName),
Description: windows.UTF16PtrToString(p2.Description),
DelayedAutoStart: delayedStart,
}, nil
}
Expand Down
13 changes: 10 additions & 3 deletions windows/svc/mgr/mgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"unicode/utf16"
"unsafe"

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

Expand Down Expand Up @@ -73,7 +74,7 @@ func (m *Mgr) LockStatus() (*LockStatus, error) {
status := &LockStatus{
IsLocked: lockStatus.IsLocked != 0,
Age: time.Duration(lockStatus.LockDuration) * time.Second,
Owner: windows.UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(lockStatus.LockOwner))[:]),
Owner: windows.UTF16PtrToString(lockStatus.LockOwner),
}
return status, nil
}
Expand Down Expand Up @@ -201,10 +202,16 @@ func (m *Mgr) ListServices() ([]string, error) {
if servicesReturned == 0 {
return nil, nil
}
services := (*[1 << 20]windows.ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0]))[:servicesReturned]

var services []windows.ENUM_SERVICE_STATUS_PROCESS
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&services))
hdr.Data = unsafe.Pointer(&buf[0])
hdr.Len = int(servicesReturned)
hdr.Cap = int(servicesReturned)

var names []string
for _, s := range services {
name := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(s.ServiceName))[:])
name := windows.UTF16PtrToString(s.ServiceName)
names = append(names, name)
}
return names, nil
Expand Down
12 changes: 9 additions & 3 deletions windows/svc/mgr/recovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"
"unsafe"

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

Expand Down Expand Up @@ -68,8 +69,13 @@ func (s *Service) RecoveryActions() ([]RecoveryAction, error) {
return nil, err
}

var actions []windows.SC_ACTION
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&actions))
hdr.Data = unsafe.Pointer(p.Actions)
hdr.Len = int(p.ActionsCount)
hdr.Cap = int(p.ActionsCount)

var recoveryActions []RecoveryAction
actions := (*[1024]windows.SC_ACTION)(unsafe.Pointer(p.Actions))[:p.ActionsCount]
for _, action := range actions {
recoveryActions = append(recoveryActions, RecoveryAction{Type: int(action.Type), Delay: time.Duration(action.Delay) * time.Millisecond})
}
Expand Down Expand Up @@ -112,7 +118,7 @@ func (s *Service) RebootMessage() (string, error) {
return "", err
}
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
return toString(p.RebootMsg), nil
return windows.UTF16PtrToString(p.RebootMsg), nil
}

// SetRecoveryCommand sets the command line of the process to execute in response to the RunCommand service controller action.
Expand All @@ -131,5 +137,5 @@ func (s *Service) RecoveryCommand() (string, error) {
return "", err
}
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
return toString(p.Command), nil
return windows.UTF16PtrToString(p.Command), nil
}
7 changes: 2 additions & 5 deletions windows/svc/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
package svc

import (
"unsafe"

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

Expand Down Expand Up @@ -48,9 +46,8 @@ func IsAnInteractiveSession() (bool, error) {
if err != nil {
return false, err
}
p := unsafe.Pointer(&gs.Groups[0])
groups := (*[2 << 20]windows.SIDAndAttributes)(p)[:gs.GroupCount]
for _, g := range groups {

for _, g := range gs.AllGroups() {
if windows.EqualSid(g.Sid, interSid) {
return true, nil
}
Expand Down
11 changes: 9 additions & 2 deletions windows/svc/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"syscall"
"unsafe"

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

Expand Down Expand Up @@ -224,10 +225,16 @@ const (
func (s *service) run() {
s.goWaits.Wait()
s.h = windows.Handle(ssHandle)
argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc]

var argv []*uint16
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&argv))
hdr.Data = unsafe.Pointer(sArgv)
hdr.Len = int(sArgc)
hdr.Cap = int(sArgc)

args := make([]string, len(argv))
for i, a := range argv {
args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:])
args[i] = windows.UTF16PtrToString(a)
}

cmdsToHandler := make(chan ChangeRequest)
Expand Down
30 changes: 29 additions & 1 deletion windows/syscall_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"time"
"unicode/utf16"
"unsafe"

"golang.org/x/sys/internal/unsafeheader"
)

type Handle uintptr
Expand Down Expand Up @@ -117,6 +119,32 @@ func UTF16PtrFromString(s string) (*uint16, error) {
return &a[0], nil
}

// UTF16PtrToString takes a pointer to a UTF-16 sequence and returns the corresponding UTF-8 encoded string.
// If the pointer is nil, this returns the empty string. This assumes that the UTF-16 sequence is terminated
// at a zero word; if the zero word is not present, the program may crash.
func UTF16PtrToString(p *uint16) string {
if p == nil {
return ""
}
if *p == 0 {
return ""
}

// Find NUL terminator.
n := 0
for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ {
ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p))
}

var s []uint16
h := (*unsafeheader.Slice)(unsafe.Pointer(&s))
h.Data = unsafe.Pointer(p)
h.Len = n
h.Cap = n

return string(utf16.Decode(s))
}

func Getpagesize() int { return 4096 }

// NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention.
Expand Down Expand Up @@ -1383,7 +1411,7 @@ func (t Token) KnownFolderPath(folderID *KNOWNFOLDERID, flags uint32) (string, e
return "", err
}
defer CoTaskMemFree(unsafe.Pointer(p))
return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:]), nil
return UTF16PtrToString(p), nil
}

// RtlGetVersion returns the version of the underlying operating system, ignoring
Expand Down