1. Component purpose
This file is a core component of the BastionGuard Wizard: it implements the post-install setup logic that requires administrative privileges (root) and must run reliably across multiple Linux distributions.
In practice, this module is responsible for:
- executing privileged steps (DNS override, firewall rules, certificates, etc.) with a single authentication prompt (pkexec/sudo);
- handling Polkit compatibility (legacy and new syntax);
- capturing output and exit codes for diagnostics;
- providing multiple fallbacks for DNS configuration (resolvectl, nmcli, direct file write);
- opening the required firewall ports (firewalld/ufw/nftables/iptables);
- generating and installing a local CA plus certificates for the “local warning server”;
- installing the phishing blacklist and the Native Messaging Host integration.
2. High-level architecture
The design revolves around two guiding principles:
- Privileged batching: instead of triggering many Polkit prompts, the wizard builds a temporary script and executes it as root only once.
- Best-effort multi-backend support: it detects what tools are available on the system and applies the most appropriate configuration, with safe fallbacks.
The code is organized into:
namespace { ... }for internal helpers (not exported)namespace BastionGuard::wizardfor the public API used by the Wizard UI
3. Privileged execution strategy
3.1 run_cmd_capture
run_cmd_capture(cmd, out, exit_code):
- executes a command via
popen()and captures stdout; - normalizes the exit status using
WIFEXITED/WEXITSTATUSandWIFSIGNALED; - returns
trueonly when the exit code is 0.
3.2 elev_cmd
elev_cmd(inner, action_id) builds an elevated command line using:
pkexec --disable-internal-agent --action-id ...when supported (legacy Polkit);pkexec ...when--action-idis not supported (Polkit 124+ behavior);sudo ...as a fallback when pkexec is unavailable.
This preserves compatibility across distributions and Polkit versions, while keeping behavior consistent.
3.3 write_temp_script_and_elevate
This helper:
- creates a secure temporary file in
/tmpusingmkstemp(); - writes the script contents, marks it executable, and runs it elevated (pkexec/sudo);
- captures output, prints a detailed debug block (command, exit code, output);
- removes the temporary file on completion.
This is primarily used for one-off privileged operations where batching is not yet aggregated.
4. Combined privileged execution (single authentication)
4.1 run_all_elevated_steps
run_all_elevated_steps(commands, out_log) is the preferred mechanism for wizard execution. It:
- writes a single
bashscript withset -euo pipefail; - adds each command line as provided (commands must already be safe/sanitized);
- executes the script using pkexec/sudo, prompting the user only once;
- returns success only when the script completes with exit code 0.
This approach ensures the wizard remains user-friendly (one authentication prompt) and reduces partial-failure states.
5. DNS override (resolver setup)
The module supports multiple strategies, applied in order:
- systemd-resolved / resolvectl:
- detects
resolvectlor an activesystemd-resolvedservice; - tries to identify the active link (via
ip route get 1.1.1.1); - sets DNS to
127.0.0.1on the selected link.
- detects
- NetworkManager / nmcli:
- detects
nmcli; - finds the active connection;
- sets
ipv4.dnsto127.0.0.1and enablesipv4.ignore-auto-dns.
- detects
- Direct file override:
- writes
/etc/resolv.confwith a BastionGuard override (nameserver 127.0.0.1); - keeps a backup at
/etc/resolv.conf.BastionGuard.bak.
- writes
This guarantees that DNS can be forced locally even on minimal systems without systemd-resolved or NetworkManager.
6. Firewall port setup
The wizard must ensure the required ports are reachable. It attempts multiple backends:
- firewalld:
firewall-cmd --permanent --add-port=...+ reload - ufw:
ufw allow ... - nftables: creates a dedicated table/chain and adds accept rules
- iptables: inserts INPUT accept rules (best-effort)
It also attempts to:
- load
nf_nat(best-effort) and persist it via/etc/modules-load.d/BastionGuard.conf; - add the effective user to groups such as
admandsystemd-journalso the UI can read logs; - restart
BastionGuard-phishing-scanner.serviceif the unit exists.
7. Certificates and local CA
The wizard can generate:
- a BastionGuard local CA (
BastionGuard-ca.key.pem+BastionGuard-ca.crt.pem); - a server key/certificate for the warning server (
local-warning.key.pem+local-warning.crt.pem), including SAN:DNS:localhostandIP:127.0.0.2.
Then it attempts to install the CA into the system trust store using distribution-specific tools:
update-ca-certificates(Debian/Ubuntu/Gentoo)trust anchor/ p11-kit (Fedora/openSUSE and others)update-ca-trust(RHEL/CentOS variants)- Arch-style anchors path + trust extract compatibility
If none succeed, it still copies the CA into common directories and reports a warning.
8. Native Messaging Host installation
The wizard generates JSON manifests for Chromium-based browsers and Firefox-based browsers, writing them into:
- user-level XDG config locations (Chrome/Chromium/Brave/Edge)
- user-level Firefox locations (Firefox, LibreWolf)
- system-wide locations when possible (best-effort)
This enables the BastionGuard browser extension to communicate with the native host binary.
9. Orchestration entry point
run_wizard_setup(options) is the main orchestrator:
- if
optionsis empty, it runs the full setup; - otherwise it runs only the requested steps (e.g.,
resolv,firewall,certs,blacklist,native-host); - builds a single privileged script (
cmds) and executes it once viarun_all_elevated_steps.
This structure gives the Wizard UI the ability to re-run single steps, or perform a full guided setup.