Keep USB approvals portable and preserve approval prompts
This commit is contained in:
1 parent
60d6b255da
commit
c3cdcb1e82
15 files changed
+535
-52
No files matched your search
@@ -1,5 +1,7 @@
|
||||
echo "Configure USB device authorization"
|
||||
|
||||
install -Dm644 "$OMARCHY_PATH/default/polkit/org.omarchy.usb.policy" /usr/share/polkit-1/actions/org.omarchy.usb.policy
|
||||
|
||||
# A deferred install has only the builder's peripherals attached. The owner
|
||||
# needs working input before there is an account or a session for approvals.
|
||||
if [[ -z ${OMARCHY_INSTALL_USER:-} ]]; then
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# Device identity is portable; the full live rule is still used when granting
|
||||
# access to the connection shown in the approval dialog.
|
||||
usb_authorization_portable_rule() {
|
||||
local rule="$1" token="" char quoted=0 escaped=0 index
|
||||
local -a tokens=() portable=()
|
||||
|
||||
# Split canonical USBGuard output without evaluating device-controlled text.
|
||||
# An attribute name inside a quoted name/serial is never a rule attribute.
|
||||
for (( index=0; index<${#rule}; index++ )); do
|
||||
char=${rule:index:1}
|
||||
if (( escaped )); then
|
||||
token+="$char"
|
||||
escaped=0
|
||||
elif (( quoted )) && [[ $char == '\' ]]; then
|
||||
token+="$char"
|
||||
escaped=1
|
||||
elif [[ $char == '"' ]]; then
|
||||
token+="$char"
|
||||
quoted=$((1 - quoted))
|
||||
elif (( ! quoted )) && [[ $char == " " ]]; then
|
||||
if [[ -n $token ]]; then tokens+=("$token"); token=""; fi
|
||||
else
|
||||
token+="$char"
|
||||
fi
|
||||
done
|
||||
(( ! quoted && ! escaped )) || return 1
|
||||
if [[ -n $token ]]; then tokens+=("$token"); fi
|
||||
[[ ${tokens[0]:-} == "allow" || ${tokens[0]:-} == "block" ]] || return 1
|
||||
portable=(allow)
|
||||
for (( index=1; index<${#tokens[@]}; index++ )); do
|
||||
case "${tokens[index]}" in
|
||||
via-port | parent-hash)
|
||||
(( ++index < ${#tokens[@]} )) || return 1
|
||||
[[ ${tokens[index]} == \"*\" ]] || return 1
|
||||
;;
|
||||
label) return 1 ;;
|
||||
*) portable+=("${tokens[index]}") ;;
|
||||
esac
|
||||
done
|
||||
local IFS=" "
|
||||
printf '%s label "omarchy-usb-authorization-v1"\n' "${portable[*]}"
|
||||
}
|
||||
|
||||
usb_authorization_permanent() {
|
||||
local id="$1" expected="$2" devices current="" allowed portable policy line target new_id matches rule saved=0
|
||||
|
||||
[[ $id =~ ^[0-9]+$ && ( $expected == block\ * || $expected == allow\ * ) ]] || return 1
|
||||
(( ${#expected} <= 16384 )) || return 1
|
||||
devices=$(usbguard list-devices) || return 1
|
||||
while IFS= read -r line; do
|
||||
if [[ $line == "$id: "* ]]; then current=${line#"$id: "}; fi
|
||||
done <<<"$devices"
|
||||
[[ $current == "$expected" ]] || return 1
|
||||
allowed="allow ${expected#* }"
|
||||
portable=$(usb_authorization_portable_rule "$current") || return 1
|
||||
usbguard-rule-parser "$portable" >/dev/null || return 1
|
||||
|
||||
# Respect earlier administrator deny rules. Do not report permanent success
|
||||
# when a saved allow would lose to an explicit block/reject on reconnect.
|
||||
policy=$(usbguard list-rules) || return 1
|
||||
while IFS= read -r line; do
|
||||
if [[ $line =~ ^[0-9]+:[[:space:]](allow|block|reject)([[:space:]]|$) ]]; then
|
||||
target=${BASH_REMATCH[1]}
|
||||
rule=${line#*: }
|
||||
# --show-devices filters by current target, hiding deny rules for a
|
||||
# temporarily allowed device. A match query compares identity instead.
|
||||
matches=$(usbguard list-devices "match${rule#"$target"}") || return 1
|
||||
if grep -Fqx -- "$id: $current" <<<"$matches"; then
|
||||
if [[ $target != "allow" ]]; then
|
||||
echo "An administrator rule blocks this device. Review that rule before saving approval." >&2
|
||||
return 1
|
||||
fi
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done <<<"$policy"
|
||||
while IFS= read -r line; do
|
||||
if [[ $line =~ ^([0-9]+):[[:space:]] && ${line#*: } == "$portable" ]]; then
|
||||
saved=1
|
||||
fi
|
||||
done <<<"$policy"
|
||||
|
||||
# A retry can reuse only an exact owned rule present in both the daemon and
|
||||
# its persistent file. Never remove/reorder rules around manual restrictions.
|
||||
if (( ! saved )) || ! grep -Fqx -- "$portable" /etc/usbguard/rules.conf; then
|
||||
new_id=$(usbguard append-rule "$portable") || return 1
|
||||
[[ $new_id =~ ^[0-9]+$ ]] || return 1
|
||||
grep -Fqx -- "$portable" /etc/usbguard/rules.conf || return 1
|
||||
fi
|
||||
if [[ $current == block\ * ]]; then
|
||||
usbguard allow-device "$expected" || return 1
|
||||
fi
|
||||
devices=$(usbguard list-devices --allowed) || return 1
|
||||
grep -Fqx -- "$1: $allowed" <<<"$devices"
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
source "${BASH_SOURCE[0]%/*}/usb-authorization-policy.sh"
|
||||
|
||||
usb_authorization_config_value() {
|
||||
local config="$1" key="$2"
|
||||
local awk_command=(awk)
|
||||
@@ -54,15 +56,24 @@ usb_authorization_require_secure_settings() {
|
||||
usb_authorization_require_secure_setting "$config" InsertedDevicePolicy apply-policy || return 1
|
||||
usb_authorization_require_secure_setting "$config" AuthorizedDefault none || return 1
|
||||
usb_authorization_require_secure_setting "$config" RestoreControllerDeviceState false || return 1
|
||||
usb_authorization_require_secure_setting "$config" RuleFile /etc/usbguard/rules.conf || return 1
|
||||
}
|
||||
|
||||
usb_authorization_generate_policy() {
|
||||
local policy="$1"
|
||||
local policy="$1" generated line
|
||||
|
||||
if ! usbguard generate-policy >"$policy"; then
|
||||
if ! generated=$(usbguard generate-policy); then
|
||||
echo "USBGuard could not enumerate devices; nothing was enabled." >&2
|
||||
return 1
|
||||
fi
|
||||
: >"$policy"
|
||||
while IFS= read -r line; do
|
||||
if [[ $line == allow\ * ]]; then
|
||||
usb_authorization_portable_rule "$line" >>"$policy" || return 1
|
||||
elif [[ -n $line ]]; then
|
||||
printf '%s\n' "$line" >>"$policy"
|
||||
fi
|
||||
done <<<"$generated"
|
||||
if ! grep -q '^allow ' "$policy"; then
|
||||
if grep -q '^[[:space:]]*[^#[:space:]]' "$policy"; then
|
||||
echo "USBGuard did not generate a usable policy; nothing was enabled." >&2
|
||||
@@ -72,6 +83,7 @@ usb_authorization_generate_policy() {
|
||||
# Keep the file nonempty so re-enabling preserves this default-deny policy.
|
||||
echo '# No USB devices were present during enrollment.' >>"$policy"
|
||||
fi
|
||||
usbguard-rule-parser -f "$policy" >/dev/null
|
||||
}
|
||||
|
||||
usb_authorization_add_user() {
|
||||
@@ -113,16 +125,16 @@ usb_authorization_provision_owner() {
|
||||
}
|
||||
|
||||
usb_authorization_trust_present_devices() {
|
||||
local line id
|
||||
local line id devices
|
||||
local count=0
|
||||
local -a devices
|
||||
devices=$(usbguard list-devices) || return 1
|
||||
local -a inventory
|
||||
mapfile -t inventory <<<"$devices"
|
||||
|
||||
mapfile -t devices < <(usbguard list-devices)
|
||||
|
||||
for line in "${devices[@]}"; do
|
||||
for line in "${inventory[@]}"; do
|
||||
if [[ $line =~ ^([0-9]+):[[:space:]] ]]; then
|
||||
id="${BASH_REMATCH[1]}"
|
||||
usbguard allow-device --permanent "$id"
|
||||
sudo /usr/bin/omarchy-usb-authorization-approve "$id" "${line#*: }" || return 1
|
||||
(( ++count ))
|
||||
fi
|
||||
done
|
||||
|
||||
Reference in new issue
Block a user