Files
fips/packaging/macos/uninstall.sh
ArjenandJohnathan Corgan d208a9db81 feat(ble): lend the radio to the macOS daemon from a login-session agent
macOS never grants Bluetooth to a root launchd daemon: CoreBluetooth
answers it Unauthorized whatever the privacy settings say, so the
packaged daemon could not use the CoreBluetooth backend at all.

When CoreBluetooth refuses the daemon, it listens on ble-agent.sock
beside the control socket (/var/run/fips, group fips), and a per-user
LaunchAgent runs `fips-ble-agent --ble-agent` in the login session,
lending its radio to the daemon over a small framed protocol
(io_macos/agent*.rs). Each agent connection that says a valid hello is
installed as the radio, replacing the previous one, so the transport is
unchanged; a lost agent is a radio switched off. A connection has five
seconds to say hello. The agent re-resolves the socket path on every
reconnect, so one started before the daemon created its runtime
directory does not settle on a fallback path.

The agent connects only once its radio is up, and its hello carries the
PSM CoreBluetooth published, read afresh for every connection. Before the
radio is up `listen` reports only the requested fallback, so a hello sent
then told the daemon PSM 133 while the listener was on another, and kept
telling it so across reconnects and Bluetooth toggles.

fips-ble-agent is a hard link to fips, so Activity Monitor tells the two
processes apart. The agent logs to ~/Library/Logs/fips/ble-agent.log,
rolled like the daemon's log, rather than to a shared path in /tmp
another account could plant a file or symlink in. Install, upgrade and
uninstall stop and start the agent in every GUI session, so none keeps
running a replaced binary. The agent ends on the stop signal the process holds from
the start, so a bootout does not wait out launchd's timeout.

The daemon/agent pair is tested end to end over a real Unix socket and
MockBleIo on every host: listener PSM, advertising, adverts, dialled and
inbound channels both ways, refusal, a lost agent, a connection that
never says hello, and an agent whose radio comes up after it starts.
2026-10-13 20:56:07 +00:00

53 lines
1.4 KiB
Bash
Executable File

#!/bin/sh
# FIPS uninstall script for macOS
#
# Run with: sudo ./uninstall.sh
set -e
PLIST="/Library/LaunchDaemons/com.fips.daemon.plist"
# Require root
if [ "$(id -u)" -ne 0 ]; then
echo "Error: must run as root (sudo $0)" >&2
exit 1
fi
echo "Uninstalling FIPS..."
# Stop and unload the service
if launchctl list com.fips.daemon >/dev/null 2>&1; then
launchctl unload "$PLIST" 2>/dev/null || true
echo " Service stopped"
fi
# Remove launchd plist
rm -f "$PLIST"
echo " Removed $PLIST"
# Stop the BLE agent in every GUI session and remove it
AGENT="/Library/LaunchAgents/com.fips.ble-agent.plist"
for AGENT_USER in $(who | awk '$2 == "console" { print $1 }' | sort -u); do
[ "$AGENT_USER" = "root" ] && continue
AGENT_UID="$(id -u "$AGENT_USER" 2>/dev/null)" || continue
launchctl bootout "gui/$AGENT_UID/com.fips.ble-agent" 2>/dev/null || true
done
rm -f "$AGENT"
echo " Removed $AGENT"
# Remove DNS resolver
rm -f /etc/resolver/fips
dscacheutil -flushcache
killall -HUP mDNSResponder 2>/dev/null || true
echo " Removed /etc/resolver/fips"
# Remove binaries
for bin in fips fips-ble-agent fipsctl fipstop; do
rm -f "/usr/local/bin/$bin"
done
echo " Removed binaries from /usr/local/bin/"
echo ""
echo "FIPS uninstalled."
echo "Config preserved at /usr/local/etc/fips/ (remove manually if desired)"
echo "Logs preserved at /usr/local/var/log/fips/ (remove manually if desired)"