Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 49 additions & 9 deletions SupportHelper/pkgbuild/scripts/postinstall
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,56 @@ launch_daemon="nl.root3.support.helper"
# CLI location
cli_location="/usr/local/bin/SupportHelper"

# Create the LaunchAgent
defaults write "/Library/LaunchDaemons/${launch_daemon}.plist" Label -string "${launch_daemon}"
defaults write "/Library/LaunchDaemons/${launch_daemon}.plist" ProgramArguments -array -string "${cli_location}"
# Keep the process alive
defaults write "/Library/LaunchDaemons/${launch_daemon}.plist" KeepAlive -boolean yes
# Run at every reboot
defaults write "/Library/LaunchDaemons/${launch_daemon}.plist" RunAtLoad -boolean yes
# Developer Team Identifier used for the SpawnConstraint
team_identifier="98LJ4XBGYK"

# Path to PlistBuddy
plistbuddy="/usr/libexec/PlistBuddy"

# Path to the LaunchDaemon property list
launch_daemon_plist="/Library/LaunchDaemons/${launch_daemon}.plist"

# Load Requirements
autoload is-at-least

# macOS Version
os_version=$(sw_vers -productVersion)

# Remove any existing LaunchDaemon plist to avoid stale keys and extended
# attributes. Note: the plist is created with PlistBuddy instead of
# "defaults write", as defaults hands the write to cfprefsd which adds the
# com.apple.quarantine extended attribute to every file it creates. launchd
# refuses to load quarantined property list files on macOS 27 and higher.
rm -f "${launch_daemon_plist}"

# Create the LaunchDaemon
# - KeepAlive keeps the process alive
# - RunAtLoad runs at every reboot
"${plistbuddy}" \
-c "Add :Label string ${launch_daemon}" \
-c "Add :ProgramArguments array" \
-c "Add :ProgramArguments:0 string ${cli_location}" \
-c "Add :KeepAlive bool true" \
-c "Add :RunAtLoad bool true" \
"${launch_daemon_plist}" > /dev/null

# Add a SpawnConstraint on macOS 14 and higher so launchd only spawns this
# service when the binary is signed by Root3 with the expected signing
# identifier
if is-at-least 14.0 ${os_version}; then
"${plistbuddy}" \
-c "Add :SpawnConstraint dict" \
-c "Add :SpawnConstraint:team-identifier string ${team_identifier}" \
-c "Add :SpawnConstraint:signing-identifier string nl.root3.support.helper" \
"${launch_daemon_plist}" > /dev/null
fi

# Just to be sure, remove the quarantine extended attribute if present
xattr -d com.apple.quarantine "${launch_daemon_plist}" &> /dev/null

# Set permissions
chown root:wheel "/Library/LaunchDaemons/${launch_daemon}.plist"
chmod 644 "/Library/LaunchDaemons/${launch_daemon}.plist"
chown root:wheel "${launch_daemon_plist}"
chmod 644 "${launch_daemon_plist}"

# Unload the LaunchDaemon
launchctl bootout system "/Library/LaunchDaemons/${launch_daemon}.plist" &> /dev/null
Expand Down
60 changes: 48 additions & 12 deletions pkgbuild/scripts/postinstall
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ launch_agent="nl.root3.support"
# LaunchDaemon label
launch_daemon="nl.root3.support.helper"

# Developer Team Identifier used for the SpawnConstraint
team_identifier="98LJ4XBGYK"

# Path to PlistBuddy
plistbuddy="/usr/libexec/PlistBuddy"

# Install location
install_location="/Applications/Support.app"

Expand All @@ -47,19 +53,49 @@ fi

# ------------------ LaunchAgent ------------------

# Add AssociatedBundleIdentifiers to show app name in Login Items on
# macOS 13 and higher instead of developer name
defaults write "/Library/LaunchAgents/${launch_agent}.plist" AssociatedBundleIdentifiers -array -string "nl.root3.support"
# Set the Label and ProgramArguments
defaults write "/Library/LaunchAgents/${launch_agent}.plist" Label -string "${launch_agent}"
defaults write "/Library/LaunchAgents/${launch_agent}.plist" ProgramArguments -array -string "/Applications/Support.app/Contents/MacOS/Support"
# Run every reboot
defaults write "/Library/LaunchAgents/${launch_agent}.plist" KeepAlive -boolean yes
# Set ProcessType to Interactive
defaults write "/Library/LaunchAgents/${launch_agent}.plist" ProcessType -string "Interactive"
# Path to the LaunchAgent property list
launch_agent_plist="/Library/LaunchAgents/${launch_agent}.plist"

# Remove any existing LaunchAgent plist to avoid stale keys and extended
# attributes. Note: the plist is created with PlistBuddy instead of
# "defaults write", as defaults hands the write to cfprefsd which adds the
# com.apple.quarantine extended attribute to every file it creates. launchd
# refuses to load quarantined property list files on macOS 27 and higher.
rm -f "${launch_agent_plist}"

