Golang - Set syscall user context in Windows - windows

I am making two syscalls to the IIS Hosted Web Core (HWC) WebCoreActivate and WebCoreShutdown APIs. I would like to add a user context, so when the syscalls are made in Windows, they are run underneath a specific user's context - i.e., that user's permissions.
type WebCore struct {
activated bool
Handle syscall.Handle
Credentials syscall.Credential
}
func New() (error, *WebCore) {
hwebcore, err := syscall.LoadLibrary(os.ExpandEnv(`${windir}\system32\inetsrv\hwebcore.dll`))
if err != nil {
return err, nil
}
return nil, &WebCore{
activated: false,
Handle: hwebcore,
}
}
func (w *WebCore) Activate(appHostConfigPath, rootWebConfigPath, instanceName string) error {
if !w.activated {
webCoreActivate, err := syscall.GetProcAddress(w.Handle, "WebCoreActivate")
if err != nil {
return err
}
var nargs uintptr = 3
_, _, exitCode := syscall.Syscall(uintptr(webCoreActivate),
nargs,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(appHostConfigPath))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(rootWebConfigPath))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(instanceName))))
if exitCode != 0 {
return fmt.Errorf("WebCoreActivate returned exit code: %d", exitCode)
}
fmt.Printf("Server Started for %+v\n", instanceName)
w.activated = true
}
return nil
}
func (w *WebCore) Shutdown(immediate int, instanceName string) error {
if w.activated {
webCoreShutdown, err := syscall.GetProcAddress(w.Handle, "WebCoreShutdown")
if err != nil {
return err
}
var nargs uintptr = 1
_, _, exitCode := syscall.Syscall(uintptr(webCoreShutdown),
nargs, uintptr(unsafe.Pointer(&immediate)), 0, 0)
if exitCode != 0 {
return fmt.Errorf("WebCoreShutdown returned exit code: %d", exitCode)
}
fmt.Printf("Server Shutdown for %+v\n", instanceName)
}
return nil
}
I've been reading about the exec.Command().SysProcAttr structure, and how you can attach specific user credentials via the syscall.Credentials{} structure. However, that seems limited to executing commands via os.exec. If I wanted to tie a specific user's context to a native syscall in Windows, how would I do that?

Related

GO: implementing syscall.Sockaddr

I am working on an embedded system that uses GO v1.13 on the build server. My goal is to make a CANbus manager using linux's socketCAN. Go has a can-go package that is perfect for this solution. However, the package uses the "golang.org/x/sys/" package that uses the unsafe.Slice that was added in Go v1.17. I am unable to upgrade my version to a supported go version.
To solve this issue, I am making my own package that is very similar to can-go but uses syscall.socket instead of unix.socket.
The issue that I have ran into is with the implementation of syscall.Sockaddr. I have implemented it identically to the can-go package but I am getting the following terminal output.
.\canSocket.go:91:42: cannot use &SockaddrCAN literal (type *SockaddrCAN) as type syscall.Sockaddr in argument to syscall.Bind:
*SockaddrCAN does not implement syscall.Sockaddr (missing syscall.sockaddr method)
have sockaddr() (unsafe.Pointer, int32, error)
want syscall.sockaddr() (unsafe.Pointer, int32, error)
I must be missing something very obvious as this looks to be the standard "you are incorrectly implementing an interface" message. I am very new to GO and am expecting that I have missed something fundamental. Can anyone see what I did wrong? Below is the relevant section of my code.
func DialRaw(device string) (net.Conn, error) {
var err error
defer func() {
if err != nil {
err = &net.OpError{Op: "dial", Net: canRawNetwork, Addr: &canRawAddr{device: device}, Err: err}
}
}()
ifi, err := net.InterfaceByName(device)
if err != nil {
return nil, fmt.Errorf("interface %s: %w", device, err)
}
fd, err := syscall.Socket(AF_CAN, SOCK_RAW, CAN_RAW)
if err != nil {
return nil, fmt.Errorf("socket: %w", err)
}
// put fd in non-blocking mode so the created file will be registered by the runtime poller (Go >= 1.12)
if err := syscall.SetNonblock(fd, true); err != nil {
return nil, fmt.Errorf("set nonblock: %w", err)
}
if err := syscall.Bind(fd, &SockaddrCAN{Ifindex: ifi.Index}); err != nil {
return nil, fmt.Errorf("bind: %w", err)
}
return &fileConn{ra: &canRawAddr{device: device}, f: os.NewFile(uintptr(fd), "can")}, nil
}
type RawSockaddrCAN struct {
Family uint16
Ifindex int32
Addr [16]byte
}
type SockaddrCAN struct {
Ifindex int
RxID uint32
TxID uint32
raw RawSockaddrCAN
}
func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, int32, error) {
if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
return nil, 0, EINVAL
}
sa.raw.Family = AF_CAN
sa.raw.Ifindex = int32(sa.Ifindex)
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
for i := 0; i < 4; i++ {
sa.raw.Addr[i] = rx[i]
}
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
for i := 0; i < 4; i++ {
sa.raw.Addr[i+4] = tx[i]
}
return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
}

