//go:build windows package main import ( "errors" "fmt" "os" "path/filepath" "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") ) const ( tokenQuery = 0x0008 tokenElevationClass = 20 errorCancelled = 1223 swShow = 1 ) 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 platformEnsureElevated() error { // Die erhöhte Instanz wurde bereits gestartet. // Sie darf sich nicht noch einmal selbst per runas starten. if hasElevatedFlag() { return nil } if isWindowsElevated() { return nil } return restartElevated() } func hasElevatedFlag() bool { for _, arg := range os.Args[1:] { if arg == "--elevated" { return true } } return false } func restartElevated() 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 } // Die erhöhte Instanz bekommt nur das interne Flag. parameters, err := syscall.UTF16PtrFromString("--elevated") if err != nil { return err } info := shellExecuteInfo{ cbSize: uint32(unsafe.Sizeof(shellExecuteInfo{})), 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 errors.New("Administratorrechte erforderlich") } return fmt.Errorf( "Administratorrechte konnten nicht angefordert werden: %w", callErr, ) } // WICHTIG: // Die ursprüngliche Instanz beendet sich sofort. // Nur die erhöhte Instanz führt danach main() weiter aus. os.Exit(0) return nil } func isWindowsElevated() bool { var token uintptr // GetCurrentProcess() = -1 ret, _, _ := openProcessToken.Call( uintptr(^uint(0)), 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 platformRunPrivileged(config Config, action string) error { // Die komplette Windows-Anwendung läuft bereits erhöht. return runAction(config, action) } func getInstallDir() (string, error) { programFiles := os.Getenv("ProgramFiles") if programFiles == "" { return "", errors.New("ProgramFiles ist nicht gesetzt") } return filepath.Join(programFiles, "logofclient"), nil }