# Create the LaunchAgent
# - AssociatedBundleIdentifiers shows the app name in Login Items on
# macOS 13 and higher instead of the developer name
# - KeepAlive runs the app at every reboot and relaunches it when quit
# - ProcessType Interactive gives the app UI process priority
"${plistbuddy}" \
-c "Add :Label string ${launch_agent}" \
-c "Add :ProgramArguments array" \
-c "Add :ProgramArguments:0 string ${install_location}/Contents/MacOS/Support" \
-c "Add :KeepAlive bool true" \
-c "Add :ProcessType string Interactive" \
-c "Add :AssociatedBundleIdentifiers array" \
-c "Add :AssociatedBundleIdentifiers:0 string nl.root3.support" \
"${launch_agent_plist}" > /dev/null

# Add a SpawnConstraint on macOS 14 and higher so launchd only spawns this
# service when the binary is signed by Root3 with the expected signing
# identifier. This prevents an orphaned plist from launching a malicious
# binary placed at the same path.
if is-at-least 14.0 ${os_version}; then
"${plistbuddy}" \
-c "Add :SpawnConstraint dict" \
-c "Add :SpawnConstraint:team-identifier string ${team_identifier}" \
-c "Add :SpawnConstraint:signing-identifier string nl.root3.support" \
"${launch_agent_plist}" > /dev/null
fi

# Just to be sure, remove the quarantine extended attribute if present
xattr -d com.apple.quarantine "${launch_agent_plist}" &> /dev/null

# Set permissions
chown root:wheel "/Library/LaunchAgents/${launch_agent}.plist"
chmod 644 "/Library/LaunchAgents/${launch_agent}.plist"
chown root:wheel "${launch_agent_plist}"
chmod 644 "${launch_agent_plist}"

# Reload the LaunchAgent
if [[ -n "${username}" ]]; then
Expand Down
62 changes: 52 additions & 10 deletions src/Support/Scripts/install_privileged_helper_tool.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ launch_daemon="nl.root3.support.helper"
# Install location
install_location="/Applications/Support.app"

# Developer Team Identifier used for the SpawnConstraint
team_identifier="98LJ4XBGYK"

# Path to PlistBuddy
plistbuddy="/usr/libexec/PlistBuddy"

# Load Requirements
autoload is-at-least

# macOS Version
os_version=$(sw_vers -productVersion)

# ------------------ PrivilegedHelperTool ------------------

# Create "/Library/PrivilegedHelperTools/" if not present
Expand All @@ -40,17 +52,47 @@ chmod 544 "${privileged_helper_tool}"

# ------------------ LaunchDaemon PrivilegedHelperTool ------------------

# Add AssociatedBundleIdentifiers to show app name in Login Items on
# macOS 13 and higher instead of developer name
defaults write "/Library/LaunchDaemons/${launch_daemon}.plist" AssociatedBundleIdentifiers -array -string "nl.root3.support"
# Set the Label and ProgramArguments
defaults write "/Library/LaunchDaemons/${launch_daemon}.plist" Label -string "${launch_daemon}"
defaults write "/Library/LaunchDaemons/${launch_daemon}.plist" ProgramArguments -array -string "${privileged_helper_tool}"
# Set MachServices
defaults write "/Library/LaunchDaemons/${launch_daemon}.plist" MachServices -dict -string "nl.root3.support.helper" -bool true
# Path to the LaunchDaemon property list
launch_daemon_plist="/Library/LaunchDaemons/${launch_daemon}.plist"

# Remove any existing LaunchDaemon plist to avoid stale keys and extended
# attributes. Note: the plist is created with PlistBuddy instead of
# "defaults write", as defaults hands the write to cfprefsd which adds the
# com.apple.quarantine extended attribute to every file it creates. launchd
# refuses to load quarantined property list files on macOS 27 and higher.
rm -f "${launch_daemon_plist}"

# Create the LaunchDaemon
# - AssociatedBundleIdentifiers shows the app name in Login Items on
# macOS 13 and higher instead of the developer name
"${plistbuddy}" \
-c "Add :Label string ${launch_daemon}" \
-c "Add :ProgramArguments array" \
-c "Add :ProgramArguments:0 string ${privileged_helper_tool}" \
-c "Add :MachServices dict" \
-c "Add :MachServices:nl.root3.support.helper bool true" \
-c "Add :AssociatedBundleIdentifiers array" \
-c "Add :AssociatedBundleIdentifiers:0 string nl.root3.support" \
"${launch_daemon_plist}" > /dev/null

# Add a SpawnConstraint on macOS 14 and higher so launchd only spawns this
# service when the binary is signed by Root3 with the expected signing
# identifier. This prevents an orphaned plist from launching a malicious
# binary placed at the same path.
if is-at-least 14.0 ${os_version}; then
"${plistbuddy}" \
-c "Add :SpawnConstraint dict" \
-c "Add :SpawnConstraint:team-identifier string ${team_identifier}" \
-c "Add :SpawnConstraint:signing-identifier string nl.root3.support.helper" \
"${launch_daemon_plist}" > /dev/null
fi

# Just to be sure, remove the quarantine extended attribute if present
xattr -d com.apple.quarantine "${launch_daemon_plist}" &> /dev/null

# Set permissions
chown root:wheel "/Library/LaunchDaemons/${launch_daemon}.plist"
chmod 644 "/Library/LaunchDaemons/${launch_daemon}.plist"
chown root:wheel "${launch_daemon_plist}"
chmod 644 "${launch_daemon_plist}"

# Unload the LaunchDaemon
if launchctl print "system/${launch_daemon}" &> /dev/null ; then
Expand Down
Loading