pgxpool's config.AfterRelease is not firing

I have the following code:
func (s *SqlServerDatabase) ConnectPool() {
config, err := pgxpool.ParseConfig(s.Url)
if err != nil {
fmt.Println("config Database Fail")
fmt.Print(err)
}
config.AfterRelease = func(conn *pgx.Conn) bool {
fmt.Println("After Releasing")
return true
}
config.BeforeAquire = func(ctx context.Context, conn *pgx.Conn) bool {
fmt.Println("Before Aquiring")
return true
}
conn, err := pgxpool.ConnectConfig(context.Background(), config)
s.PoolConn = conn
}
func (s *SqlServerDatabase) PoolQuery(query string) (pgx.Rows, error) {
conn, err := s.PoolConn.Acquire(context.Background())
if err != nil {
log.Printf("Couldn't get a connection with the database. Reason %v", err)
} else {
// release the connection to the pool after using it
defer conn.Release()
results, err := conn.Query(context.Background(), query)
if err != nil {
log.Printf("Couldn't execute query. Reason %v", err)
} else {
// show the results boy, you got it.
fmt.Printf("%T\n", results)
}
return results, err
}
return nil, err
}
So :
I create the connection in ConnectPool. thats where I set up the config and connect.
Then In my query method I acquire one of the pools the BeforeAcquire method fires and prints.
But the AfterRelease method never does.
I release the connection in the deferred call so I'm not sure why its not running.
See the code at pgxpool/conn.go l.30 :
/*20*/ func (c *Conn) Release() {
...
/*30*/ if conn.IsClosed() || conn.PgConn().IsBusy() ||
conn.PgConn().TxStatus() != 'I' ||
(now.Sub(res.CreationTime()) > c.p.maxConnLifetime) {
res.Destroy()
return
}
/* 'c.afterRelease' is checked and used only after that block */
So : under some conditions, the connection is detroyed right away, and AfterRelease is indeed never executed.
note: the code link reflects the state of the master branch on 2021-05-05.

Mocking open in go…

I have been following this answer trying to mock open. I have got exactly no where.
This is the test code I have:
func (m mockedFS) Open(name string) (file, error) {
if m.reportErrOpen {
return nil, errors.New("Fake failure")
}
mockedFile := mockIORead{}
mockedFile.On("ReadAll", mock.AnythingOfType("[]uint8")).Return(0, fmt.Errorf("error reading"))
mockedFile.On("Read", mock.AnythingOfType("[]byte")).Return(0, errors.New("NON"))
return mockedFile, nil
}
type mockIORead struct {
mock.Mock
reportErr bool // Tells if this mocked FS should return error in our tests
reportSize int64 // Tells what size should Stat() report in our test
}
func (m mockIORead) Read(b []byte) (n int, err error) {
if m.reportErr {
return 0, errors.New("A fake failure")
}
s := "Fear the old blood"
copy(b[:], s)
return 0, nil
}
func (m mockIORead) Close() error {
return nil
}
func (m mockIORead) ReadAt([]byte, int64) (int, error) {
return 0, nil
}
func (m mockIORead) Seek(int64, int) (int64, error) {
return 0, nil
}
func (m mockIORead) Stat() (os.FileInfo, error) {
if m.reportErr {
return nil, os.ErrNotExist
}
return mockedFileInfo{size: m.reportSize}, nil
}
func TestOok(t *testing.T) {
oldFs := fs
// Create and "install" mocked fs:
mfs := &mockedFS{}
fs = mfs
// Make sure fs is restored after this test:
defer func() {
fs = oldFs
}()
mfs.reportErr = false
mfs.reportErrOpen = false
token, err := Ook("fake")
assert.NotNil(t, err)
assert.Equal(t, "Fear the old blood", token)
}
And this is the code under test:
func Ook(name string) (string, error) {
_, err := fs.Stat(name)
if err != nil {
return "", nil
}
file, err := fs.Open(name)
if err != nil {
return "", errors.Wrap(err, "Cannot open token file")
}
defer file.Close()
_, err = ioutil.ReadAll(file)
fmt.Print("PING\n")
if err != nil {
return "", errors.Wrap(err, "Could not read token")
}
return "Fear the old blood", nil
//return string(token), nil
}
What the hell am I doing wrong?
The first error is that your mockIORead.Read() returns wrong values. It must return the number of read bytes (bytes written to the slice argument) (e.g. what copy() would return).
Next, mockIORead.Read() must be stateful! Reader.Read() might be called several times, there is no guarantee the passed slice can accommodate all the data you want to return (via the passed b slice).
So mockIORead must store the data you want to return, and it must remember how much of them has been delivered so far, so the next Read() call can continue from there.
An easy implementation of this is to utilize bytes.Buffer:
type mockIORead struct {
mock.Mock
reportErr bool // Tells if this mocked FS should return error in our tests
reportSize int64 // Tells what size should Stat() report in our test
content *bytes.Buffer
}
When returning such a mockIORead, initialize content with the content you wish to return:
func (m mockedFS) Open(name string) (file, error) {
if m.reportErrOpen {
return nil, errors.New("Fake failure")
}
mockedFile := mockIORead{
content: bytes.NewBufferString("Fear the old blood"),
}
return mockedFile, nil
}
And thanks to the available bytes.Buffer.Read() method, the mockIORead.Read() implementation can be as simple as this:
func (m mockIORead) Read(b []byte) (n int, err error) {
if m.reportErr {
return 0, errors.New("A fake failure")
}
return m.content.Read(b)
}
The Ook() function itself should not try to "stat" as you haven't mocked it (and so calling the original os.Stat() will likely yield an error for the "fake" file name used in the test):
func Ook(name string) (string, error) {
file, err := fs.Open(name)
if err != nil {
return "", errors.Wrap(err, "Cannot open token file")
}
defer file.Close()
token, err := ioutil.ReadAll(file)
fmt.Print("PING\n")
if err != nil {
return "", errors.Wrap(err, "Could not read token")
}
return string(token), nil
}
And the testing code:
func TestOok(t *testing.T) {
oldFs := fs
// Create and "install" mocked fs:
mfs := &mockedFS{}
fs = mfs
// Make sure fs is restored after this test:
defer func() {
fs = oldFs
}()
mfs.reportErr = false
mfs.reportErrOpen = false
token, err := Ook("fake")
assert.Nil(t, err)
assert.Equal(t, "Fear the old blood", token)
}
Which yields a successful ("OK") test.

How to get process id by process name in windows environment?

I want to get the process id by the process name in windows environment?
I find golang only has the api os.FindProcess(id),but no by name.
I had to struggle with this too, and found the way to the solution not very straightforward, because… WinApi :)
In the end you have to create a snapshot of the current windows process list using CreateToolhelp32Snapshot. Then you get the first process in the snapshot with Process32First. After that keep iterating over the list with Process32Next, until you get the ERROR_NO_MORE_FILES error. Only then you have the whole process list.
See how2readwindowsprocesses for a working example.
Here is the gist:
const TH32CS_SNAPPROCESS = 0x00000002
type WindowsProcess struct {
ProcessID int
ParentProcessID int
Exe string
}
func processes() ([]WindowsProcess, error) {
handle, err := windows.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
if err != nil {
return nil, err
}
defer windows.CloseHandle(handle)
var entry windows.ProcessEntry32
entry.Size = uint32(unsafe.Sizeof(entry))
// get the first process
err = windows.Process32First(handle, &entry)
if err != nil {
return nil, err
}
results := make([]WindowsProcess, 0, 50)
for {
results = append(results, newWindowsProcess(&entry))
err = windows.Process32Next(handle, &entry)
if err != nil {
// windows sends ERROR_NO_MORE_FILES on last process
if err == syscall.ERROR_NO_MORE_FILES {
return results, nil
}
return nil, err
}
}
}
func findProcessByName(processes []WindowsProcess, name string) *WindowsProcess {
for _, p := range processes {
if strings.ToLower(p.Exe) == strings.ToLower(name) {
return &p
}
}
return nil
}
func newWindowsProcess(e *windows.ProcessEntry32) WindowsProcess {
// Find when the string ends for decoding
end := 0
for {
if e.ExeFile[end] == 0 {
break
}
end++
}
return WindowsProcess{
ProcessID: int(e.ProcessID),
ParentProcessID: int(e.ParentProcessID),
Exe: syscall.UTF16ToString(e.ExeFile[:end]),
}
}
You can list all the processes and match them with the name you want to find, by using the updated sys call package, https://godoc.org/golang.org/x/sys,
it has most of the windows api.
func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error)
func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error)
also see the msdn docs:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms684834(v=vs.85).aspx
const TH32CS_SNAPPROCESS = 0x00000002
type WindowsProcess struct {
ProcessID int
ParentProcessID int
Exe string
}
func newWindowsProcess(e *syscall.ProcessEntry32) WindowsProcess {
// Find when the string ends for decoding
end := 0
for {
if e.ExeFile[end] == 0 {
break
}
end++
}
return WindowsProcess{
ProcessID: int(e.ProcessID),
ParentProcessID: int(e.ParentProcessID),
Exe: syscall.UTF16ToString(e.ExeFile[:end]),
}
}
func processes() ([]WindowsProcess, error) {
handle, err := syscall.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
if err != nil {
return nil, err
}
defer syscall.CloseHandle(handle)
var entry syscall.ProcessEntry32
entry.Size = uint32(unsafe.Sizeof(entry))
// get the first process
err = syscall.Process32First(handle, &entry)
if err != nil {
return nil, err
}
results := make([]WindowsProcess, 0, 50)
for {
results = append(results, newWindowsProcess(&entry))
err = syscall.Process32Next(handle, &entry)
if err != nil {
// windows sends ERROR_NO_MORE_FILES on last process
if err == syscall.ERROR_NO_MORE_FILES {
return results, nil
}
return nil, err
}
}
}
func findProcessByName(processes []WindowsProcess, name string) *WindowsProcess {
for _, p := range processes {
if bytes.Contains([]byte(strings.ToUpper(p.Exe)), []byte(strings.ToUpper(name))) {
return &p
}
}
return nil
}
This seems to do it:
package main
import (
"fmt"
"golang.org/x/sys/windows"
)
// unsafe.Sizeof(windows.ProcessEntry32{})
const processEntrySize = 568
func processID(name string) (uint32, error) {
h, e := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
if e != nil { return 0, e }
p := windows.ProcessEntry32{Size: processEntrySize}
for {
e := windows.Process32Next(h, &p)
if e != nil { return 0, e }
if windows.UTF16ToString(p.ExeFile[:]) == name {
return p.ProcessID, nil
}
}
return 0, fmt.Errorf("%q not found", name)
}
func main() {
n, e := processID("WindowsTerminal.exe")
if e != nil {
panic(e)
}
println(n)
}
https://pkg.go.dev/golang.org/x/sys/windows#CreateToolhelp32Snapshot

