Compare commits
7 Commits
2c283a2864
...
81b2207b81
Author | SHA1 | Date |
---|---|---|
AJ ONeal | 81b2207b81 | |
AJ ONeal | 759dc46f11 | |
AJ ONeal | ce27e9d610 | |
AJ ONeal | 6f178a6de4 | |
AJ ONeal | 3bf23349a1 | |
AJ ONeal | ff57c6cc53 | |
AJ ONeal | c2ce9b4085 |
4
go.mod
4
go.mod
|
@ -1,8 +1,8 @@
|
||||||
module git.rootprojects.org/root/pathman
|
module git.rootprojects.org/root/pathman
|
||||||
|
|
||||||
go 1.12
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.rootprojects.org/root/go-gitver v1.1.3
|
git.rootprojects.org/root/go-gitver v1.1.3
|
||||||
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7
|
golang.org/x/sys v0.14.0
|
||||||
)
|
)
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,4 +1,4 @@
|
||||||
git.rootprojects.org/root/go-gitver v1.1.3 h1:/qR9z53vY+IFhWRxLkF9cjaiWh8xRJIm6gyuW+MG81A=
|
git.rootprojects.org/root/go-gitver v1.1.3 h1:/qR9z53vY+IFhWRxLkF9cjaiWh8xRJIm6gyuW+MG81A=
|
||||||
git.rootprojects.org/root/go-gitver v1.1.3/go.mod h1:Rj1v3TBhvdaSphFEqMynUYwAz/4f+wY/+syBTvRrmlI=
|
git.rootprojects.org/root/go-gitver v1.1.3/go.mod h1:Rj1v3TBhvdaSphFEqMynUYwAz/4f+wY/+syBTvRrmlI=
|
||||||
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 h1:LepdCS8Gf/MVejFIt8lsiexZATdoGVyp5bcyS+rYoUI=
|
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||||
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
|
||||||
|
# NOTE
|
||||||
|
# building for linux on linux seems to yield smaller sizes
|
||||||
|
|
||||||
|
# TODO use the git log describe thing
|
||||||
|
my_version="$(
|
||||||
|
git describe --tags
|
||||||
|
)"
|
||||||
|
export GOOS="linux"
|
||||||
|
|
||||||
|
fn_package() { (
|
||||||
|
if test -n "${GOARM:-}"; then
|
||||||
|
my_arch="${GOARCH}v${GOARM}"
|
||||||
|
elif test -n "${GOAMD64:-}"; then
|
||||||
|
my_arch="${GOARCH}_${GOAMD64}"
|
||||||
|
else
|
||||||
|
my_arch="${GOARCH}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
my_bin="pathman-${my_version}-${GOOS}-${my_arch}"
|
||||||
|
tinygo build -no-debug -o "${my_bin}"
|
||||||
|
strip "${my_bin}" || true
|
||||||
|
|
||||||
|
tar cvf "$my_bin.tar" "$my_bin"
|
||||||
|
gzip --keep "$my_bin.tar"
|
||||||
|
xz --keep "$my_bin.tar"
|
||||||
|
|
||||||
|
echo "$my_bin.tar.xz"
|
||||||
|
); }
|
||||||
|
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
|
export GOAMD64=v1
|
||||||
|
export GOARCH=amd64
|
||||||
|
fn_package
|
||||||
|
export GOAMD64=''
|
||||||
|
|
||||||
|
export GOARCH=386
|
||||||
|
fn_package
|
||||||
|
|
||||||
|
export GOARCH=arm64
|
||||||
|
fn_package
|
||||||
|
|
||||||
|
export GOARCH=arm
|
||||||
|
export GOARM=7
|
||||||
|
fn_package
|
||||||
|
|
||||||
|
export GOARCH=arm
|
||||||
|
export GOARM=6
|
||||||
|
fn_package
|
||||||
|
|
||||||
|
# no longer supported
|
||||||
|
# export GOARCH=arm
|
||||||
|
# export GOARM=5
|
||||||
|
# fn_package
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
|
||||||
|
# NOTE
|
||||||
|
# building for macOS on macOS seems to yield smaller sizes
|
||||||
|
|
||||||
|
my_version="$(
|
||||||
|
git describe --tags
|
||||||
|
)"
|
||||||
|
export GOOS="darwin"
|
||||||
|
|
||||||
|
fn_package() { (
|
||||||
|
if test -n "${GOARM:-}"; then
|
||||||
|
my_arch="${GOARCH}v${GOARM}"
|
||||||
|
elif test -n "${GOAMD64:-}"; then
|
||||||
|
my_arch="${GOARCH}_${GOAMD64}"
|
||||||
|
else
|
||||||
|
my_arch="${GOARCH}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
my_bin="pathman-${my_version}-${GOOS}-${my_arch}"
|
||||||
|
tinygo build -no-debug -o "${my_bin}"
|
||||||
|
strip "${my_bin}" || true
|
||||||
|
|
||||||
|
tar cvf "$my_bin.tar" "$my_bin"
|
||||||
|
gzip --keep "$my_bin.tar"
|
||||||
|
xz --keep "$my_bin.tar"
|
||||||
|
|
||||||
|
echo "$my_bin.tar.xz"
|
||||||
|
); }
|
||||||
|
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
|
export GOAMD64=v2
|
||||||
|
export GOARCH=amd64
|
||||||
|
fn_package
|
||||||
|
export GOAMD64=''
|
||||||
|
|
||||||
|
export GOARCH=arm64
|
||||||
|
fn_package
|
|
@ -0,0 +1,51 @@
|
||||||
|
#!/bin/bin/env pwsh
|
||||||
|
|
||||||
|
# TODO use the git log describe thing
|
||||||
|
$my_version = git describe --tags
|
||||||
|
$Env:GOOS = "windows"
|
||||||
|
|
||||||
|
function fn_package() {
|
||||||
|
IF ($Env:GOARM.Length -gt 0) {
|
||||||
|
$my_arch = "${Env:GOARCH}v${Env:GOARM}"
|
||||||
|
} ELSEIF ($Env:GOAMD64.Length -gt 0) {
|
||||||
|
$my_arch = "${Env:GOARCH}_${Env:GOAMD64}"
|
||||||
|
} ELSE {
|
||||||
|
$my_arch = "${Env:GOARCH}"
|
||||||
|
}
|
||||||
|
|
||||||
|
$my_bin = "pathman-${my_version}-${Env:GOOS}-${my_arch}"
|
||||||
|
tinygo build -no-debug -o "${my_bin}"
|
||||||
|
#strip "${my_bin}" || true
|
||||||
|
|
||||||
|
tar cvzf "$my_bin.tar.gz" "$my_bin"
|
||||||
|
Compress-Archive "$my_bin" "$my_bin.zip"
|
||||||
|
|
||||||
|
Write-Output "$my_bin.zip"
|
||||||
|
}
|
||||||
|
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
|
$Env:GOAMD64 = "v1"
|
||||||
|
$Env:GOARCH = "amd64"
|
||||||
|
fn_package
|
||||||
|
$Env:GOAMD64 = ""
|
||||||
|
|
||||||
|
# $Env:GOARCH = "386"
|
||||||
|
# fn_package
|
||||||
|
|
||||||
|
$Env:GOARCH = "arm64"
|
||||||
|
fn_package
|
||||||
|
|
||||||
|
# $Env:GOARCH = "arm"
|
||||||
|
# $Env:GOARM = "7"
|
||||||
|
# fn_package
|
||||||
|
|
||||||
|
# $Env:GOARCH = "arm"
|
||||||
|
# $Env:GOARM = "6"
|
||||||
|
# fn_package
|
||||||
|
|
||||||
|
# unset vars
|
||||||
|
$Env:GOOS = ""
|
||||||
|
$Env:GOARCH = ""
|
||||||
|
$Env:GOARM = ""
|
||||||
|
$Env:GOAMD64 = ""
|
|
@ -0,0 +1,54 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
|
||||||
|
# NOTE
|
||||||
|
# building for macOS on macOS seems to yield smaller sizes
|
||||||
|
|
||||||
|
# TODO use the git log describe thing
|
||||||
|
my_version="$(
|
||||||
|
git describe --tags
|
||||||
|
)"
|
||||||
|
export GOOS="windows"
|
||||||
|
|
||||||
|
fn_package() { (
|
||||||
|
if test -n "${GOARM:-}"; then
|
||||||
|
my_arch="${GOARCH}v${GOARM}"
|
||||||
|
elif test -n "${GOAMD64:-}"; then
|
||||||
|
my_arch="${GOARCH}_${GOAMD64}"
|
||||||
|
else
|
||||||
|
my_arch="${GOARCH}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
my_bin="pathman-${my_version}-${GOOS}-${my_arch}"
|
||||||
|
tinygo build -no-debug -o "${my_bin}"
|
||||||
|
#strip "${my_bin}" || true
|
||||||
|
|
||||||
|
tar cvf "$my_bin.tar" "$my_bin"
|
||||||
|
gzip --keep "$my_bin.tar"
|
||||||
|
#xz --keep "$my_bin.tar"
|
||||||
|
zip "$my_bin.zip" "$my_bin"
|
||||||
|
|
||||||
|
echo "$my_bin.zip"
|
||||||
|
); }
|
||||||
|
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
|
export GOAMD64=v1
|
||||||
|
export GOARCH=amd64
|
||||||
|
fn_package
|
||||||
|
export GOAMD64=''
|
||||||
|
|
||||||
|
# export GOARCH=386
|
||||||
|
# fn_package
|
||||||
|
|
||||||
|
export GOARCH=arm64
|
||||||
|
fn_package
|
||||||
|
|
||||||
|
# export GOARCH=arm
|
||||||
|
# export GOARM=7
|
||||||
|
# fn_package
|
||||||
|
|
||||||
|
# export GOARCH=arm
|
||||||
|
# export GOARM=6
|
||||||
|
# fn_package
|
|
@ -1,3 +0,0 @@
|
||||||
module git.rootprojects.org/root/go-gitver
|
|
||||||
|
|
||||||
go 1.12
|
|
|
@ -1,3 +0,0 @@
|
||||||
# This source code refers to The Go Authors for copyright purposes.
|
|
||||||
# The master list of authors is in the main Go distribution,
|
|
||||||
# visible at http://tip.golang.org/AUTHORS.
|
|
|
@ -1,3 +0,0 @@
|
||||||
# This source code was written by the Go contributors.
|
|
||||||
# The master list of contributors is in the main Go distribution,
|
|
||||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
|
|
@ -2,8 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build windows
|
//go:build windows && go1.9
|
||||||
// +build go1.9
|
|
||||||
|
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
// Copyright 2009 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.
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for 386, Windows are implemented in runtime/syscall_windows.goc
|
|
||||||
//
|
|
||||||
|
|
||||||
TEXT ·getprocaddress(SB), 7, $0-16
|
|
||||||
JMP syscall·getprocaddress(SB)
|
|
||||||
|
|
||||||
TEXT ·loadlibrary(SB), 7, $0-12
|
|
||||||
JMP syscall·loadlibrary(SB)
|
|
|
@ -1,13 +0,0 @@
|
||||||
// Copyright 2009 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.
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for amd64, Windows are implemented in runtime/syscall_windows.goc
|
|
||||||
//
|
|
||||||
|
|
||||||
TEXT ·getprocaddress(SB), 7, $0-32
|
|
||||||
JMP syscall·getprocaddress(SB)
|
|
||||||
|
|
||||||
TEXT ·loadlibrary(SB), 7, $0-24
|
|
||||||
JMP syscall·loadlibrary(SB)
|
|
|
@ -1,11 +0,0 @@
|
||||||
// Copyright 2018 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.
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
TEXT ·getprocaddress(SB),NOSPLIT,$0
|
|
||||||
B syscall·getprocaddress(SB)
|
|
||||||
|
|
||||||
TEXT ·loadlibrary(SB),NOSPLIT,$0
|
|
||||||
B syscall·loadlibrary(SB)
|
|
|
@ -11,6 +11,18 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// We need to use LoadLibrary and GetProcAddress from the Go runtime, because
|
||||||
|
// the these symbols are loaded by the system linker and are required to
|
||||||
|
// dynamically load additional symbols. Note that in the Go runtime, these
|
||||||
|
// return syscall.Handle and syscall.Errno, but these are the same, in fact,
|
||||||
|
// as windows.Handle and windows.Errno, and we intend to keep these the same.
|
||||||
|
|
||||||
|
//go:linkname syscall_loadlibrary syscall.loadlibrary
|
||||||
|
func syscall_loadlibrary(filename *uint16) (handle Handle, err Errno)
|
||||||
|
|
||||||
|
//go:linkname syscall_getprocaddress syscall.getprocaddress
|
||||||
|
func syscall_getprocaddress(handle Handle, procname *uint8) (proc uintptr, err Errno)
|
||||||
|
|
||||||
// DLLError describes reasons for DLL load failures.
|
// DLLError describes reasons for DLL load failures.
|
||||||
type DLLError struct {
|
type DLLError struct {
|
||||||
Err error
|
Err error
|
||||||
|
@ -20,9 +32,7 @@ type DLLError struct {
|
||||||
|
|
||||||
func (e *DLLError) Error() string { return e.Msg }
|
func (e *DLLError) Error() string { return e.Msg }
|
||||||
|
|
||||||
// Implemented in runtime/syscall_windows.goc; we provide jumps to them in our assembly file.
|
func (e *DLLError) Unwrap() error { return e.Err }
|
||||||
func loadlibrary(filename *uint16) (handle uintptr, err syscall.Errno)
|
|
||||||
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err syscall.Errno)
|
|
||||||
|
|
||||||
// A DLL implements access to a single DLL.
|
// A DLL implements access to a single DLL.
|
||||||
type DLL struct {
|
type DLL struct {
|
||||||
|
@ -40,7 +50,7 @@ func LoadDLL(name string) (dll *DLL, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
h, e := loadlibrary(namep)
|
h, e := syscall_loadlibrary(namep)
|
||||||
if e != 0 {
|
if e != 0 {
|
||||||
return nil, &DLLError{
|
return nil, &DLLError{
|
||||||
Err: e,
|
Err: e,
|
||||||
|
@ -50,7 +60,7 @@ func LoadDLL(name string) (dll *DLL, err error) {
|
||||||
}
|
}
|
||||||
d := &DLL{
|
d := &DLL{
|
||||||
Name: name,
|
Name: name,
|
||||||
Handle: Handle(h),
|
Handle: h,
|
||||||
}
|
}
|
||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
|
@ -71,7 +81,7 @@ func (d *DLL) FindProc(name string) (proc *Proc, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
a, e := getprocaddress(uintptr(d.Handle), namep)
|
a, e := syscall_getprocaddress(d.Handle, namep)
|
||||||
if e != 0 {
|
if e != 0 {
|
||||||
return nil, &DLLError{
|
return nil, &DLLError{
|
||||||
Err: e,
|
Err: e,
|
||||||
|
@ -96,6 +106,35 @@ func (d *DLL) MustFindProc(name string) *Proc {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindProcByOrdinal searches DLL d for procedure by ordinal and returns *Proc
|
||||||
|
// if found. It returns an error if search fails.
|
||||||
|
func (d *DLL) FindProcByOrdinal(ordinal uintptr) (proc *Proc, err error) {
|
||||||
|
a, e := GetProcAddressByOrdinal(d.Handle, ordinal)
|
||||||
|
name := "#" + itoa(int(ordinal))
|
||||||
|
if e != nil {
|
||||||
|
return nil, &DLLError{
|
||||||
|
Err: e,
|
||||||
|
ObjName: name,
|
||||||
|
Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p := &Proc{
|
||||||
|
Dll: d,
|
||||||
|
Name: name,
|
||||||
|
addr: a,
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustFindProcByOrdinal is like FindProcByOrdinal but panics if search fails.
|
||||||
|
func (d *DLL) MustFindProcByOrdinal(ordinal uintptr) *Proc {
|
||||||
|
p, e := d.FindProcByOrdinal(ordinal)
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
// Release unloads DLL d from memory.
|
// Release unloads DLL d from memory.
|
||||||
func (d *DLL) Release() (err error) {
|
func (d *DLL) Release() (err error) {
|
||||||
return FreeLibrary(d.Handle)
|
return FreeLibrary(d.Handle)
|
||||||
|
@ -352,7 +391,6 @@ func loadLibraryEx(name string, system bool) (*DLL, error) {
|
||||||
var flags uintptr
|
var flags uintptr
|
||||||
if system {
|
if system {
|
||||||
if canDoSearchSystem32() {
|
if canDoSearchSystem32() {
|
||||||
const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
|
|
||||||
flags = LOAD_LIBRARY_SEARCH_SYSTEM32
|
flags = LOAD_LIBRARY_SEARCH_SYSTEM32
|
||||||
} else if isBaseName(name) {
|
} else if isBaseName(name) {
|
||||||
// WindowsXP or unpatched Windows machine
|
// WindowsXP or unpatched Windows machine
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Copyright 2019 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.
|
||||||
|
|
||||||
|
//go:build !go1.12
|
||||||
|
|
||||||
|
// This file is here to allow bodyless functions with go:linkname for Go 1.11
|
||||||
|
// and earlier (see https://golang.org/issue/23311).
|
|
@ -8,7 +8,6 @@ package windows
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"unicode/utf16"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,20 +37,14 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer DestroyEnvironmentBlock(block)
|
defer DestroyEnvironmentBlock(block)
|
||||||
blockp := uintptr(unsafe.Pointer(block))
|
blockp := unsafe.Pointer(block)
|
||||||
for {
|
for {
|
||||||
entry := (*[(1 << 30) - 1]uint16)(unsafe.Pointer(blockp))[:]
|
entry := UTF16PtrToString((*uint16)(blockp))
|
||||||
for i, v := range entry {
|
|
||||||
if v == 0 {
|
|
||||||
entry = entry[:i]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(entry) == 0 {
|
if len(entry) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
env = append(env, string(utf16.Decode(entry)))
|
env = append(env, entry)
|
||||||
blockp += 2 * (uintptr(len(entry)) + 1)
|
blockp = unsafe.Add(blockp, 2*(len(entry)+1))
|
||||||
}
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build windows
|
//go:build windows
|
||||||
|
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
|
|
|
@ -6,18 +6,23 @@
|
||||||
|
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
errorspkg "errors"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
// EscapeArg rewrites command line argument s as prescribed
|
// EscapeArg rewrites command line argument s as prescribed
|
||||||
// in http://msdn.microsoft.com/en-us/library/ms880421.
|
// in http://msdn.microsoft.com/en-us/library/ms880421.
|
||||||
// This function returns "" (2 double quotes) if s is empty.
|
// This function returns "" (2 double quotes) if s is empty.
|
||||||
// Alternatively, these transformations are done:
|
// Alternatively, these transformations are done:
|
||||||
// - every back slash (\) is doubled, but only if immediately
|
// - every back slash (\) is doubled, but only if immediately
|
||||||
// followed by double quote (");
|
// followed by double quote (");
|
||||||
// - every double quote (") is escaped by back slash (\);
|
// - every double quote (") is escaped by back slash (\);
|
||||||
// - finally, s is wrapped with double quotes (arg -> "arg"),
|
// - finally, s is wrapped with double quotes (arg -> "arg"),
|
||||||
// but only if there is space or tab inside s.
|
// but only if there is space or tab inside s.
|
||||||
func EscapeArg(s string) string {
|
func EscapeArg(s string) string {
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
return "\"\""
|
return `""`
|
||||||
}
|
}
|
||||||
n := len(s)
|
n := len(s)
|
||||||
hasSpace := false
|
hasSpace := false
|
||||||
|
@ -30,7 +35,7 @@ func EscapeArg(s string) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if hasSpace {
|
if hasSpace {
|
||||||
n += 2
|
n += 2 // Reserve space for quotes.
|
||||||
}
|
}
|
||||||
if n == len(s) {
|
if n == len(s) {
|
||||||
return s
|
return s
|
||||||
|
@ -73,6 +78,110 @@ func EscapeArg(s string) string {
|
||||||
return string(qs[:j])
|
return string(qs[:j])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ComposeCommandLine escapes and joins the given arguments suitable for use as a Windows command line,
|
||||||
|
// in CreateProcess's CommandLine argument, CreateService/ChangeServiceConfig's BinaryPathName argument,
|
||||||
|
// or any program that uses CommandLineToArgv.
|
||||||
|
func ComposeCommandLine(args []string) string {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Per https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw:
|
||||||
|
// “This function accepts command lines that contain a program name; the
|
||||||
|
// program name can be enclosed in quotation marks or not.”
|
||||||
|
//
|
||||||
|
// Unfortunately, it provides no means of escaping interior quotation marks
|
||||||
|
// within that program name, and we have no way to report them here.
|
||||||
|
prog := args[0]
|
||||||
|
mustQuote := len(prog) == 0
|
||||||
|
for i := 0; i < len(prog); i++ {
|
||||||
|
c := prog[i]
|
||||||
|
if c <= ' ' || (c == '"' && i == 0) {
|
||||||
|
// Force quotes for not only the ASCII space and tab as described in the
|
||||||
|
// MSDN article, but also ASCII control characters.
|
||||||
|
// The documentation for CommandLineToArgvW doesn't say what happens when
|
||||||
|
// the first argument is not a valid program name, but it empirically
|
||||||
|
// seems to drop unquoted control characters.
|
||||||
|
mustQuote = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var commandLine []byte
|
||||||
|
if mustQuote {
|
||||||
|
commandLine = make([]byte, 0, len(prog)+2)
|
||||||
|
commandLine = append(commandLine, '"')
|
||||||
|
for i := 0; i < len(prog); i++ {
|
||||||
|
c := prog[i]
|
||||||
|
if c == '"' {
|
||||||
|
// This quote would interfere with our surrounding quotes.
|
||||||
|
// We have no way to report an error, so just strip out
|
||||||
|
// the offending character instead.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
commandLine = append(commandLine, c)
|
||||||
|
}
|
||||||
|
commandLine = append(commandLine, '"')
|
||||||
|
} else {
|
||||||
|
if len(args) == 1 {
|
||||||
|
// args[0] is a valid command line representing itself.
|
||||||
|
// No need to allocate a new slice or string for it.
|
||||||
|
return prog
|
||||||
|
}
|
||||||
|
commandLine = []byte(prog)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, arg := range args[1:] {
|
||||||
|
commandLine = append(commandLine, ' ')
|
||||||
|
// TODO(bcmills): since we're already appending to a slice, it would be nice
|
||||||
|
// to avoid the intermediate allocations of EscapeArg.
|
||||||
|
// Perhaps we can factor out an appendEscapedArg function.
|
||||||
|
commandLine = append(commandLine, EscapeArg(arg)...)
|
||||||
|
}
|
||||||
|
return string(commandLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecomposeCommandLine breaks apart its argument command line into unescaped parts using CommandLineToArgv,
|
||||||
|
// as gathered from GetCommandLine, QUERY_SERVICE_CONFIG's BinaryPathName argument, or elsewhere that
|
||||||
|
// command lines are passed around.
|
||||||
|
// DecomposeCommandLine returns an error if commandLine contains NUL.
|
||||||
|
func DecomposeCommandLine(commandLine string) ([]string, error) {
|
||||||
|
if len(commandLine) == 0 {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
utf16CommandLine, err := UTF16FromString(commandLine)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errorspkg.New("string with NUL passed to DecomposeCommandLine")
|
||||||
|
}
|
||||||
|
var argc int32
|
||||||
|
argv, err := commandLineToArgv(&utf16CommandLine[0], &argc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer LocalFree(Handle(unsafe.Pointer(argv)))
|
||||||
|
|
||||||
|
var args []string
|
||||||
|
for _, p := range unsafe.Slice(argv, argc) {
|
||||||
|
args = append(args, UTF16PtrToString(p))
|
||||||
|
}
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandLineToArgv parses a Unicode command line string and sets
|
||||||
|
// argc to the number of parsed arguments.
|
||||||
|
//
|
||||||
|
// The returned memory should be freed using a single call to LocalFree.
|
||||||
|
//
|
||||||
|
// Note that although the return type of CommandLineToArgv indicates 8192
|
||||||
|
// entries of up to 8192 characters each, the actual count of parsed arguments
|
||||||
|
// may exceed 8192, and the documentation for CommandLineToArgvW does not mention
|
||||||
|
// any bound on the lengths of the individual argument strings.
|
||||||
|
// (See https://go.dev/issue/63236.)
|
||||||
|
func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) {
|
||||||
|
argp, err := commandLineToArgv(cmd, argc)
|
||||||
|
argv = (*[8192]*[8192]uint16)(unsafe.Pointer(argp))
|
||||||
|
return argv, err
|
||||||
|
}
|
||||||
|
|
||||||
func CloseOnExec(fd Handle) {
|
func CloseOnExec(fd Handle) {
|
||||||
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
|
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
|
||||||
}
|
}
|
||||||
|
@ -95,3 +204,45 @@ func FullPath(name string) (path string, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewProcThreadAttributeList allocates a new ProcThreadAttributeListContainer, with the requested maximum number of attributes.
|
||||||
|
func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeListContainer, error) {
|
||||||
|
var size uintptr
|
||||||
|
err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size)
|
||||||
|
if err != ERROR_INSUFFICIENT_BUFFER {
|
||||||
|
if err == nil {
|
||||||
|
return nil, errorspkg.New("unable to query buffer size from InitializeProcThreadAttributeList")
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
alloc, err := LocalAlloc(LMEM_FIXED, uint32(size))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// size is guaranteed to be ≥1 by InitializeProcThreadAttributeList.
|
||||||
|
al := &ProcThreadAttributeListContainer{data: (*ProcThreadAttributeList)(unsafe.Pointer(alloc))}
|
||||||
|
err = initializeProcThreadAttributeList(al.data, maxAttrCount, 0, &size)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return al, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update modifies the ProcThreadAttributeList using UpdateProcThreadAttribute.
|
||||||
|
func (al *ProcThreadAttributeListContainer) Update(attribute uintptr, value unsafe.Pointer, size uintptr) error {
|
||||||
|
al.pointers = append(al.pointers, value)
|
||||||
|
return updateProcThreadAttribute(al.data, 0, attribute, value, size, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete frees ProcThreadAttributeList's resources.
|
||||||
|
func (al *ProcThreadAttributeListContainer) Delete() {
|
||||||
|
deleteProcThreadAttributeList(al.data)
|
||||||
|
LocalFree(Handle(unsafe.Pointer(al.data)))
|
||||||
|
al.data = nil
|
||||||
|
al.pointers = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns the actual ProcThreadAttributeList to be passed to StartupInfoEx.
|
||||||
|
func (al *ProcThreadAttributeListContainer) List() *ProcThreadAttributeList {
|
||||||
|
return al.data
|
||||||
|
}
|
||||||
|
|
|
@ -16,11 +16,33 @@ const (
|
||||||
MEM_RESET_UNDO = 0x01000000
|
MEM_RESET_UNDO = 0x01000000
|
||||||
MEM_LARGE_PAGES = 0x20000000
|
MEM_LARGE_PAGES = 0x20000000
|
||||||
|
|
||||||
PAGE_NOACCESS = 0x01
|
PAGE_NOACCESS = 0x00000001
|
||||||
PAGE_READONLY = 0x02
|
PAGE_READONLY = 0x00000002
|
||||||
PAGE_READWRITE = 0x04
|
PAGE_READWRITE = 0x00000004
|
||||||
PAGE_WRITECOPY = 0x08
|
PAGE_WRITECOPY = 0x00000008
|
||||||
PAGE_EXECUTE_READ = 0x20
|
PAGE_EXECUTE = 0x00000010
|
||||||
PAGE_EXECUTE_READWRITE = 0x40
|
PAGE_EXECUTE_READ = 0x00000020
|
||||||
PAGE_EXECUTE_WRITECOPY = 0x80
|
PAGE_EXECUTE_READWRITE = 0x00000040
|
||||||
|
PAGE_EXECUTE_WRITECOPY = 0x00000080
|
||||||
|
PAGE_GUARD = 0x00000100
|
||||||
|
PAGE_NOCACHE = 0x00000200
|
||||||
|
PAGE_WRITECOMBINE = 0x00000400
|
||||||
|
PAGE_TARGETS_INVALID = 0x40000000
|
||||||
|
PAGE_TARGETS_NO_UPDATE = 0x40000000
|
||||||
|
|
||||||
|
QUOTA_LIMITS_HARDWS_MIN_DISABLE = 0x00000002
|
||||||
|
QUOTA_LIMITS_HARDWS_MIN_ENABLE = 0x00000001
|
||||||
|
QUOTA_LIMITS_HARDWS_MAX_DISABLE = 0x00000008
|
||||||
|
QUOTA_LIMITS_HARDWS_MAX_ENABLE = 0x00000004
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type MemoryBasicInformation struct {
|
||||||
|
BaseAddress uintptr
|
||||||
|
AllocationBase uintptr
|
||||||
|
AllocationProtect uint32
|
||||||
|
PartitionId uint16
|
||||||
|
RegionSize uintptr
|
||||||
|
State uint32
|
||||||
|
Protect uint32
|
||||||
|
Type uint32
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ shopt -s nullglob
|
||||||
|
|
||||||
winerror="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/shared/winerror.h | sort -Vr | head -n 1)"
|
winerror="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/shared/winerror.h | sort -Vr | head -n 1)"
|
||||||
[[ -n $winerror ]] || { echo "Unable to find winerror.h" >&2; exit 1; }
|
[[ -n $winerror ]] || { echo "Unable to find winerror.h" >&2; exit 1; }
|
||||||
|
ntstatus="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/shared/ntstatus.h | sort -Vr | head -n 1)"
|
||||||
|
[[ -n $ntstatus ]] || { echo "Unable to find ntstatus.h" >&2; exit 1; }
|
||||||
|
|
||||||
declare -A errors
|
declare -A errors
|
||||||
|
|
||||||
|
@ -59,5 +61,10 @@ declare -A errors
|
||||||
echo "$key $vtype = $value"
|
echo "$key $vtype = $value"
|
||||||
done < "$winerror"
|
done < "$winerror"
|
||||||
|
|
||||||
|
while read -r line; do
|
||||||
|
[[ $line =~ ^#define\ (STATUS_[^\s]+)\ +\(\(NTSTATUS\)((0x)?[0-9a-fA-F]+)L?\) ]] || continue
|
||||||
|
echo "${BASH_REMATCH[1]} NTStatus = ${BASH_REMATCH[2]}"
|
||||||
|
done < "$ntstatus"
|
||||||
|
|
||||||
echo ")"
|
echo ")"
|
||||||
} | gofmt > "zerrors_windows.go"
|
} | gofmt > "zerrors_windows.go"
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build generate
|
//go:build generate
|
||||||
|
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go
|
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go setupapi_windows.go
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build windows,race
|
//go:build windows && race
|
||||||
|
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build windows,!race
|
//go:build windows && !race
|
||||||
|
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build windows
|
//go:build windows
|
||||||
|
|
||||||
// Package registry provides access to the Windows registry.
|
// Package registry provides access to the Windows registry.
|
||||||
//
|
//
|
||||||
|
@ -19,11 +19,11 @@
|
||||||
// log.Fatal(err)
|
// log.Fatal(err)
|
||||||
// }
|
// }
|
||||||
// fmt.Printf("Windows system root is %q\n", s)
|
// fmt.Printf("Windows system root is %q\n", s)
|
||||||
//
|
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -113,6 +113,13 @@ func OpenRemoteKey(pcname string, k Key) (Key, error) {
|
||||||
// The parameter n controls the number of returned names,
|
// The parameter n controls the number of returned names,
|
||||||
// analogous to the way os.File.Readdirnames works.
|
// analogous to the way os.File.Readdirnames works.
|
||||||
func (k Key) ReadSubKeyNames(n int) ([]string, error) {
|
func (k Key) ReadSubKeyNames(n int) ([]string, error) {
|
||||||
|
// RegEnumKeyEx must be called repeatedly and to completion.
|
||||||
|
// During this time, this goroutine cannot migrate away from
|
||||||
|
// its current thread. See https://golang.org/issue/49320 and
|
||||||
|
// https://golang.org/issue/49466.
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
names := make([]string, 0)
|
names := make([]string, 0)
|
||||||
// Registry key size limit is 255 bytes and described there:
|
// Registry key size limit is 255 bytes and described there:
|
||||||
// https://msdn.microsoft.com/library/windows/desktop/ms724872.aspx
|
// https://msdn.microsoft.com/library/windows/desktop/ms724872.aspx
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build generate
|
//go:build generate
|
||||||
|
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
|
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall.go
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build windows
|
//go:build windows
|
||||||
|
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build windows
|
//go:build windows
|
||||||
|
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ func (k Key) GetStringValue(name string) (val string, valtype uint32, err error)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return "", typ, nil
|
return "", typ, nil
|
||||||
}
|
}
|
||||||
u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:]
|
u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[: len(data)/2 : len(data)/2]
|
||||||
return syscall.UTF16ToString(u), typ, nil
|
return syscall.UTF16ToString(u), typ, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,8 +185,7 @@ func ExpandString(value string) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if n <= uint32(len(r)) {
|
if n <= uint32(len(r)) {
|
||||||
u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:]
|
return syscall.UTF16ToString(r[:n]), nil
|
||||||
return syscall.UTF16ToString(u), nil
|
|
||||||
}
|
}
|
||||||
r = make([]uint16, n)
|
r = make([]uint16, n)
|
||||||
}
|
}
|
||||||
|
@ -208,7 +207,7 @@ func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err err
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil, typ, nil
|
return nil, typ, nil
|
||||||
}
|
}
|
||||||
p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
|
p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[: len(data)/2 : len(data)/2]
|
||||||
if len(p) == 0 {
|
if len(p) == 0 {
|
||||||
return nil, typ, nil
|
return nil, typ, nil
|
||||||
}
|
}
|
||||||
|
@ -299,7 +298,7 @@ func (k Key) setStringValue(name string, valtype uint32, value string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
|
buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[: len(v)*2 : len(v)*2]
|
||||||
return k.setValue(name, valtype, buf)
|
return k.setValue(name, valtype, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +328,7 @@ func (k Key) SetStringsValue(name string, value []string) error {
|
||||||
ss += s + "\x00"
|
ss += s + "\x00"
|
||||||
}
|
}
|
||||||
v := utf16.Encode([]rune(ss + "\x00"))
|
v := utf16.Encode([]rune(ss + "\x00"))
|
||||||
buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
|
buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[: len(v)*2 : len(v)*2]
|
||||||
return k.setValue(name, MULTI_SZ, buf)
|
return k.setValue(name, MULTI_SZ, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ const (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
errERROR_EINVAL error = syscall.EINVAL
|
||||||
)
|
)
|
||||||
|
|
||||||
// errnoErr returns common boxed Errno values, to prevent
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
@ -26,7 +27,7 @@ var (
|
||||||
func errnoErr(e syscall.Errno) error {
|
func errnoErr(e syscall.Errno) error {
|
||||||
switch e {
|
switch e {
|
||||||
case 0:
|
case 0:
|
||||||
return nil
|
return errERROR_EINVAL
|
||||||
case errnoERROR_IO_PENDING:
|
case errnoERROR_IO_PENDING:
|
||||||
return errERROR_IO_PENDING
|
return errERROR_IO_PENDING
|
||||||
}
|
}
|
||||||
|
@ -40,16 +41,24 @@ var (
|
||||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
|
|
||||||
|
procRegConnectRegistryW = modadvapi32.NewProc("RegConnectRegistryW")
|
||||||
procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW")
|
procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW")
|
||||||
procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW")
|
procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW")
|
||||||
procRegSetValueExW = modadvapi32.NewProc("RegSetValueExW")
|
|
||||||
procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW")
|
|
||||||
procRegDeleteValueW = modadvapi32.NewProc("RegDeleteValueW")
|
procRegDeleteValueW = modadvapi32.NewProc("RegDeleteValueW")
|
||||||
|
procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW")
|
||||||
procRegLoadMUIStringW = modadvapi32.NewProc("RegLoadMUIStringW")
|
procRegLoadMUIStringW = modadvapi32.NewProc("RegLoadMUIStringW")
|
||||||
procRegConnectRegistryW = modadvapi32.NewProc("RegConnectRegistryW")
|
procRegSetValueExW = modadvapi32.NewProc("RegSetValueExW")
|
||||||
procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
|
procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func regConnectRegistry(machinename *uint16, key syscall.Handle, result *syscall.Handle) (regerrno error) {
|
||||||
|
r0, _, _ := syscall.Syscall(procRegConnectRegistryW.Addr(), 3, uintptr(unsafe.Pointer(machinename)), uintptr(key), uintptr(unsafe.Pointer(result)))
|
||||||
|
if r0 != 0 {
|
||||||
|
regerrno = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) {
|
func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) {
|
||||||
r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition)))
|
r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition)))
|
||||||
if r0 != 0 {
|
if r0 != 0 {
|
||||||
|
@ -66,8 +75,8 @@ func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) {
|
func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) {
|
||||||
r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize))
|
r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0)
|
||||||
if r0 != 0 {
|
if r0 != 0 {
|
||||||
regerrno = syscall.Errno(r0)
|
regerrno = syscall.Errno(r0)
|
||||||
}
|
}
|
||||||
|
@ -82,14 +91,6 @@ func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint3
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) {
|
|
||||||
r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0)
|
|
||||||
if r0 != 0 {
|
|
||||||
regerrno = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) {
|
func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) {
|
||||||
r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0)
|
r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0)
|
||||||
if r0 != 0 {
|
if r0 != 0 {
|
||||||
|
@ -98,8 +99,8 @@ func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func regConnectRegistry(machinename *uint16, key syscall.Handle, result *syscall.Handle) (regerrno error) {
|
func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) {
|
||||||
r0, _, _ := syscall.Syscall(procRegConnectRegistryW.Addr(), 3, uintptr(unsafe.Pointer(machinename)), uintptr(key), uintptr(unsafe.Pointer(result)))
|
r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize))
|
||||||
if r0 != 0 {
|
if r0 != 0 {
|
||||||
regerrno = syscall.Errno(r0)
|
regerrno = syscall.Errno(r0)
|
||||||
}
|
}
|
||||||
|
@ -110,11 +111,7 @@ func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32,
|
||||||
r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size))
|
r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size))
|
||||||
n = uint32(r0)
|
n = uint32(r0)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
if e1 != 0 {
|
err = errnoErr(e1)
|
||||||
err = errnoErr(e1)
|
|
||||||
} else {
|
|
||||||
err = syscall.EINVAL
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,6 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
STANDARD_RIGHTS_REQUIRED = 0xf0000
|
|
||||||
STANDARD_RIGHTS_READ = 0x20000
|
|
||||||
STANDARD_RIGHTS_WRITE = 0x20000
|
|
||||||
STANDARD_RIGHTS_EXECUTE = 0x20000
|
|
||||||
STANDARD_RIGHTS_ALL = 0x1F0000
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NameUnknown = 0
|
NameUnknown = 0
|
||||||
NameFullyQualifiedDN = 1
|
NameFullyQualifiedDN = 1
|
||||||
|
@ -235,16 +227,15 @@ func LookupSID(system, account string) (sid *SID, domain string, accType uint32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// String converts SID to a string format
|
// String converts SID to a string format suitable for display, storage, or transmission.
|
||||||
// suitable for display, storage, or transmission.
|
func (sid *SID) String() string {
|
||||||
func (sid *SID) String() (string, error) {
|
|
||||||
var s *uint16
|
var s *uint16
|
||||||
e := ConvertSidToStringSid(sid, &s)
|
e := ConvertSidToStringSid(sid, &s)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return "", e
|
return ""
|
||||||
}
|
}
|
||||||
defer LocalFree((Handle)(unsafe.Pointer(s)))
|
defer LocalFree((Handle)(unsafe.Pointer(s)))
|
||||||
return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
|
return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Len returns the length, in bytes, of a valid security identifier SID.
|
// Len returns the length, in bytes, of a valid security identifier SID.
|
||||||
|
@ -631,6 +622,7 @@ func (tml *Tokenmandatorylabel) Size() uint32 {
|
||||||
|
|
||||||
// Authorization Functions
|
// Authorization Functions
|
||||||
//sys checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) (err error) = advapi32.CheckTokenMembership
|
//sys checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) (err error) = advapi32.CheckTokenMembership
|
||||||
|
//sys isTokenRestricted(tokenHandle Token) (ret bool, err error) [!failretval] = advapi32.IsTokenRestricted
|
||||||
//sys OpenProcessToken(process Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
|
//sys OpenProcessToken(process Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
|
||||||
//sys OpenThreadToken(thread Handle, access uint32, openAsSelf bool, token *Token) (err error) = advapi32.OpenThreadToken
|
//sys OpenThreadToken(thread Handle, access uint32, openAsSelf bool, token *Token) (err error) = advapi32.OpenThreadToken
|
||||||
//sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf
|
//sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf
|
||||||
|
@ -644,6 +636,8 @@ func (tml *Tokenmandatorylabel) Size() uint32 {
|
||||||
//sys DuplicateTokenEx(existingToken Token, desiredAccess uint32, tokenAttributes *SecurityAttributes, impersonationLevel uint32, tokenType uint32, newToken *Token) (err error) = advapi32.DuplicateTokenEx
|
//sys DuplicateTokenEx(existingToken Token, desiredAccess uint32, tokenAttributes *SecurityAttributes, impersonationLevel uint32, tokenType uint32, newToken *Token) (err error) = advapi32.DuplicateTokenEx
|
||||||
//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
|
//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
|
||||||
//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW
|
//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW
|
||||||
|
//sys getWindowsDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetWindowsDirectoryW
|
||||||
|
//sys getSystemWindowsDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemWindowsDirectoryW
|
||||||
|
|
||||||
// An access token contains the security information for a logon session.
|
// An access token contains the security information for a logon session.
|
||||||
// The system creates an access token when a user logs on, and every
|
// The system creates an access token when a user logs on, and every
|
||||||
|
@ -654,21 +648,16 @@ func (tml *Tokenmandatorylabel) Size() uint32 {
|
||||||
// system-related operations on the local computer.
|
// system-related operations on the local computer.
|
||||||
type Token Handle
|
type Token Handle
|
||||||
|
|
||||||
// OpenCurrentProcessToken opens the access token
|
// OpenCurrentProcessToken opens an access token associated with current
|
||||||
// associated with current process. It is a real
|
// process with TOKEN_QUERY access. It is a real token that needs to be closed.
|
||||||
// token that needs to be closed, unlike
|
//
|
||||||
// GetCurrentProcessToken.
|
// Deprecated: Explicitly call OpenProcessToken(CurrentProcess(), ...)
|
||||||
|
// with the desired access instead, or use GetCurrentProcessToken for a
|
||||||
|
// TOKEN_QUERY token.
|
||||||
func OpenCurrentProcessToken() (Token, error) {
|
func OpenCurrentProcessToken() (Token, error) {
|
||||||
p, e := GetCurrentProcess()
|
var token Token
|
||||||
if e != nil {
|
err := OpenProcessToken(CurrentProcess(), TOKEN_QUERY, &token)
|
||||||
return 0, e
|
return token, err
|
||||||
}
|
|
||||||
var t Token
|
|
||||||
e = OpenProcessToken(p, TOKEN_QUERY, &t)
|
|
||||||
if e != nil {
|
|
||||||
return 0, e
|
|
||||||
}
|
|
||||||
return t, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentProcessToken returns the access token associated with
|
// GetCurrentProcessToken returns the access token associated with
|
||||||
|
@ -785,8 +774,8 @@ func (token Token) GetLinkedToken() (Token, error) {
|
||||||
return linkedToken, nil
|
return linkedToken, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSystemDirectory retrieves path to current location of the system
|
// GetSystemDirectory retrieves the path to current location of the system
|
||||||
// directory, which is typically, though not always, C:\Windows\System32.
|
// directory, which is typically, though not always, `C:\Windows\System32`.
|
||||||
func GetSystemDirectory() (string, error) {
|
func GetSystemDirectory() (string, error) {
|
||||||
n := uint32(MAX_PATH)
|
n := uint32(MAX_PATH)
|
||||||
for {
|
for {
|
||||||
|
@ -802,6 +791,42 @@ func GetSystemDirectory() (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetWindowsDirectory retrieves the path to current location of the Windows
|
||||||
|
// directory, which is typically, though not always, `C:\Windows`. This may
|
||||||
|
// be a private user directory in the case that the application is running
|
||||||
|
// under a terminal server.
|
||||||
|
func GetWindowsDirectory() (string, error) {
|
||||||
|
n := uint32(MAX_PATH)
|
||||||
|
for {
|
||||||
|
b := make([]uint16, n)
|
||||||
|
l, e := getWindowsDirectory(&b[0], n)
|
||||||
|
if e != nil {
|
||||||
|
return "", e
|
||||||
|
}
|
||||||
|
if l <= n {
|
||||||
|
return UTF16ToString(b[:l]), nil
|
||||||
|
}
|
||||||
|
n = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSystemWindowsDirectory retrieves the path to current location of the
|
||||||
|
// Windows directory, which is typically, though not always, `C:\Windows`.
|
||||||
|
func GetSystemWindowsDirectory() (string, error) {
|
||||||
|
n := uint32(MAX_PATH)
|
||||||
|
for {
|
||||||
|
b := make([]uint16, n)
|
||||||
|
l, e := getSystemWindowsDirectory(&b[0], n)
|
||||||
|
if e != nil {
|
||||||
|
return "", e
|
||||||
|
}
|
||||||
|
if l <= n {
|
||||||
|
return UTF16ToString(b[:l]), nil
|
||||||
|
}
|
||||||
|
n = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IsMember reports whether the access token t is a member of the provided SID.
|
// IsMember reports whether the access token t is a member of the provided SID.
|
||||||
func (t Token) IsMember(sid *SID) (bool, error) {
|
func (t Token) IsMember(sid *SID) (bool, error) {
|
||||||
var b int32
|
var b int32
|
||||||
|
@ -811,6 +836,16 @@ func (t Token) IsMember(sid *SID) (bool, error) {
|
||||||
return b != 0, nil
|
return b != 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsRestricted reports whether the access token t is a restricted token.
|
||||||
|
func (t Token) IsRestricted() (isRestricted bool, err error) {
|
||||||
|
isRestricted, err = isTokenRestricted(t)
|
||||||
|
if !isRestricted && err == syscall.EINVAL {
|
||||||
|
// If err is EINVAL, this returned ERROR_SUCCESS indicating a non-restricted token.
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
WTS_CONSOLE_CONNECT = 0x1
|
WTS_CONSOLE_CONNECT = 0x1
|
||||||
WTS_CONSOLE_DISCONNECT = 0x2
|
WTS_CONSOLE_DISCONNECT = 0x2
|
||||||
|
@ -852,3 +887,549 @@ type WTS_SESSION_INFO struct {
|
||||||
//sys WTSQueryUserToken(session uint32, token *Token) (err error) = wtsapi32.WTSQueryUserToken
|
//sys WTSQueryUserToken(session uint32, token *Token) (err error) = wtsapi32.WTSQueryUserToken
|
||||||
//sys WTSEnumerateSessions(handle Handle, reserved uint32, version uint32, sessions **WTS_SESSION_INFO, count *uint32) (err error) = wtsapi32.WTSEnumerateSessionsW
|
//sys WTSEnumerateSessions(handle Handle, reserved uint32, version uint32, sessions **WTS_SESSION_INFO, count *uint32) (err error) = wtsapi32.WTSEnumerateSessionsW
|
||||||
//sys WTSFreeMemory(ptr uintptr) = wtsapi32.WTSFreeMemory
|
//sys WTSFreeMemory(ptr uintptr) = wtsapi32.WTSFreeMemory
|
||||||
|
//sys WTSGetActiveConsoleSessionId() (sessionID uint32)
|
||||||
|
|
||||||
|
type ACL struct {
|
||||||
|
aclRevision byte
|
||||||
|
sbz1 byte
|
||||||
|
aclSize uint16
|
||||||
|
aceCount uint16
|
||||||
|
sbz2 uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type SECURITY_DESCRIPTOR struct {
|
||||||
|
revision byte
|
||||||
|
sbz1 byte
|
||||||
|
control SECURITY_DESCRIPTOR_CONTROL
|
||||||
|
owner *SID
|
||||||
|
group *SID
|
||||||
|
sacl *ACL
|
||||||
|
dacl *ACL
|
||||||
|
}
|
||||||
|
|
||||||
|
type SECURITY_QUALITY_OF_SERVICE struct {
|
||||||
|
Length uint32
|
||||||
|
ImpersonationLevel uint32
|
||||||
|
ContextTrackingMode byte
|
||||||
|
EffectiveOnly byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants for the ContextTrackingMode field of SECURITY_QUALITY_OF_SERVICE.
|
||||||
|
const (
|
||||||
|
SECURITY_STATIC_TRACKING = 0
|
||||||
|
SECURITY_DYNAMIC_TRACKING = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type SecurityAttributes struct {
|
||||||
|
Length uint32
|
||||||
|
SecurityDescriptor *SECURITY_DESCRIPTOR
|
||||||
|
InheritHandle uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type SE_OBJECT_TYPE uint32
|
||||||
|
|
||||||
|
// Constants for type SE_OBJECT_TYPE
|
||||||
|
const (
|
||||||
|
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_32KEY = 12
|
||||||
|
SE_REGISTRY_WOW64_64KEY = 13
|
||||||
|
)
|
||||||
|
|
||||||
|
type SECURITY_INFORMATION uint32
|
||||||
|
|
||||||
|
// Constants for type SECURITY_INFORMATION
|
||||||
|
const (
|
||||||
|
OWNER_SECURITY_INFORMATION = 0x00000001
|
||||||
|
GROUP_SECURITY_INFORMATION = 0x00000002
|
||||||
|
DACL_SECURITY_INFORMATION = 0x00000004
|
||||||
|
SACL_SECURITY_INFORMATION = 0x00000008
|
||||||
|
LABEL_SECURITY_INFORMATION = 0x00000010
|
||||||
|
ATTRIBUTE_SECURITY_INFORMATION = 0x00000020
|
||||||
|
SCOPE_SECURITY_INFORMATION = 0x00000040
|
||||||
|
BACKUP_SECURITY_INFORMATION = 0x00010000
|
||||||
|
PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
|
||||||
|
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
|
||||||
|
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
|
||||||
|
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
|
||||||
|
)
|
||||||
|
|
||||||
|
type SECURITY_DESCRIPTOR_CONTROL uint16
|
||||||
|
|
||||||
|
// Constants for type SECURITY_DESCRIPTOR_CONTROL
|
||||||
|
const (
|
||||||
|
SE_OWNER_DEFAULTED = 0x0001
|
||||||
|
SE_GROUP_DEFAULTED = 0x0002
|
||||||
|
SE_DACL_PRESENT = 0x0004
|
||||||
|
SE_DACL_DEFAULTED = 0x0008
|
||||||
|
SE_SACL_PRESENT = 0x0010
|
||||||
|
SE_SACL_DEFAULTED = 0x0020
|
||||||
|
SE_DACL_AUTO_INHERIT_REQ = 0x0100
|
||||||
|
SE_SACL_AUTO_INHERIT_REQ = 0x0200
|
||||||
|
SE_DACL_AUTO_INHERITED = 0x0400
|
||||||
|
SE_SACL_AUTO_INHERITED = 0x0800
|
||||||
|
SE_DACL_PROTECTED = 0x1000
|
||||||
|
SE_SACL_PROTECTED = 0x2000
|
||||||
|
SE_RM_CONTROL_VALID = 0x4000
|
||||||
|
SE_SELF_RELATIVE = 0x8000
|
||||||
|
)
|
||||||
|
|
||||||
|
type ACCESS_MASK uint32
|
||||||
|
|
||||||
|
// Constants for type ACCESS_MASK
|
||||||
|
const (
|
||||||
|
DELETE = 0x00010000
|
||||||
|
READ_CONTROL = 0x00020000
|
||||||
|
WRITE_DAC = 0x00040000
|
||||||
|
WRITE_OWNER = 0x00080000
|
||||||
|
SYNCHRONIZE = 0x00100000
|
||||||
|
STANDARD_RIGHTS_REQUIRED = 0x000F0000
|
||||||
|
STANDARD_RIGHTS_READ = READ_CONTROL
|
||||||
|
STANDARD_RIGHTS_WRITE = READ_CONTROL
|
||||||
|
STANDARD_RIGHTS_EXECUTE = READ_CONTROL
|
||||||
|
STANDARD_RIGHTS_ALL = 0x001F0000
|
||||||
|
SPECIFIC_RIGHTS_ALL = 0x0000FFFF
|
||||||
|
ACCESS_SYSTEM_SECURITY = 0x01000000
|
||||||
|
MAXIMUM_ALLOWED = 0x02000000
|
||||||
|
GENERIC_READ = 0x80000000
|
||||||
|
GENERIC_WRITE = 0x40000000
|
||||||
|
GENERIC_EXECUTE = 0x20000000
|
||||||
|
GENERIC_ALL = 0x10000000
|
||||||
|
)
|
||||||
|
|
||||||
|
type ACCESS_MODE uint32
|
||||||
|
|
||||||
|
// Constants for type ACCESS_MODE
|
||||||
|
const (
|
||||||
|
NOT_USED_ACCESS = 0
|
||||||
|
GRANT_ACCESS = 1
|
||||||
|
SET_ACCESS = 2
|
||||||
|
DENY_ACCESS = 3
|
||||||
|
REVOKE_ACCESS = 4
|
||||||
|
SET_AUDIT_SUCCESS = 5
|
||||||
|
SET_AUDIT_FAILURE = 6
|
||||||
|
)
|
||||||
|
|
||||||
|
// Constants for AceFlags and Inheritance fields
|
||||||
|
const (
|
||||||
|
NO_INHERITANCE = 0x0
|
||||||
|
SUB_OBJECTS_ONLY_INHERIT = 0x1
|
||||||
|
SUB_CONTAINERS_ONLY_INHERIT = 0x2
|
||||||
|
SUB_CONTAINERS_AND_OBJECTS_INHERIT = 0x3
|
||||||
|
INHERIT_NO_PROPAGATE = 0x4
|
||||||
|
INHERIT_ONLY = 0x8
|
||||||
|
INHERITED_ACCESS_ENTRY = 0x10
|
||||||
|
INHERITED_PARENT = 0x10000000
|
||||||
|
INHERITED_GRANDPARENT = 0x20000000
|
||||||
|
OBJECT_INHERIT_ACE = 0x1
|
||||||
|
CONTAINER_INHERIT_ACE = 0x2
|
||||||
|
NO_PROPAGATE_INHERIT_ACE = 0x4
|
||||||
|
INHERIT_ONLY_ACE = 0x8
|
||||||
|
INHERITED_ACE = 0x10
|
||||||
|
VALID_INHERIT_FLAGS = 0x1F
|
||||||
|
)
|
||||||
|
|
||||||
|
type MULTIPLE_TRUSTEE_OPERATION uint32
|
||||||
|
|
||||||
|
// Constants for MULTIPLE_TRUSTEE_OPERATION
|
||||||
|
const (
|
||||||
|
NO_MULTIPLE_TRUSTEE = 0
|
||||||
|
TRUSTEE_IS_IMPERSONATE = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type TRUSTEE_FORM uint32
|
||||||
|
|
||||||
|
// Constants for TRUSTEE_FORM
|
||||||
|
const (
|
||||||
|
TRUSTEE_IS_SID = 0
|
||||||
|
TRUSTEE_IS_NAME = 1
|
||||||
|
TRUSTEE_BAD_FORM = 2
|
||||||
|
TRUSTEE_IS_OBJECTS_AND_SID = 3
|
||||||
|
TRUSTEE_IS_OBJECTS_AND_NAME = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
type TRUSTEE_TYPE uint32
|
||||||
|
|
||||||
|
// Constants for TRUSTEE_TYPE
|
||||||
|
const (
|
||||||
|
TRUSTEE_IS_UNKNOWN = 0
|
||||||
|
TRUSTEE_IS_USER = 1
|
||||||
|
TRUSTEE_IS_GROUP = 2
|
||||||
|
TRUSTEE_IS_DOMAIN = 3
|
||||||
|
TRUSTEE_IS_ALIAS = 4
|
||||||
|
TRUSTEE_IS_WELL_KNOWN_GROUP = 5
|
||||||
|
TRUSTEE_IS_DELETED = 6
|
||||||
|
TRUSTEE_IS_INVALID = 7
|
||||||
|
TRUSTEE_IS_COMPUTER = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
// Constants for ObjectsPresent field
|
||||||
|
const (
|
||||||
|
ACE_OBJECT_TYPE_PRESENT = 0x1
|
||||||
|
ACE_INHERITED_OBJECT_TYPE_PRESENT = 0x2
|
||||||
|
)
|
||||||
|
|
||||||
|
type EXPLICIT_ACCESS struct {
|
||||||
|
AccessPermissions ACCESS_MASK
|
||||||
|
AccessMode ACCESS_MODE
|
||||||
|
Inheritance uint32
|
||||||
|
Trustee TRUSTEE
|
||||||
|
}
|
||||||
|
|
||||||
|
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
|
||||||
|
type TrusteeValue uintptr
|
||||||
|
|
||||||
|
func TrusteeValueFromString(str string) TrusteeValue {
|
||||||
|
return TrusteeValue(unsafe.Pointer(StringToUTF16Ptr(str)))
|
||||||
|
}
|
||||||
|
func TrusteeValueFromSID(sid *SID) TrusteeValue {
|
||||||
|
return TrusteeValue(unsafe.Pointer(sid))
|
||||||
|
}
|
||||||
|
func TrusteeValueFromObjectsAndSid(objectsAndSid *OBJECTS_AND_SID) TrusteeValue {
|
||||||
|
return TrusteeValue(unsafe.Pointer(objectsAndSid))
|
||||||
|
}
|
||||||
|
func TrusteeValueFromObjectsAndName(objectsAndName *OBJECTS_AND_NAME) TrusteeValue {
|
||||||
|
return TrusteeValue(unsafe.Pointer(objectsAndName))
|
||||||
|
}
|
||||||
|
|
||||||
|
type TRUSTEE struct {
|
||||||
|
MultipleTrustee *TRUSTEE
|
||||||
|
MultipleTrusteeOperation MULTIPLE_TRUSTEE_OPERATION
|
||||||
|
TrusteeForm TRUSTEE_FORM
|
||||||
|
TrusteeType TRUSTEE_TYPE
|
||||||
|
TrusteeValue TrusteeValue
|
||||||
|
}
|
||||||
|
|
||||||
|
type OBJECTS_AND_SID struct {
|
||||||
|
ObjectsPresent uint32
|
||||||
|
ObjectTypeGuid GUID
|
||||||
|
InheritedObjectTypeGuid GUID
|
||||||
|
Sid *SID
|
||||||
|
}
|
||||||
|
|
||||||
|
type OBJECTS_AND_NAME struct {
|
||||||
|
ObjectsPresent uint32
|
||||||
|
ObjectType SE_OBJECT_TYPE
|
||||||
|
ObjectTypeName *uint16
|
||||||
|
InheritedObjectTypeName *uint16
|
||||||
|
Name *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys getSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner **SID, group **SID, dacl **ACL, sacl **ACL, sd **SECURITY_DESCRIPTOR) (ret error) = advapi32.GetSecurityInfo
|
||||||
|
//sys SetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) (ret error) = advapi32.SetSecurityInfo
|
||||||
|
//sys getNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner **SID, group **SID, dacl **ACL, sacl **ACL, sd **SECURITY_DESCRIPTOR) (ret error) = advapi32.GetNamedSecurityInfoW
|
||||||
|
//sys SetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) (ret error) = advapi32.SetNamedSecurityInfoW
|
||||||
|
//sys SetKernelObjectSecurity(handle Handle, securityInformation SECURITY_INFORMATION, securityDescriptor *SECURITY_DESCRIPTOR) (err error) = advapi32.SetKernelObjectSecurity
|
||||||
|
|
||||||
|
//sys buildSecurityDescriptor(owner *TRUSTEE, group *TRUSTEE, countAccessEntries uint32, accessEntries *EXPLICIT_ACCESS, countAuditEntries uint32, auditEntries *EXPLICIT_ACCESS, oldSecurityDescriptor *SECURITY_DESCRIPTOR, sizeNewSecurityDescriptor *uint32, newSecurityDescriptor **SECURITY_DESCRIPTOR) (ret error) = advapi32.BuildSecurityDescriptorW
|
||||||
|
//sys initializeSecurityDescriptor(absoluteSD *SECURITY_DESCRIPTOR, revision uint32) (err error) = advapi32.InitializeSecurityDescriptor
|
||||||
|
|
||||||
|
//sys getSecurityDescriptorControl(sd *SECURITY_DESCRIPTOR, control *SECURITY_DESCRIPTOR_CONTROL, revision *uint32) (err error) = advapi32.GetSecurityDescriptorControl
|
||||||
|
//sys getSecurityDescriptorDacl(sd *SECURITY_DESCRIPTOR, daclPresent *bool, dacl **ACL, daclDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorDacl
|
||||||
|
//sys getSecurityDescriptorSacl(sd *SECURITY_DESCRIPTOR, saclPresent *bool, sacl **ACL, saclDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorSacl
|
||||||
|
//sys getSecurityDescriptorOwner(sd *SECURITY_DESCRIPTOR, owner **SID, ownerDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorOwner
|
||||||
|
//sys getSecurityDescriptorGroup(sd *SECURITY_DESCRIPTOR, group **SID, groupDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorGroup
|
||||||
|
//sys getSecurityDescriptorLength(sd *SECURITY_DESCRIPTOR) (len uint32) = advapi32.GetSecurityDescriptorLength
|
||||||
|
//sys getSecurityDescriptorRMControl(sd *SECURITY_DESCRIPTOR, rmControl *uint8) (ret error) [failretval!=0] = advapi32.GetSecurityDescriptorRMControl
|
||||||
|
//sys isValidSecurityDescriptor(sd *SECURITY_DESCRIPTOR) (isValid bool) = advapi32.IsValidSecurityDescriptor
|
||||||
|
|
||||||
|
//sys setSecurityDescriptorControl(sd *SECURITY_DESCRIPTOR, controlBitsOfInterest SECURITY_DESCRIPTOR_CONTROL, controlBitsToSet SECURITY_DESCRIPTOR_CONTROL) (err error) = advapi32.SetSecurityDescriptorControl
|
||||||
|
//sys setSecurityDescriptorDacl(sd *SECURITY_DESCRIPTOR, daclPresent bool, dacl *ACL, daclDefaulted bool) (err error) = advapi32.SetSecurityDescriptorDacl
|
||||||
|
//sys setSecurityDescriptorSacl(sd *SECURITY_DESCRIPTOR, saclPresent bool, sacl *ACL, saclDefaulted bool) (err error) = advapi32.SetSecurityDescriptorSacl
|
||||||
|
//sys setSecurityDescriptorOwner(sd *SECURITY_DESCRIPTOR, owner *SID, ownerDefaulted bool) (err error) = advapi32.SetSecurityDescriptorOwner
|
||||||
|
//sys setSecurityDescriptorGroup(sd *SECURITY_DESCRIPTOR, group *SID, groupDefaulted bool) (err error) = advapi32.SetSecurityDescriptorGroup
|
||||||
|
//sys setSecurityDescriptorRMControl(sd *SECURITY_DESCRIPTOR, rmControl *uint8) = advapi32.SetSecurityDescriptorRMControl
|
||||||
|
|
||||||
|
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd **SECURITY_DESCRIPTOR, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
|
||||||
|
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *SECURITY_DESCRIPTOR, revision uint32, securityInformation SECURITY_INFORMATION, str **uint16, strLen *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
|
||||||
|
|
||||||
|
//sys makeAbsoluteSD(selfRelativeSD *SECURITY_DESCRIPTOR, absoluteSD *SECURITY_DESCRIPTOR, absoluteSDSize *uint32, dacl *ACL, daclSize *uint32, sacl *ACL, saclSize *uint32, owner *SID, ownerSize *uint32, group *SID, groupSize *uint32) (err error) = advapi32.MakeAbsoluteSD
|
||||||
|
//sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD
|
||||||
|
|
||||||
|
//sys setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) = advapi32.SetEntriesInAclW
|
||||||
|
|
||||||
|
// Control returns the security descriptor control bits.
|
||||||
|
func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) {
|
||||||
|
err = getSecurityDescriptorControl(sd, &control, &revision)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetControl sets the security descriptor control bits.
|
||||||
|
func (sd *SECURITY_DESCRIPTOR) SetControl(controlBitsOfInterest SECURITY_DESCRIPTOR_CONTROL, controlBitsToSet SECURITY_DESCRIPTOR_CONTROL) error {
|
||||||
|
return setSecurityDescriptorControl(sd, controlBitsOfInterest, controlBitsToSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RMControl returns the security descriptor resource manager control bits.
|
||||||
|
func (sd *SECURITY_DESCRIPTOR) RMControl() (control uint8, err error) {
|
||||||
|
err = getSecurityDescriptorRMControl(sd, &control)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRMControl sets the security descriptor resource manager control bits.
|
||||||
|
func (sd *SECURITY_DESCRIPTOR) SetRMControl(rmControl uint8) {
|
||||||
|
setSecurityDescriptorRMControl(sd, &rmControl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DACL returns the security descriptor DACL and whether it was defaulted. The dacl return value may be nil
|
||||||
|
// if a DACL exists but is an "empty DACL", meaning fully permissive. If the DACL does not exist, err returns
|
||||||
|
// ERROR_OBJECT_NOT_FOUND.
|
||||||
|
func (sd *SECURITY_DESCRIPTOR) DACL() (dacl *ACL, defaulted bool, err error) {
|
||||||
|
var present bool
|
||||||
|
err = getSecurityDescriptorDacl(sd, &present, &dacl, &defaulted)
|
||||||
|
if !present {
|
||||||
|
err = ERROR_OBJECT_NOT_FOUND
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDACL sets the absolute security descriptor DACL.
|
||||||
|
func (absoluteSD *SECURITY_DESCRIPTOR) SetDACL(dacl *ACL, present, defaulted bool) error {
|
||||||
|
return setSecurityDescriptorDacl(absoluteSD, present, dacl, defaulted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SACL returns the security descriptor SACL and whether it was defaulted. The sacl return value may be nil
|
||||||
|
// if a SACL exists but is an "empty SACL", meaning fully permissive. If the SACL does not exist, err returns
|
||||||
|
// ERROR_OBJECT_NOT_FOUND.
|
||||||
|
func (sd *SECURITY_DESCRIPTOR) SACL() (sacl *ACL, defaulted bool, err error) {
|
||||||
|
var present bool
|
||||||
|
err = getSecurityDescriptorSacl(sd, &present, &sacl, &defaulted)
|
||||||
|
if !present {
|
||||||
|
err = ERROR_OBJECT_NOT_FOUND
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSACL sets the absolute security descriptor SACL.
|
||||||
|
func (absoluteSD *SECURITY_DESCRIPTOR) SetSACL(sacl *ACL, present, defaulted bool) error {
|
||||||
|
return setSecurityDescriptorSacl(absoluteSD, present, sacl, defaulted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Owner returns the security descriptor owner and whether it was defaulted.
|
||||||
|
func (sd *SECURITY_DESCRIPTOR) Owner() (owner *SID, defaulted bool, err error) {
|
||||||
|
err = getSecurityDescriptorOwner(sd, &owner, &defaulted)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOwner sets the absolute security descriptor owner.
|
||||||
|
func (absoluteSD *SECURITY_DESCRIPTOR) SetOwner(owner *SID, defaulted bool) error {
|
||||||
|
return setSecurityDescriptorOwner(absoluteSD, owner, defaulted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group returns the security descriptor group and whether it was defaulted.
|
||||||
|
func (sd *SECURITY_DESCRIPTOR) Group() (group *SID, defaulted bool, err error) {
|
||||||
|
err = getSecurityDescriptorGroup(sd, &group, &defaulted)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetGroup sets the absolute security descriptor owner.
|
||||||
|
func (absoluteSD *SECURITY_DESCRIPTOR) SetGroup(group *SID, defaulted bool) error {
|
||||||
|
return setSecurityDescriptorGroup(absoluteSD, group, defaulted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Length returns the length of the security descriptor.
|
||||||
|
func (sd *SECURITY_DESCRIPTOR) Length() uint32 {
|
||||||
|
return getSecurityDescriptorLength(sd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid returns whether the security descriptor is valid.
|
||||||
|
func (sd *SECURITY_DESCRIPTOR) IsValid() bool {
|
||||||
|
return isValidSecurityDescriptor(sd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the SDDL form of the security descriptor, with a function signature that can be
|
||||||
|
// used with %v formatting directives.
|
||||||
|
func (sd *SECURITY_DESCRIPTOR) String() string {
|
||||||
|
var sddl *uint16
|
||||||
|
err := convertSecurityDescriptorToStringSecurityDescriptor(sd, 1, 0xff, &sddl, nil)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
defer LocalFree(Handle(unsafe.Pointer(sddl)))
|
||||||
|
return UTF16PtrToString(sddl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToAbsolute converts a self-relative security descriptor into an absolute one.
|
||||||
|
func (selfRelativeSD *SECURITY_DESCRIPTOR) ToAbsolute() (absoluteSD *SECURITY_DESCRIPTOR, err error) {
|
||||||
|
control, _, err := selfRelativeSD.Control()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if control&SE_SELF_RELATIVE == 0 {
|
||||||
|
err = ERROR_INVALID_PARAMETER
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var absoluteSDSize, daclSize, saclSize, ownerSize, groupSize uint32
|
||||||
|
err = makeAbsoluteSD(selfRelativeSD, nil, &absoluteSDSize,
|
||||||
|
nil, &daclSize, nil, &saclSize, nil, &ownerSize, nil, &groupSize)
|
||||||
|
switch err {
|
||||||
|
case ERROR_INSUFFICIENT_BUFFER:
|
||||||
|
case nil:
|
||||||
|
// makeAbsoluteSD is expected to fail, but it succeeds.
|
||||||
|
return nil, ERROR_INTERNAL_ERROR
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if absoluteSDSize > 0 {
|
||||||
|
absoluteSD = (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&make([]byte, absoluteSDSize)[0]))
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
dacl *ACL
|
||||||
|
sacl *ACL
|
||||||
|
owner *SID
|
||||||
|
group *SID
|
||||||
|
)
|
||||||
|
if daclSize > 0 {
|
||||||
|
dacl = (*ACL)(unsafe.Pointer(&make([]byte, daclSize)[0]))
|
||||||
|
}
|
||||||
|
if saclSize > 0 {
|
||||||
|
sacl = (*ACL)(unsafe.Pointer(&make([]byte, saclSize)[0]))
|
||||||
|
}
|
||||||
|
if ownerSize > 0 {
|
||||||
|
owner = (*SID)(unsafe.Pointer(&make([]byte, ownerSize)[0]))
|
||||||
|
}
|
||||||
|
if groupSize > 0 {
|
||||||
|
group = (*SID)(unsafe.Pointer(&make([]byte, groupSize)[0]))
|
||||||
|
}
|
||||||
|
err = makeAbsoluteSD(selfRelativeSD, absoluteSD, &absoluteSDSize,
|
||||||
|
dacl, &daclSize, sacl, &saclSize, owner, &ownerSize, group, &groupSize)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSelfRelative converts an absolute security descriptor into a self-relative one.
|
||||||
|
func (absoluteSD *SECURITY_DESCRIPTOR) ToSelfRelative() (selfRelativeSD *SECURITY_DESCRIPTOR, err error) {
|
||||||
|
control, _, err := absoluteSD.Control()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if control&SE_SELF_RELATIVE != 0 {
|
||||||
|
err = ERROR_INVALID_PARAMETER
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var selfRelativeSDSize uint32
|
||||||
|
err = makeSelfRelativeSD(absoluteSD, nil, &selfRelativeSDSize)
|
||||||
|
switch err {
|
||||||
|
case ERROR_INSUFFICIENT_BUFFER:
|
||||||
|
case nil:
|
||||||
|
// makeSelfRelativeSD is expected to fail, but it succeeds.
|
||||||
|
return nil, ERROR_INTERNAL_ERROR
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if selfRelativeSDSize > 0 {
|
||||||
|
selfRelativeSD = (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&make([]byte, selfRelativeSDSize)[0]))
|
||||||
|
}
|
||||||
|
err = makeSelfRelativeSD(absoluteSD, selfRelativeSD, &selfRelativeSDSize)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (selfRelativeSD *SECURITY_DESCRIPTOR) copySelfRelativeSecurityDescriptor() *SECURITY_DESCRIPTOR {
|
||||||
|
sdLen := int(selfRelativeSD.Length())
|
||||||
|
const min = int(unsafe.Sizeof(SECURITY_DESCRIPTOR{}))
|
||||||
|
if sdLen < min {
|
||||||
|
sdLen = min
|
||||||
|
}
|
||||||
|
|
||||||
|
src := unsafe.Slice((*byte)(unsafe.Pointer(selfRelativeSD)), sdLen)
|
||||||
|
// SECURITY_DESCRIPTOR has pointers in it, which means checkptr expects for it to
|
||||||
|
// be aligned properly. When we're copying a Windows-allocated struct to a
|
||||||
|
// Go-allocated one, make sure that the Go allocation is aligned to the
|
||||||
|
// pointer size.
|
||||||
|
const psize = int(unsafe.Sizeof(uintptr(0)))
|
||||||
|
alloc := make([]uintptr, (sdLen+psize-1)/psize)
|
||||||
|
dst := unsafe.Slice((*byte)(unsafe.Pointer(&alloc[0])), sdLen)
|
||||||
|
copy(dst, src)
|
||||||
|
return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&dst[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecurityDescriptorFromString converts an SDDL string describing a security descriptor into a
|
||||||
|
// self-relative security descriptor object allocated on the Go heap.
|
||||||
|
func SecurityDescriptorFromString(sddl string) (sd *SECURITY_DESCRIPTOR, err error) {
|
||||||
|
var winHeapSD *SECURITY_DESCRIPTOR
|
||||||
|
err = convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &winHeapSD, nil)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
|
||||||
|
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSecurityInfo queries the security information for a given handle and returns the self-relative security
|
||||||
|
// descriptor result on the Go heap.
|
||||||
|
func GetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION) (sd *SECURITY_DESCRIPTOR, err error) {
|
||||||
|
var winHeapSD *SECURITY_DESCRIPTOR
|
||||||
|
err = getSecurityInfo(handle, objectType, securityInformation, nil, nil, nil, nil, &winHeapSD)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
|
||||||
|
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNamedSecurityInfo queries the security information for a given named object and returns the self-relative security
|
||||||
|
// descriptor result on the Go heap.
|
||||||
|
func GetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION) (sd *SECURITY_DESCRIPTOR, err error) {
|
||||||
|
var winHeapSD *SECURITY_DESCRIPTOR
|
||||||
|
err = getNamedSecurityInfo(objectName, objectType, securityInformation, nil, nil, nil, nil, &winHeapSD)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
|
||||||
|
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildSecurityDescriptor makes a new security descriptor using the input trustees, explicit access lists, and
|
||||||
|
// prior security descriptor to be merged, any of which can be nil, returning the self-relative security descriptor
|
||||||
|
// result on the Go heap.
|
||||||
|
func BuildSecurityDescriptor(owner *TRUSTEE, group *TRUSTEE, accessEntries []EXPLICIT_ACCESS, auditEntries []EXPLICIT_ACCESS, mergedSecurityDescriptor *SECURITY_DESCRIPTOR) (sd *SECURITY_DESCRIPTOR, err error) {
|
||||||
|
var winHeapSD *SECURITY_DESCRIPTOR
|
||||||
|
var winHeapSDSize uint32
|
||||||
|
var firstAccessEntry *EXPLICIT_ACCESS
|
||||||
|
if len(accessEntries) > 0 {
|
||||||
|
firstAccessEntry = &accessEntries[0]
|
||||||
|
}
|
||||||
|
var firstAuditEntry *EXPLICIT_ACCESS
|
||||||
|
if len(auditEntries) > 0 {
|
||||||
|
firstAuditEntry = &auditEntries[0]
|
||||||
|
}
|
||||||
|
err = buildSecurityDescriptor(owner, group, uint32(len(accessEntries)), firstAccessEntry, uint32(len(auditEntries)), firstAuditEntry, mergedSecurityDescriptor, &winHeapSDSize, &winHeapSD)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
|
||||||
|
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSecurityDescriptor creates and initializes a new absolute security descriptor.
|
||||||
|
func NewSecurityDescriptor() (absoluteSD *SECURITY_DESCRIPTOR, err error) {
|
||||||
|
absoluteSD = &SECURITY_DESCRIPTOR{}
|
||||||
|
err = initializeSecurityDescriptor(absoluteSD, 1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACLFromEntries returns a new ACL on the Go heap containing a list of explicit entries as well as those of another ACL.
|
||||||
|
// Both explicitEntries and mergedACL are optional and can be nil.
|
||||||
|
func ACLFromEntries(explicitEntries []EXPLICIT_ACCESS, mergedACL *ACL) (acl *ACL, err error) {
|
||||||
|
var firstExplicitEntry *EXPLICIT_ACCESS
|
||||||
|
if len(explicitEntries) > 0 {
|
||||||
|
firstExplicitEntry = &explicitEntries[0]
|
||||||
|
}
|
||||||
|
var winHeapACL *ACL
|
||||||
|
err = setEntriesInAcl(uint32(len(explicitEntries)), firstExplicitEntry, mergedACL, &winHeapACL)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer LocalFree(Handle(unsafe.Pointer(winHeapACL)))
|
||||||
|
aclBytes := make([]byte, winHeapACL.aclSize)
|
||||||
|
copy(aclBytes, (*[(1 << 31) - 1]byte)(unsafe.Pointer(winHeapACL))[:len(aclBytes):len(aclBytes)])
|
||||||
|
return (*ACL)(unsafe.Pointer(&aclBytes[0])), nil
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build windows
|
//go:build windows
|
||||||
|
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
|
@ -16,8 +16,6 @@ const (
|
||||||
SC_MANAGER_ALL_ACCESS = 0xf003f
|
SC_MANAGER_ALL_ACCESS = 0xf003f
|
||||||
)
|
)
|
||||||
|
|
||||||
//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenSCManagerW
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SERVICE_KERNEL_DRIVER = 1
|
SERVICE_KERNEL_DRIVER = 1
|
||||||
SERVICE_FILE_SYSTEM_DRIVER = 2
|
SERVICE_FILE_SYSTEM_DRIVER = 2
|
||||||
|
@ -65,6 +63,7 @@ const (
|
||||||
SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 32
|
SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 32
|
||||||
SERVICE_ACCEPT_POWEREVENT = 64
|
SERVICE_ACCEPT_POWEREVENT = 64
|
||||||
SERVICE_ACCEPT_SESSIONCHANGE = 128
|
SERVICE_ACCEPT_SESSIONCHANGE = 128
|
||||||
|
SERVICE_ACCEPT_PRESHUTDOWN = 256
|
||||||
|
|
||||||
SERVICE_CONTROL_STOP = 1
|
SERVICE_CONTROL_STOP = 1
|
||||||
SERVICE_CONTROL_PAUSE = 2
|
SERVICE_CONTROL_PAUSE = 2
|
||||||
|
@ -80,6 +79,7 @@ const (
|
||||||
SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12
|
SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12
|
||||||
SERVICE_CONTROL_POWEREVENT = 13
|
SERVICE_CONTROL_POWEREVENT = 13
|
||||||
SERVICE_CONTROL_SESSIONCHANGE = 14
|
SERVICE_CONTROL_SESSIONCHANGE = 14
|
||||||
|
SERVICE_CONTROL_PRESHUTDOWN = 15
|
||||||
|
|
||||||
SERVICE_ACTIVE = 1
|
SERVICE_ACTIVE = 1
|
||||||
SERVICE_INACTIVE = 2
|
SERVICE_INACTIVE = 2
|
||||||
|
@ -126,8 +126,26 @@ const (
|
||||||
SERVICE_NOTIFY_CREATED = 0x00000080
|
SERVICE_NOTIFY_CREATED = 0x00000080
|
||||||
SERVICE_NOTIFY_DELETED = 0x00000100
|
SERVICE_NOTIFY_DELETED = 0x00000100
|
||||||
SERVICE_NOTIFY_DELETE_PENDING = 0x00000200
|
SERVICE_NOTIFY_DELETE_PENDING = 0x00000200
|
||||||
|
|
||||||
|
SC_EVENT_DATABASE_CHANGE = 0
|
||||||
|
SC_EVENT_PROPERTY_CHANGE = 1
|
||||||
|
SC_EVENT_STATUS_CHANGE = 2
|
||||||
|
|
||||||
|
SERVICE_START_REASON_DEMAND = 0x00000001
|
||||||
|
SERVICE_START_REASON_AUTO = 0x00000002
|
||||||
|
SERVICE_START_REASON_TRIGGER = 0x00000004
|
||||||
|
SERVICE_START_REASON_RESTART_ON_FAILURE = 0x00000008
|
||||||
|
SERVICE_START_REASON_DELAYEDAUTO = 0x00000010
|
||||||
|
|
||||||
|
SERVICE_DYNAMIC_INFORMATION_LEVEL_START_REASON = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ENUM_SERVICE_STATUS struct {
|
||||||
|
ServiceName *uint16
|
||||||
|
DisplayName *uint16
|
||||||
|
ServiceStatus SERVICE_STATUS
|
||||||
|
}
|
||||||
|
|
||||||
type SERVICE_STATUS struct {
|
type SERVICE_STATUS struct {
|
||||||
ServiceType uint32
|
ServiceType uint32
|
||||||
CurrentState uint32
|
CurrentState uint32
|
||||||
|
@ -159,6 +177,10 @@ type SERVICE_DESCRIPTION struct {
|
||||||
Description *uint16
|
Description *uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SERVICE_DELAYED_AUTO_START_INFO struct {
|
||||||
|
IsDelayedAutoStartUp uint32
|
||||||
|
}
|
||||||
|
|
||||||
type SERVICE_STATUS_PROCESS struct {
|
type SERVICE_STATUS_PROCESS struct {
|
||||||
ServiceType uint32
|
ServiceType uint32
|
||||||
CurrentState uint32
|
CurrentState uint32
|
||||||
|
@ -195,6 +217,10 @@ type SERVICE_FAILURE_ACTIONS struct {
|
||||||
Actions *SC_ACTION
|
Actions *SC_ACTION
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SERVICE_FAILURE_ACTIONS_FLAG struct {
|
||||||
|
FailureActionsOnNonCrashFailures int32
|
||||||
|
}
|
||||||
|
|
||||||
type SC_ACTION struct {
|
type SC_ACTION struct {
|
||||||
Type uint32
|
Type uint32
|
||||||
Delay uint32
|
Delay uint32
|
||||||
|
@ -206,6 +232,7 @@ type QUERY_SERVICE_LOCK_STATUS struct {
|
||||||
LockDuration uint32
|
LockDuration uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenSCManagerW
|
||||||
//sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle
|
//sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle
|
||||||
//sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW
|
//sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW
|
||||||
//sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW
|
//sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW
|
||||||
|
@ -223,3 +250,8 @@ type QUERY_SERVICE_LOCK_STATUS struct {
|
||||||
//sys EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serviceState uint32, services *byte, bufSize uint32, bytesNeeded *uint32, servicesReturned *uint32, resumeHandle *uint32, groupName *uint16) (err error) = advapi32.EnumServicesStatusExW
|
//sys EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serviceState uint32, services *byte, bufSize uint32, bytesNeeded *uint32, servicesReturned *uint32, resumeHandle *uint32, groupName *uint16) (err error) = advapi32.EnumServicesStatusExW
|
||||||
//sys QueryServiceStatusEx(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceStatusEx
|
//sys QueryServiceStatusEx(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceStatusEx
|
||||||
//sys NotifyServiceStatusChange(service Handle, notifyMask uint32, notifier *SERVICE_NOTIFY) (ret error) = advapi32.NotifyServiceStatusChangeW
|
//sys NotifyServiceStatusChange(service Handle, notifyMask uint32, notifier *SERVICE_NOTIFY) (ret error) = advapi32.NotifyServiceStatusChangeW
|
||||||
|
//sys SubscribeServiceChangeNotifications(service Handle, eventType uint32, callback uintptr, callbackCtx uintptr, subscription *uintptr) (ret error) = sechost.SubscribeServiceChangeNotifications?
|
||||||
|
//sys UnsubscribeServiceChangeNotifications(subscription uintptr) = sechost.UnsubscribeServiceChangeNotifications?
|
||||||
|
//sys RegisterServiceCtrlHandlerEx(serviceName *uint16, handlerProc uintptr, context uintptr) (handle Handle, err error) = advapi32.RegisterServiceCtrlHandlerExW
|
||||||
|
//sys QueryServiceDynamicInformation(service Handle, infoLevel uint32, dynamicInfo unsafe.Pointer) (err error) = advapi32.QueryServiceDynamicInformation?
|
||||||
|
//sys EnumDependentServices(service Handle, activityState uint32, services *ENUM_SERVICE_STATUS, buffSize uint32, bytesNeeded *uint32, servicesReturned *uint32) (err error) = advapi32.EnumDependentServicesW
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build windows
|
//go:build windows
|
||||||
|
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build windows
|
//go:build windows
|
||||||
|
|
||||||
// Package windows contains an interface to the low-level operating system
|
// Package windows contains an interface to the low-level operating system
|
||||||
// primitives. OS details vary depending on the underlying system, and
|
// primitives. OS details vary depending on the underlying system, and
|
||||||
|
@ -25,17 +25,18 @@
|
||||||
package windows // import "golang.org/x/sys/windows"
|
package windows // import "golang.org/x/sys/windows"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
||||||
// containing the text of s. If s contains a NUL byte at any
|
// containing the text of s. If s contains a NUL byte at any
|
||||||
// location, it returns (nil, syscall.EINVAL).
|
// location, it returns (nil, syscall.EINVAL).
|
||||||
func ByteSliceFromString(s string) ([]byte, error) {
|
func ByteSliceFromString(s string) ([]byte, error) {
|
||||||
for i := 0; i < len(s); i++ {
|
if strings.IndexByte(s, 0) != -1 {
|
||||||
if s[i] == 0 {
|
return nil, syscall.EINVAL
|
||||||
return nil, syscall.EINVAL
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
a := make([]byte, len(s)+1)
|
a := make([]byte, len(s)+1)
|
||||||
copy(a, s)
|
copy(a, s)
|
||||||
|
@ -53,6 +54,35 @@ func BytePtrFromString(s string) (*byte, error) {
|
||||||
return &a[0], nil
|
return &a[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ByteSliceToString returns a string form of the text represented by the slice s, with a terminating NUL and any
|
||||||
|
// bytes after the NUL removed.
|
||||||
|
func ByteSliceToString(s []byte) string {
|
||||||
|
if i := bytes.IndexByte(s, 0); i != -1 {
|
||||||
|
s = s[:i]
|
||||||
|
}
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytePtrToString takes a pointer to a sequence of text and returns the corresponding string.
|
||||||
|
// If the pointer is nil, it returns the empty string. It assumes that the text sequence is terminated
|
||||||
|
// at a zero byte; if the zero byte is not present, the program may crash.
|
||||||
|
func BytePtrToString(p *byte) string {
|
||||||
|
if p == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if *p == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find NUL terminator.
|
||||||
|
n := 0
|
||||||
|
for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ {
|
||||||
|
ptr = unsafe.Pointer(uintptr(ptr) + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(unsafe.Slice(p, n))
|
||||||
|
}
|
||||||
|
|
||||||
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
||||||
// See mksyscall.pl.
|
// See mksyscall.pl.
|
||||||
var _zero uintptr
|
var _zero uintptr
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -20,3 +20,16 @@ type Servent struct {
|
||||||
Port uint16
|
Port uint16
|
||||||
Proto *byte
|
Proto *byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type JOBOBJECT_BASIC_LIMIT_INFORMATION struct {
|
||||||
|
PerProcessUserTimeLimit int64
|
||||||
|
PerJobUserTimeLimit int64
|
||||||
|
LimitFlags uint32
|
||||||
|
MinimumWorkingSetSize uintptr
|
||||||
|
MaximumWorkingSetSize uintptr
|
||||||
|
ActiveProcessLimit uint32
|
||||||
|
Affinity uintptr
|
||||||
|
PriorityClass uint32
|
||||||
|
SchedulingClass uint32
|
||||||
|
_ uint32 // pad to 8 byte boundary
|
||||||
|
}
|
||||||
|
|
|
@ -20,3 +20,15 @@ type Servent struct {
|
||||||
Proto *byte
|
Proto *byte
|
||||||
Port uint16
|
Port uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type JOBOBJECT_BASIC_LIMIT_INFORMATION struct {
|
||||||
|
PerProcessUserTimeLimit int64
|
||||||
|
PerJobUserTimeLimit int64
|
||||||
|
LimitFlags uint32
|
||||||
|
MinimumWorkingSetSize uintptr
|
||||||
|
MaximumWorkingSetSize uintptr
|
||||||
|
ActiveProcessLimit uint32
|
||||||
|
Affinity uintptr
|
||||||
|
PriorityClass uint32
|
||||||
|
SchedulingClass uint32
|
||||||
|
}
|
||||||
|
|
|
@ -20,3 +20,16 @@ type Servent struct {
|
||||||
Port uint16
|
Port uint16
|
||||||
Proto *byte
|
Proto *byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type JOBOBJECT_BASIC_LIMIT_INFORMATION struct {
|
||||||
|
PerProcessUserTimeLimit int64
|
||||||
|
PerJobUserTimeLimit int64
|
||||||
|
LimitFlags uint32
|
||||||
|
MinimumWorkingSetSize uintptr
|
||||||
|
MaximumWorkingSetSize uintptr
|
||||||
|
ActiveProcessLimit uint32
|
||||||
|
Affinity uintptr
|
||||||
|
PriorityClass uint32
|
||||||
|
SchedulingClass uint32
|
||||||
|
_ uint32 // pad to 8 byte boundary
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
type WSAData struct {
|
||||||
|
Version uint16
|
||||||
|
HighVersion uint16
|
||||||
|
MaxSockets uint16
|
||||||
|
MaxUdpDg uint16
|
||||||
|
VendorInfo *byte
|
||||||
|
Description [WSADESCRIPTION_LEN + 1]byte
|
||||||
|
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Servent struct {
|
||||||
|
Name *byte
|
||||||
|
Aliases **byte
|
||||||
|
Proto *byte
|
||||||
|
Port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type JOBOBJECT_BASIC_LIMIT_INFORMATION struct {
|
||||||
|
PerProcessUserTimeLimit int64
|
||||||
|
PerJobUserTimeLimit int64
|
||||||
|
LimitFlags uint32
|
||||||
|
MinimumWorkingSetSize uintptr
|
||||||
|
MaximumWorkingSetSize uintptr
|
||||||
|
ActiveProcessLimit uint32
|
||||||
|
Affinity uintptr
|
||||||
|
PriorityClass uint32
|
||||||
|
SchedulingClass uint32
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,8 @@
|
||||||
# git.rootprojects.org/root/go-gitver v1.1.3
|
# git.rootprojects.org/root/go-gitver v1.1.3
|
||||||
|
## explicit; go 1.12
|
||||||
git.rootprojects.org/root/go-gitver
|
git.rootprojects.org/root/go-gitver
|
||||||
git.rootprojects.org/root/go-gitver/gitver
|
git.rootprojects.org/root/go-gitver/gitver
|
||||||
# golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7
|
# golang.org/x/sys v0.14.0
|
||||||
golang.org/x/sys/windows/registry
|
## explicit; go 1.18
|
||||||
golang.org/x/sys/windows
|
golang.org/x/sys/windows
|
||||||
|
golang.org/x/sys/windows/registry
|
||||||
|
|
Loading…
Reference in New Issue