Skip to content

Commit

Permalink
security.go: add and use InitializeAcl and SetNamedSecurityInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
alexbrainman committed Nov 16, 2017
1 parent c959b37 commit eca66af
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 1 deletion.
2 changes: 1 addition & 1 deletion mksyscall.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

package winapi

//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go winapi.go serial.go tls.go memory.go
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go winapi.go serial.go tls.go memory.go security.go
48 changes: 48 additions & 0 deletions security.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build windows

package winapi

const (
ACL_REVISION = 2

SE_UNKNOWN_OBJECT_TYPE = 0
SE_FILE_OBJECT = 1
SE_SERVICE = 2
SE_PRINTER = 3
SE_REGISTRY_KEY = 4
SE_LMSHARE = 5
SE_KERNEL_OBJECT = 6
SE_WINDOW_OBJECT = 7
SE_DS_OBJECT = 8
SE_DS_OBJECT_ALL = 9
SE_PROVIDER_DEFINED_OBJECT = 10
SE_WMIGUID_OBJECT = 11
SE_REGISTRY_WOW64_32KE = 12

OWNER_SECURITY_INFORMATION = 0x00000001
GROUP_SECURITY_INFORMATION = 0x00000002
DACL_SECURITY_INFORMATION = 0x00000004
SACL_SECURITY_INFORMATION = 0x00000008
LABEL_SECURITY_INFORMATION = 0x00000010
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
)

type ACL struct {
AclRevision byte
Sbz1 byte
AclSize uint16
AceCount uint16
Sbz2 uint16
}

type SECURITY_INFORMATION uint32

//sys InitializeAcl(acl *ACL, acllen uint32, aclrev uint32) (err error) = advapi32.InitializeAcl
//sys SetNamedSecurityInfo(objname *uint16, objtype int32, secinfo SECURITY_INFORMATION, owner *syscall.SID, group *syscall.SID, dacl *ACL, sacl *ACL) (errno uint32) = advapi32.SetNamedSecurityInfoW
86 changes: 86 additions & 0 deletions winapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
package winapi_test

import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"syscall"
"testing"
Expand Down Expand Up @@ -96,3 +101,84 @@ func TestTls(t *testing.T) {
<-done
}
}

func runIcacls(t *testing.T, args ...string) string {
t.Helper()
out, err := exec.Command("icacls", args...).CombinedOutput()
if err != nil {
t.Fatalf("icacls failed: %v\n%v", err, string(out))
}
return string(out)
}

func adjustACL(t *testing.T, path string) {
// as described in
// https://stackoverflow.com/questions/17536692/resetting-file-security-to-inherit-after-a-movefile-operation
var acl winapi.ACL
err := winapi.InitializeAcl(&acl, uint32(unsafe.Sizeof(acl)), winapi.ACL_REVISION)
if err != nil {
t.Fatal(err)
}
errno := winapi.SetNamedSecurityInfo(syscall.StringToUTF16Ptr(path), winapi.SE_FILE_OBJECT, winapi.DACL_SECURITY_INFORMATION|winapi.UNPROTECTED_DACL_SECURITY_INFORMATION, nil, nil, &acl, nil)
if errno != 0 {
t.Fatalf("SetNamedSecurityInfo failed: %v", syscall.Errno(errno))
}
}

func runGetACL(t *testing.T, path string) string {
t.Helper()
cmd := fmt.Sprintf(`Get-Acl "%s" | Select -expand AccessToString`, path)
out, err := exec.Command("powershell", "-Command", cmd).CombinedOutput()
if err != nil {
t.Fatalf("Get-Acl failed: %v\n%v", err, string(out))
}
return string(out)
}

func TestIssue22343(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "TestIssue22343")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)

newtmpdir := filepath.Join(tmpdir, "tmp")
err = os.Mkdir(newtmpdir, 0777)
if err != nil {
t.Fatal(err)
}

// When TestIssue22343/tmp directory is created, it will have
// the same security attributes as TestIssue22343.
// Add Guest account full access to TestIssue22343/tmp - this
// will make all files created in TestIssue22343/tmp have different
// security attributes to the files created in TestIssue22343.
runIcacls(t, newtmpdir,
"/inheritance:r", // breaks the inheritance from the directory above
"/grant:r", // clears the ACL
"guest:(oi)(ci)f", // Guest user will have full access
)

src := filepath.Join(tmpdir, "main.go")
err = ioutil.WriteFile(src, []byte("package main; func main() { }\n"), 0644)
if err != nil {
t.Fatal(err)
}
exe := filepath.Join(tmpdir, "main.exe")
cmd := exec.Command("go", "build", "-o", exe, src)
cmd.Env = append(os.Environ(),
"TMP="+newtmpdir,
"TEMP="+newtmpdir,
)
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("go command failed: %v\n%v", err, string(out))
}

adjustACL(t, exe)

// exe file is expected to have the same security atributes as the src.
if got, expected := runGetACL(t, exe), runGetACL(t, src); got != expected {
t.Fatalf("expected Get-Acl output of \n%v\n, got \n%v\n", expected, got)
}
}
21 changes: 21 additions & 0 deletions zsyscall_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func errnoErr(e syscall.Errno) error {

var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")

procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx")
procGetProcessHandleCount = modkernel32.NewProc("GetProcessHandleCount")
Expand All @@ -56,6 +57,8 @@ var (
procVirtualAlloc = modkernel32.NewProc("VirtualAlloc")
procVirtualFree = modkernel32.NewProc("VirtualFree")
procVirtualProtect = modkernel32.NewProc("VirtualProtect")
procInitializeAcl = modadvapi32.NewProc("InitializeAcl")
procSetNamedSecurityInfoW = modadvapi32.NewProc("SetNamedSecurityInfoW")
)

func GlobalMemoryStatusEx(buf *MEMORYSTATUSEX) (err error) {
Expand Down Expand Up @@ -258,3 +261,21 @@ func VirtualProtect(address uintptr, size uintptr, newprotect uint32, oldprotect
}
return
}

func InitializeAcl(acl *ACL, acllen uint32, aclrev uint32) (err error) {
r1, _, e1 := syscall.Syscall(procInitializeAcl.Addr(), 3, uintptr(unsafe.Pointer(acl)), uintptr(acllen), uintptr(aclrev))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}

func SetNamedSecurityInfo(objname *uint16, objtype int32, secinfo SECURITY_INFORMATION, owner *syscall.SID, group *syscall.SID, dacl *ACL, sacl *ACL) (errno uint32) {
r0, _, _ := syscall.Syscall9(procSetNamedSecurityInfoW.Addr(), 7, uintptr(unsafe.Pointer(objname)), uintptr(objtype), uintptr(secinfo), uintptr(unsafe.Pointer(owner)), uintptr(unsafe.Pointer(group)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0)
errno = uint32(r0)
return
}

0 comments on commit eca66af

Please sign in to comment.