From 568528c747afe3ae991b0340d15cd6a897fd5c9d Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 6 May 2019 09:46:10 +0200 Subject: updater: move into manager --- updater/msirunner_windows.go | 71 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 9 deletions(-) (limited to 'updater/msirunner_windows.go') diff --git a/updater/msirunner_windows.go b/updater/msirunner_windows.go index dfa921ee..de3fb58e 100644 --- a/updater/msirunner_windows.go +++ b/updater/msirunner_windows.go @@ -6,26 +6,79 @@ package updater import ( + "crypto/rand" + "encoding/hex" + "errors" + "github.com/Microsoft/go-winio" "golang.org/x/sys/windows" - "golang.zx2c4.com/wireguard/windows/conf" + "os" "os/exec" "path" + "runtime" + "syscall" + "unsafe" ) -func runMsi(msiPath string) error { +func runMsi(msiPath string, userToken uintptr, env []string) error { system32, err := windows.GetSystemDirectory() if err != nil { return err } - cmd := exec.Command(path.Join(system32, "msiexec.exe"), "/qb!-", "/i", path.Base(msiPath)) - cmd.Dir = path.Dir(msiPath) - return cmd.Run() + devNull, err := os.OpenFile(os.DevNull, os.O_RDWR, 0) + if err != nil { + return err + } + defer devNull.Close() + attr := &os.ProcAttr{ + Sys: &syscall.SysProcAttr{ + Token: syscall.Token(userToken), + }, + Files: []*os.File{devNull, devNull, devNull}, + Env: env, + Dir: path.Dir(msiPath), + } + msiexec := path.Join(system32, "msiexec.exe") + proc, err := os.StartProcess(msiexec, []string{msiexec, "/qb!-", "/i", path.Base(msiPath)}, attr) + if err != nil { + return err + } + state, err := proc.Wait() + if err != nil { + return err + } + if !state.Success() { + return &exec.ExitError{ProcessState: state} + } + return nil } -func msiSaveDirectory() (string, error) { - configRootDir, err := conf.RootDirectory() +func msiTempFile() (*os.File, error) { + var randBytes [32]byte + n, err := rand.Read(randBytes[:]) + if err != nil { + return nil, err + } + if n != int(len(randBytes)) { + return nil, errors.New("Unable to generate random bytes") + } + sd, err := winio.SddlToSecurityDescriptor("O:SYD:PAI(A;;FA;;;SY)(A;;FR;;;BA)") + if err != nil { + return nil, err + } + sa := &windows.SecurityAttributes{ + Length: uint32(len(sd)), + SecurityDescriptor: uintptr(unsafe.Pointer(&sd[0])), + } + //TODO: os.TempDir() returns C:\windows\temp when calling from this context. Supposedly this is mostly secure + // against TOCTOU, but who knows! Look into this! + name := path.Join(os.TempDir(), hex.EncodeToString(randBytes[:])) + name16 := windows.StringToUTF16Ptr(name) + //TODO: it would be nice to specify delete_on_close, but msiexec.exe doesn't open its files with read sharing. + fileHandle, err := windows.CreateFile(name16, windows.GENERIC_WRITE, windows.FILE_SHARE_READ, sa, windows.CREATE_NEW, windows.FILE_ATTRIBUTE_NORMAL, 0) + runtime.KeepAlive(sd) if err != nil { - return "", err + return nil, err } - return path.Join(configRootDir, "Updates"), nil + windows.MoveFileEx(name16, nil, windows.MOVEFILE_DELAY_UNTIL_REBOOT) + return os.NewFile(uintptr(fileHandle), name), nil } -- cgit v1.2.3-59-g8ed1b