Merge branch 'main' into embedded-vnc

This commit is contained in:
Viktor Liu
2026-09-02 19:10:03 +02:00
153 changed files with 9089 additions and 1934 deletions
+52 -9
View File
@@ -36,7 +36,9 @@
# IDEMPOTENCY: re-running with the same values is a no-op from the
# daemon's point of view (the 1-minute reload ticker diff returns empty).
#
# SECURITY: PreSharedKey is redacted in this script's log output.
# SECURITY: PreSharedKey (and any secret-bearing debugBundleUploadURL) is
# redacted in this script's log output, and the installed plist is 0600
# root:wheel so its values are not readable by local non-root users.
set -euo pipefail
@@ -56,6 +58,8 @@ NULL='__UNSET__'
managementURL='https://api.netbird.io:443'
preSharedKey="$NULL" # secret; redacted in log
allowServerSSH='true'
allowRemoteJobs="$NULL"
debugBundleUploadURL="$NULL" # HTTPS URL with a host; overrides management
allowServerVNC="$NULL"
disableVNCApproval="$NULL"
blockInbound="$NULL"
@@ -109,21 +113,35 @@ end_plist() {
EOF
}
# emit_string appends a plist `<key>`/`<string>` entry for the given key and value to "$PLIST_PATH.tmp", XML-escaping `&`, `<`, and `>`, and logs the assignment (masking the logged value as `********** (secret)` when the key is `preSharedKey`).
# emit_string appends a plist `<key>`/`<string>` entry for the given key and value to "$PLIST_PATH.tmp", XML-escaping `&`, `<`, and `>`, and logs the assignment (masking the logged value as `********** (secret)` for secret keys — `preSharedKey` and `debugBundleUploadURL`, which can embed credentials or a signed query token).
emit_string() {
local key="$1" value="$2" log_value="$2"
# Escape XML entities in the value
local escaped
escaped="$(printf '%s' "$value" | sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g' -e 's/>/\&gt;/g')"
printf ' <key>%s</key>\n <string>%s</string>\n' "$key" "$escaped" >> "$PLIST_PATH.tmp"
if [[ "$key" == "preSharedKey" ]]; then
log_value='********** (secret)'
fi
case "$key" in
preSharedKey|debugBundleUploadURL) log_value='********** (secret)' ;;
*) ;;
esac
log "set $key = $log_value"
}
# emit_bool writes a boolean plist entry for a given key into the temporary plist file.
# emit_bool writes a boolean plist entry for a key when the provided value matches an accepted boolean token; logs an error and skips the key on invalid input.
# is_bool returns success if the value is an accepted boolean token.
is_bool() {
local value="$1"
case "$value" in
true|True|TRUE|1|yes|false|False|FALSE|0|no) return 0 ;;
*) return 1 ;;
esac
}
# emit_bool writes a boolean plist entry for a key when the provided value matches
# an accepted boolean token; logs an error and skips the key on invalid input.
# It returns success even on invalid input (like emit_int) so a single typo in one
# boolean does not abort the whole policy push under `set -euo pipefail`. Callers
# that must fail closed on an invalid value (e.g. allowRemoteJobs) validate with
# is_bool before calling and substitute a safe default themselves.
emit_bool() {
local key="$1" value="$2"
local xml_bool
@@ -147,15 +165,35 @@ emit_int() {
log "set $key = $value"
}
# main builds the NetBird MDM plist from configured policy variables, validates and installs it to /Library/Managed Preferences/io.netbird.client.plist (root:wheel, 644) and optionally triggers the NetBird daemon to reload.
# main builds the NetBird MDM plist from configured policy variables, validates and installs it to /Library/Managed Preferences/io.netbird.client.plist (root:wheel, 600 — the daemon reads it directly as root, so it need not be world-readable) and optionally triggers the NetBird daemon to reload.
main() {
log "applying NetBird MDM policy to $PLIST_PATH"
# Restrict the temp plist while it is being built: it carries the same
# secret-bearing values as the final file, which is installed 0600 below.
umask 077
/bin/mkdir -p "$PLIST_DIR"
start_plist
# Force 0600 on the temp file explicitly: start_plist writes it with a
# truncating redirect, which keeps an existing file's mode, so a leftover
# 0644 tmp from an interrupted run would not be tightened by umask alone.
# start_plist only wrote the header so far — the secret-bearing values are
# appended after this point.
/bin/chmod 600 "$PLIST_PATH.tmp"
is_set "$managementURL" && emit_string managementURL "$managementURL"
is_set "$preSharedKey" && emit_string preSharedKey "$preSharedKey"
is_set "$allowServerSSH" && emit_bool allowServerSSH "$allowServerSSH"
# Fail closed: an invalid allowRemoteJobs value must not drop the key and
# leave a conflicting local opt-in active — enforce the safe default (false).
if is_set "$allowRemoteJobs"; then
if is_bool "$allowRemoteJobs"; then
emit_bool allowRemoteJobs "$allowRemoteJobs"
else
log "invalid boolean for allowRemoteJobs: $allowRemoteJobs; enforcing safe default (false)"
emit_bool allowRemoteJobs false
fi
fi
is_set "$debugBundleUploadURL" && emit_string debugBundleUploadURL "$debugBundleUploadURL"
is_set "$allowServerVNC" && emit_bool allowServerVNC "$allowServerVNC"
is_set "$disableVNCApproval" && emit_bool disableVNCApproval "$disableVNCApproval"
is_set "$blockInbound" && emit_bool blockInbound "$blockInbound"
@@ -185,7 +223,12 @@ main() {
/bin/mv -f "$PLIST_PATH.tmp" "$PLIST_PATH"
/usr/sbin/chown root:wheel "$PLIST_PATH"
/bin/chmod 644 "$PLIST_PATH"
# 0600, not 0644: the daemon's loader (client/mdm/policy_darwin.go) opens the
# plist directly as root, so it does not need to be world-readable. Restricting
# it keeps secret-bearing values (preSharedKey, a signed debugBundleUploadURL)
# from any local non-root user. The loader's only mode check refuses a
# world-writable file, which 0600 satisfies.
/bin/chmod 600 "$PLIST_PATH"
log "policy installed; NetBird daemon will pick it up within the next 1-minute reload tick"