diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-05-06 09:46:10 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-05-06 15:55:02 +0200 |
commit | 568528c747afe3ae991b0340d15cd6a897fd5c9d (patch) | |
tree | dd08e02b053b0cf27a75ed2e428701b1799e3bf1 /updater/msirunner_windows.go | |
parent | ui: do tray click action when popup clicked (diff) | |
download | wireguard-windows-568528c747afe3ae991b0340d15cd6a897fd5c9d.tar.xz wireguard-windows-568528c747afe3ae991b0340d15cd6a897fd5c9d.zip |
updater: move into manager
Diffstat (limited to 'updater/msirunner_windows.go')
-rw-r--r-- | updater/msirunner_windows.go | 71 |
1 files changed, 62 insertions, 9 deletions
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 } |