mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-01 20:41:28 +02:00
[client] launch macOS UI via sudo -u -H for full user env (HOME/USER/LOGNAME)
Both launch paths (pkg postinstall and the updater's startUIAsUser) run as root, so launchctl asuser alone moves the launch into the user's GUI domain but leaves root's HOME/USER/LOGNAME. Use sudo -u <user> -H to drop to the console user with their environment, fixing os.UserConfigDir() resolution. Drops the space-fragile dscl/awk home lookup and the duplicate-HOME append; extracts consoleUser() and aligns the skip list across both paths.
This commit is contained in:
@@ -98,39 +98,25 @@ func (u *Installer) startDaemon(daemonFolder string) error {
|
||||
func (u *Installer) startUIAsUser() error {
|
||||
log.Infof("starting netbird-ui: %s", uiBinary)
|
||||
|
||||
// Get the current console user
|
||||
cmd := exec.Command("stat", "-f", "%Su", "/dev/console")
|
||||
output, err := cmd.Output()
|
||||
username, err := consoleUser()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get console user: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
username := strings.TrimSpace(string(output))
|
||||
if username == "" || username == "root" {
|
||||
return fmt.Errorf("no active user session found")
|
||||
}
|
||||
|
||||
log.Infof("starting UI for user: %s", username)
|
||||
|
||||
// Get user's UID
|
||||
userInfo, err := user.Lookup(username)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to lookup user %s: %w", username, err)
|
||||
return fmt.Errorf("lookup user %s: %w", username, err)
|
||||
}
|
||||
|
||||
// Start the UI process as the console user using launchctl
|
||||
// This ensures the app runs in the user's context with proper GUI access
|
||||
launchCmd := exec.Command("launchctl", "asuser", userInfo.Uid, "open", "-a", uiBinary)
|
||||
log.Infof("starting UI for user: %s (uid %s)", username, userInfo.Uid)
|
||||
|
||||
launchCmd := exec.Command("launchctl", "asuser", userInfo.Uid, "sudo", "-u", username, "-H", "open", "-a", uiBinary)
|
||||
log.Infof("launchCmd: %s", launchCmd.String())
|
||||
// Set the user's home directory for proper macOS app behavior
|
||||
launchCmd.Env = append(os.Environ(), "HOME="+userInfo.HomeDir)
|
||||
log.Infof("set HOME environment variable: %s", userInfo.HomeDir)
|
||||
|
||||
if err := launchCmd.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start UI process: %w", err)
|
||||
return fmt.Errorf("start UI process: %w", err)
|
||||
}
|
||||
|
||||
// Release the process so it can run independently
|
||||
if err := launchCmd.Process.Release(); err != nil {
|
||||
log.Warnf("failed to release UI process: %v", err)
|
||||
}
|
||||
@@ -139,6 +125,21 @@ func (u *Installer) startUIAsUser() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func consoleUser() (string, error) {
|
||||
output, err := exec.Command("stat", "-f", "%Su", "/dev/console").Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("get console user: %w", err)
|
||||
}
|
||||
|
||||
username := strings.TrimSpace(string(output))
|
||||
switch username {
|
||||
case "", "root", "loginwindow", "_mbsetupuser":
|
||||
return "", fmt.Errorf("no active GUI user session, console user: %q", username)
|
||||
}
|
||||
|
||||
return username, nil
|
||||
}
|
||||
|
||||
func (u *Installer) installPkgFile(ctx context.Context, path string) error {
|
||||
log.Infof("installing pkg file: %s", path)
|
||||
|
||||
|
||||
@@ -30,10 +30,6 @@ mkdir -p /usr/local/bin/
|
||||
$AGENT service install || true
|
||||
$AGENT service start || true
|
||||
|
||||
# Launch the GUI as the logged-in console user, NOT as the installer's
|
||||
# (root) context. When there is no active GUI session
|
||||
# (unattended MDM install, login window), there is nobody to launch as, skip it;
|
||||
|
||||
console_user=$(stat -f%Su /dev/console 2>/dev/null)
|
||||
case "$console_user" in
|
||||
""|root|loginwindow|_mbsetupuser)
|
||||
@@ -41,13 +37,12 @@ mkdir -p /usr/local/bin/
|
||||
;;
|
||||
*)
|
||||
uid=$(id -u "$console_user" 2>/dev/null)
|
||||
home_dir=$(dscl . -read "/Users/$console_user" NFSHomeDirectory 2>/dev/null | awk '{print $2}')
|
||||
if [ -z "$uid" ] || [ -z "$home_dir" ]; then
|
||||
echo "Could not resolve uid/home for console user '$console_user' (uid='$uid', home='$home_dir'); skipping UI launch."
|
||||
if [ -z "$uid" ]; then
|
||||
echo "Could not resolve uid for console user '$console_user'; skipping UI launch."
|
||||
else
|
||||
echo "Launching NetBird UI as console user $console_user (uid $uid, home $home_dir)."
|
||||
if ! HOME="$home_dir" launchctl asuser "$uid" open "$APP"; then
|
||||
echo "Failed to launch NetBird UI; it will start at next login via the per-user LaunchAgent."
|
||||
echo "Launching NetBird UI as console user $console_user (uid $uid)."
|
||||
if ! launchctl asuser "$uid" sudo -u "$console_user" -H open "$APP"; then
|
||||
echo "Failed to launch NetBird UI; if autostart is enabled it will start at next login."
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
Reference in New Issue
Block a user