130 lines
2.8 KiB
Go
130 lines
2.8 KiB
Go
//go:build windows
|
|
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
var (
|
|
shell32 = syscall.NewLazyDLL("shell32.dll")
|
|
shellExecuteExW = shell32.NewProc("ShellExecuteExW")
|
|
)
|
|
|
|
const (
|
|
seeMaskNocloseprocess = 0x00000040
|
|
)
|
|
|
|
type shellExecuteInfo struct {
|
|
cbSize uint32
|
|
fMask uint32
|
|
hwnd uintptr
|
|
lpVerb *uint16
|
|
lpFile *uint16
|
|
lpParameters *uint16
|
|
lpDirectory *uint16
|
|
nShow int32
|
|
hInstApp uintptr
|
|
lpIDList uintptr
|
|
lpClass *uint16
|
|
hkeyClass uintptr
|
|
dwHotKey uint32
|
|
hIcon uintptr
|
|
hProcess uintptr
|
|
}
|
|
|
|
func getInstallDir() (string, error) {
|
|
programFiles := os.Getenv("ProgramFiles")
|
|
|
|
if programFiles == "" {
|
|
return "", errors.New("ProgramFiles ist nicht gesetzt")
|
|
}
|
|
|
|
return filepath.Join(programFiles, "logofclient"), nil
|
|
}
|
|
|
|
func platformRunPrivileged(config Config, action string) error {
|
|
if isWindowsAdmin() {
|
|
return runAction(config, action)
|
|
}
|
|
|
|
return runElevated(action)
|
|
}
|
|
|
|
func isWindowsAdmin() bool {
|
|
// Ein einfacher und robuster Test:
|
|
// Versuch, in das Windows-Systemverzeichnis zu schreiben.
|
|
//
|
|
// Da wir dort natürlich nichts verändern wollen, verwenden wir
|
|
// stattdessen "net session". Der Befehl funktioniert nur mit
|
|
// Administratorrechten.
|
|
|
|
cmd := exec.Command("net", "session")
|
|
cmd.Stdout = nil
|
|
cmd.Stderr = nil
|
|
|
|
return cmd.Run() == nil
|
|
}
|
|
|
|
func runElevated(action string) error {
|
|
exe, err := os.Executable()
|
|
if err != nil {
|
|
return fmt.Errorf("Pfad des Installers konnte nicht ermittelt werden: %w", err)
|
|
}
|
|
|
|
verb, err := syscall.UTF16PtrFromString("runas")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
file, err := syscall.UTF16PtrFromString(exe)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
parameters, err := syscall.UTF16PtrFromString(action)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
info := shellExecuteInfo{
|
|
cbSize: uint32(unsafe.Sizeof(shellExecuteInfo{})),
|
|
fMask: seeMaskNocloseprocess,
|
|
lpVerb: verb,
|
|
lpFile: file,
|
|
lpParameters: parameters,
|
|
nShow: 1, // SW_SHOWNORMAL
|
|
}
|
|
|
|
ret, _, callErr := shellExecuteExW.Call(uintptr(unsafe.Pointer(&info)))
|
|
|
|
if ret == 0 {
|
|
// ERROR_CANCELLED = 1223:
|
|
// Benutzer hat den UAC-Dialog abgebrochen.
|
|
if errno, ok := callErr.(syscall.Errno); ok && errno == 1223 {
|
|
fmt.Println("Administratorrechte wurden nicht erteilt.")
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("Administratorrechte konnten nicht angefordert werden: %w", callErr)
|
|
}
|
|
|
|
// Auf die erhöhte Instanz warten.
|
|
if info.hProcess != 0 {
|
|
handle := syscall.Handle(info.hProcess)
|
|
defer syscall.CloseHandle(handle)
|
|
|
|
_, err := syscall.WaitForSingleObject(handle, syscall.INFINITE)
|
|
if err != nil {
|
|
return fmt.Errorf("auf erhöhte Instanz konnte nicht gewartet werden: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
} |