Bound sudo policy natively and guard expiry package transactions
This commit is contained in:
1 parent
4ae25cd4d2
commit
a6385e60b8
4 files changed
+106
-20
No files matched your search
@@ -28,6 +28,7 @@ readonly STATE_DIR=/var/lib/omarchy/sudo-passwordless
|
||||
readonly RUNTIME_DIR=/run/omarchy/sudo-passwordless
|
||||
readonly LOCK_FILE=/run/lock/omarchy-sudo-passwordless.lock
|
||||
readonly BOOT_CLEANUP_FILE=/etc/tmpfiles.d/omarchy-nopasswd-sudo.conf
|
||||
readonly PACKAGE_HOOK=/usr/share/libalpm/hooks/05-omarchy-passwordless-revoke.hook
|
||||
readonly REMOVAL_BLOCKER=/run/omarchy-sudo-passwordless-package-removing
|
||||
readonly INSTALLED_SELF=/usr/bin/omarchy-sudo-passwordless
|
||||
readonly STATUS_INACTIVE=3
|
||||
@@ -182,7 +183,11 @@ classify_generated_rule() {
|
||||
|
||||
if [[ $suffix =~ ^[0-9]+$ ]]; then
|
||||
name=${contents%' ALL=(ALL) NOPASSWD: ALL'}
|
||||
valid_account_name "$name" && [[ $contents == "$name ALL=(ALL) NOPASSWD: ALL" ]]
|
||||
if valid_account_name "$name" && [[ $contents == "$name ALL=(ALL) NOPASSWD: ALL" ]]; then
|
||||
return 0
|
||||
fi
|
||||
name=${contents%%' ALL=(ALL) NOTAFTER='*}
|
||||
valid_account_name "$name" && [[ $contents =~ ^[a-z_][a-z0-9_-]*\$?\ ALL=\(ALL\)\ NOTAFTER=[0-9]{14}Z\ NOPASSWD:\ ALL$ ]]
|
||||
elif valid_account_name "$suffix" && [[ $contents == "$suffix ALL=(ALL) NOPASSWD: ALL" ]]; then
|
||||
GENERATED_RULE_LEGACY_TIMER="omarchy-nopasswd-expire-${suffix}"
|
||||
else
|
||||
@@ -256,17 +261,16 @@ cleanup_all_locked() {
|
||||
return "$failed"
|
||||
}
|
||||
|
||||
verify_boot_cleanup() {
|
||||
local owner mode canonical current active_rules
|
||||
[[ ! -e $REMOVAL_BLOCKER && ! -L $REMOVAL_BLOCKER ]] || return 1
|
||||
[[ -f $BOOT_CLEANUP_FILE && ! -L $BOOT_CLEANUP_FILE ]] || return 1
|
||||
canonical=$(/usr/bin/realpath -e -- "$BOOT_CLEANUP_FILE") || return 1
|
||||
[[ $canonical == "$BOOT_CLEANUP_FILE" ]] || return 1
|
||||
owner=$(/usr/bin/stat -Lc '%u' -- "$BOOT_CLEANUP_FILE") || return 1
|
||||
mode=$(/usr/bin/stat -Lc '%a' -- "$BOOT_CLEANUP_FILE") || return 1
|
||||
verify_root_policy_file() {
|
||||
local file=$1 owner mode canonical current
|
||||
[[ -f $file && ! -L $file ]] || return 1
|
||||
canonical=$(/usr/bin/realpath -e -- "$file") || return 1
|
||||
[[ $canonical == "$file" ]] || return 1
|
||||
owner=$(/usr/bin/stat -Lc '%u' -- "$file") || return 1
|
||||
mode=$(/usr/bin/stat -Lc '%a' -- "$file") || return 1
|
||||
[[ $owner == 0 && $mode =~ ^[0-7]+$ ]] && ! ((8#$mode & 022)) || return 1
|
||||
|
||||
current=${BOOT_CLEANUP_FILE%/*}
|
||||
current=${file%/*}
|
||||
while :; do
|
||||
[[ -d $current && ! -L $current ]] || return 1
|
||||
canonical=$(/usr/bin/realpath -e -- "$current") || return 1
|
||||
@@ -277,9 +281,36 @@ verify_boot_cleanup() {
|
||||
current=${current%/*}
|
||||
[[ -n $current ]] || current=/
|
||||
done
|
||||
}
|
||||
|
||||
verify_boot_cleanup() {
|
||||
local active_rules hook
|
||||
[[ ! -e $REMOVAL_BLOCKER && ! -L $REMOVAL_BLOCKER ]] || return 1
|
||||
verify_root_policy_file "$BOOT_CLEANUP_FILE" || return 1
|
||||
active_rules=$(/usr/bin/awk '!/^[[:space:]]*(#|$)/ { print }' "$BOOT_CLEANUP_FILE") || return 1
|
||||
[[ $active_rules == 'r! /etc/sudoers.d/99-omarchy-nopasswd-*' ]]
|
||||
[[ $active_rules == 'r! /etc/sudoers.d/99-omarchy-nopasswd-*' ]] || return 1
|
||||
verify_root_policy_file "$PACKAGE_HOOK" || return 1
|
||||
hook=$(/usr/bin/cat -- "$PACKAGE_HOOK") || return 1
|
||||
[[ $hook == '[Trigger]
|
||||
Operation = Upgrade
|
||||
Operation = Remove
|
||||
Type = Package
|
||||
Target = omarchy-settings
|
||||
Target = omarchy-settings-dev
|
||||
|
||||
[Action]
|
||||
Description = Revoking temporary Omarchy sudo grants before settings changes...
|
||||
When = PreTransaction
|
||||
Exec = /usr/bin/omarchy-sudo-passwordless __package-removing
|
||||
AbortOnFail' ]]
|
||||
}
|
||||
|
||||
package_removing_locked() {
|
||||
# ALPM must abort before removing the helper or boot cleanup if revocation
|
||||
# fails. The marker also blocks publication after this lock is released.
|
||||
(umask 077; : >"$REMOVAL_BLOCKER") || return 1
|
||||
/usr/bin/rm -f -- /etc/sudoers.d/99-omarchy-nopasswd-* || return 1
|
||||
cleanup_all_locked
|
||||
}
|
||||
|
||||
prepare_state_file() {
|
||||
@@ -306,10 +337,13 @@ start_expiry_timer() {
|
||||
}
|
||||
|
||||
publish_rule() {
|
||||
local uid="$1" name="$2" destination tmp
|
||||
local uid="$1" name="$2" expires="$3" destination tmp deadline
|
||||
valid_expiry "$expires" || return 1
|
||||
deadline=$(/usr/bin/date -u -d "@$expires" +%Y%m%d%H%M%SZ) || return 1
|
||||
[[ $deadline =~ ^[0-9]{14}Z$ ]] || return 1
|
||||
destination=$(rule_file "$uid")
|
||||
tmp=$(/usr/bin/mktemp "$STATE_DIR/.sudoers.XXXXXX") || return 1
|
||||
if ! /usr/bin/printf '%s ALL=(ALL) NOPASSWD: ALL\n' "$name" >"$tmp" ||
|
||||
if ! /usr/bin/printf '%s ALL=(ALL) NOTAFTER=%s NOPASSWD: ALL\n' "$name" "$deadline" >"$tmp" ||
|
||||
! /usr/bin/chown root:root "$tmp" || ! /usr/bin/chmod 0440 "$tmp" ||
|
||||
! /usr/sbin/visudo -cf "$tmp" >/dev/null ||
|
||||
! /usr/bin/install -o root -g root -m 0440 -- "$tmp" "$destination"; then
|
||||
@@ -339,7 +373,7 @@ enable_locked() {
|
||||
valid_minutes "$minutes" || return 1
|
||||
prepare_root_state || return 1
|
||||
verify_boot_cleanup || {
|
||||
echo "omarchy-sudo-passwordless: package-owned boot cleanup rule is missing or unsafe" >&2
|
||||
echo "omarchy-sudo-passwordless: package-owned boot cleanup or transaction hook is missing or unsafe" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -363,7 +397,7 @@ enable_locked() {
|
||||
abort_enable_locked "$uid" "$timer" "$old_timer" "$pending_state"
|
||||
return 1
|
||||
fi
|
||||
if ! verify_boot_cleanup || ! publish_rule "$uid" "$ACCOUNT_NAME"; then
|
||||
if ! verify_boot_cleanup || ! publish_rule "$uid" "$ACCOUNT_NAME" "$expires"; then
|
||||
abort_enable_locked "$uid" "$timer" "$old_timer" "$pending_state"
|
||||
return 1
|
||||
fi
|
||||
@@ -464,12 +498,16 @@ root_dispatch() {
|
||||
(($# == 0)) && ((EUID == 0)) || return 1
|
||||
with_root_lock cleanup_all_locked
|
||||
;;
|
||||
__package-removing)
|
||||
(($# == 0)) && ((EUID == 0)) || return 1
|
||||
with_root_lock package_removing_locked
|
||||
;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
__status|__enable|__disable|__expire|__cleanup-all)
|
||||
__status|__enable|__disable|__expire|__cleanup-all|__package-removing)
|
||||
action=$1
|
||||
shift
|
||||
root_dispatch "$action" "$@"
|
||||
|
||||
Reference in new issue
Block a user