mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-19 21:29:09 +02:00
ui: elevate Windows debug-bundle reveal to bypass SystemTemp ACL
The daemon runs as SYSTEM and writes the bundle into C:\Windows\SystemTemp, whose ACL denies the logged-in user, so a plain 'explorer /select' could not open it. The Windows reveal now elevates via ShellExecuteW with the runas verb, falling back to an unelevated reveal of the parent dir on decline.
This commit is contained in:
@@ -5,9 +5,6 @@ package services
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -85,16 +82,7 @@ func (s *Debug) RevealFile(_ context.Context, path string) error {
|
||||
if path == "" {
|
||||
return fmt.Errorf("empty path")
|
||||
}
|
||||
var cmd *exec.Cmd
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
cmd = exec.Command("open", "-R", path)
|
||||
case "windows":
|
||||
cmd = exec.Command("explorer", "/select,"+path)
|
||||
default:
|
||||
cmd = exec.Command("xdg-open", filepath.Dir(path))
|
||||
}
|
||||
return cmd.Start()
|
||||
return revealFile(path)
|
||||
}
|
||||
|
||||
// RegisterUILog reports the GUI log path to the daemon for bundle collection;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//go:build !android && !ios && !freebsd && !js && !windows
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// revealFile opens the OS file manager focused on path.
|
||||
func revealFile(path string) error {
|
||||
var cmd *exec.Cmd
|
||||
if runtime.GOOS == "darwin" {
|
||||
cmd = exec.Command("open", "-R", path)
|
||||
} else {
|
||||
cmd = exec.Command("xdg-open", filepath.Dir(path))
|
||||
}
|
||||
return cmd.Start()
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// SW_SHOWNORMAL for ShellExecuteW's nShowCmd.
|
||||
const swShowNormal = 1
|
||||
|
||||
var (
|
||||
shell32 = windows.NewLazySystemDLL("shell32.dll")
|
||||
procShellExecute = shell32.NewProc("ShellExecuteW")
|
||||
)
|
||||
|
||||
// revealFile opens Explorer focused on path. The debug bundle is written by the
|
||||
// daemon (running as SYSTEM) into C:\Windows\SystemTemp, whose ACL denies the
|
||||
// logged-in user. A plain "explorer /select" can't traverse it, so we elevate
|
||||
// via the ShellExecuteW "runas" verb (UAC prompt) — the elevated Explorer can
|
||||
// read the folder and highlight the file.
|
||||
func revealFile(path string) error {
|
||||
verb, err := windows.UTF16PtrFromString("runas")
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode verb: %w", err)
|
||||
}
|
||||
file, err := windows.UTF16PtrFromString("explorer.exe")
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode file: %w", err)
|
||||
}
|
||||
params, err := windows.UTF16PtrFromString("/select," + path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode params: %w", err)
|
||||
}
|
||||
|
||||
// ShellExecuteW returns an HINSTANCE; a value <=32 is an error code.
|
||||
ret, _, _ := procShellExecute.Call(
|
||||
0,
|
||||
uintptr(unsafe.Pointer(verb)),
|
||||
uintptr(unsafe.Pointer(file)),
|
||||
uintptr(unsafe.Pointer(params)),
|
||||
0,
|
||||
swShowNormal,
|
||||
)
|
||||
if ret <= 32 {
|
||||
// Elevation declined or failed: fall back to an unelevated reveal of the
|
||||
// parent directory so the user at least lands near the bundle.
|
||||
return exec.Command("explorer", filepath.Dir(path)).Start() //nolint:gosec
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user