Handling multiple errors

I have Function 1:
func Function1() {
if err := Function2(); err != nil {
}
}
and Function2:
func Function2() error {
if err := doSomethingThatMightCauseError(); err != nil {
return errors.New("Error Type 1")
}
if err := doSomethingElseThatMightCauseError(); err != nil {
return errors.New("Error Type 2")
}
}
How can I detect what type of error has happened (internal, no results found in db etc) and then handle accordingly in Function 1?
You have 3 main options:
string based, i.e. looking into the message. This is of course pretty bad because if you later change one letter in the message, you need to rewrite all the checking code, so I'd avoid it.
If the error messages can stay constant, simply create errors as global variables, and then compare the received error with a known pre-defined one.
For example:
var ErrDB = errors.New("Database Error")
var ErrTimeout = errors.New("Timeout") //or whatever
and then
if err := someFunc(); err != nil {
switch err {
case ErrDB:
//do stuff that needs to be done here
case ErrTimeout:
//etc /etc
}
}
Create a custom error type, since errors are just interfaces, that can have some identifier or other contextual data.
For example:
const (
ErrDB = 1
ErrTimeout = 2
...
)
type MyError struct {
Code int
Message string
}
// This is what you need to be an error
func (e MyError)Error() string {
return e.Message
}
func NewError(s string, code int) error {
return MyError{s,code}
}
and then when you return it do something like this:
// Return a MyError with a DB code for db operations
func someFunc() error {
if err := talkToDB(); err != nil {
return NewError(err.Error(), ErrDB)
}
return nil
}
and when analyzing it:
if err := someFunc(); err != nil {
// check if this is a MyError
if me, ok := err.(MyError); ok {
// now we can check the code
switch me.Code {
case ErrDB:
//handle this
....
}
}
}

Resources