//go:build windows package main import ( "errors" "fmt" "os" "path/filepath" "strings" "syscall" "unsafe" ) var ( shell32 = syscall.NewLazyDLL("shell32.dll") shellExecuteExW = shell32.NewProc("ShellExecuteExW") advapi32 = syscall.NewLazyDLL("advapi32.dll") openProcessToken = advapi32.NewProc("OpenProcessToken") getTokenInformation = advapi32.NewProc("GetTokenInformation") kernel32 = syscall.NewLazyDLL("kernel32.dll") closeHandle = kernel32.NewProc("CloseHandle") waitForSingleObject = kernel32.NewProc("WaitForSingleObject") ) const ( tokenQuery = 0x0008 tokenElevationClass = 20 seeMaskNoCloseProcess = 0x00000040 swShow = 1 infinite = 0xFFFFFFFF errorCancelled = 1223 ) 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 } type tokenElevationData struct { TokenIsElevated uint32 } 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 isWindowsElevated() { return runAction(config, action) } fmt.Println() fmt.Println("Für diese Aktion werden Administratorrechte benötigt.") fmt.Print("Jetzt Administratorrechte anfordern? [J/n]: ") var answer string if _, err := fmt.Scanln(&answer); err != nil { // Enter ohne Eingabe = Ja answer = "" } answer = strings.ToLower(strings.TrimSpace(answer)) if answer != "" && answer != "j" && answer != "ja" { fmt.Println("Abgebrochen.") return nil } return runElevated(action) } func isWindowsElevated() bool { var token uintptr ret, _, _ := openProcessToken.Call( uintptr(^uint(0)>>1), tokenQuery, uintptr(unsafe.Pointer(&token)), ) if ret == 0 || token == 0 { return false } defer closeHandle.Call(token) var elevation tokenElevationData var returned uint32 ret, _, _ = getTokenInformation.Call( token, tokenElevationClass, uintptr(unsafe.Pointer(&elevation)), uintptr(unsafe.Sizeof(elevation)), uintptr(unsafe.Pointer(&returned)), ) if ret == 0 { return false } return elevation.TokenIsElevated != 0 } 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: swShow, } ret, _, callErr := shellExecuteExW.Call( uintptr(unsafe.Pointer(&info)), ) if ret == 0 { if errno, ok := callErr.(syscall.Errno); ok && errno == errorCancelled { fmt.Println("Administratorrechte wurden nicht erteilt.") return nil } return fmt.Errorf( "Administratorrechte konnten nicht angefordert werden: %w", callErr, ) } if info.hProcess != 0 { handle := syscall.Handle(info.hProcess) defer syscall.CloseHandle(handle) ret, _, err := waitForSingleObject.Call( uintptr(handle), infinite, ) if ret == 0xFFFFFFFF { return fmt.Errorf( "auf erhöhte Instanz konnte nicht gewartet werden: %w", err, ) } } return nil }