kiss: Big cleanup of as_root() usage.

1. The same as_root() function is used for all elevation now. The
   environment can be fully controlled when calling the function.

2. Removal of mixed tabs/spaces due to heredoc fuckery thanks to
   'set -- $(cmd)'.

3. Moved file owner code to a function and added safety measure
   against non-existent UIDs.

4. Fixed bugs when generating checksums via as_root(). Permissions
   are now checked on a file basis instead of a directory one.
This commit is contained in:
Dylan Araps 2020-05-19 12:28:08 +03:00
parent 724d393bb1
commit f5c2777787
No known key found for this signature in database
GPG Key ID: 46D62DD9F1DE636E
2 changed files with 62 additions and 73 deletions

View File

@ -1,7 +0,0 @@
root = true
# Force GitHub to display tabs
# mixed with [4] spaces properly.
[kiss]
indent_style = tab
indent_size = 4

112
kiss
View File

@ -51,19 +51,32 @@ as_root() {
# 'doas' or 'su'. Hurrah for choice. # 'doas' or 'su'. Hurrah for choice.
[ "$uid" = 0 ] || log "Using '${su:-su}' (to become ${user:=root})" [ "$uid" = 0 ] || log "Using '${su:-su}' (to become ${user:=root})"
# Add the following environment variables to the root environment case ${su##*/} in
# so that the non-root user's cache can be used. This is the sudo) sudo -u "$user" -- env "$@" ;;
# portable method of doing so and works across all tools. doas) doas -u "$user" -- env "$@" ;;
set -- env HOME="$HOME" XDG_CACHE_HOME="$XDG_CACHE_HOME" \ su) su -c "env $* <&3" "$user" 3<&0 </dev/tty ;;
KISS_PATH="$KISS_PATH" KISS_FORCE="$KISS_FORCE" "$@" *) die "Invalid KISS_SU value: $su (valid: doas, sudo, su)"
case $su in
*sudo) sudo -iu "$user" -- "$@" ;;
*doas) doas -u "$user" -- "$@" ;;
*) su -lc "$* <&3" "$user" 3<&0 </dev/tty ;;
esac esac
} }
file_owner() {
# Grab the owner of the file/directory via 'ls -ld'. This is
# fine despite the usual gabble about 'ls' and its usage in scripts.
#
# Grabbing permissions, ownership or symlink targets from 'ls -l'
# output is totally fine and doesn't suffer from the disconnect
# between the real and display representation of the information.
#
# Globbing is disabled and word splitting is intentional here.
# shellcheck disable=2046
set -- $(ls -ld "$1"); user=${3:-root}
# If the owner's user ID doesn't exist, fallback
# to using 'root'. This prevents the code from
# changing the permissions to something wonky.
id -u "$user" >/dev/null 2>&1 || user=root
}
run_hook() { run_hook() {
# Provide a default post-build hook to remove files # Provide a default post-build hook to remove files
# and directories for things we don't support out of # and directories for things we don't support out of
@ -1339,33 +1352,26 @@ pkg_updates() {
# ownership of files and directories in the rare # ownership of files and directories in the rare
# case that the repository is owned by a 3rd user. # case that the repository is owned by a 3rd user.
( (
# Grab the owner of the directory via 'ls -ld'. file_owner "$PWD"
# This is fine despite the usual gabble about
# 'ls' and its usage in scripts.
#
# Grabbing permissions, ownership or symlink
# targets from 'ls -l' output is totally fine
# and doesn't suffer from the disconnect
# between the real and display representation
# of the information..
read -r _ _ user _ <<-EOF || user=root
$(ls -ld "$PWD")
EOF
# If the owner's user ID doesn't exist, fallback
# to using 'root'. This prevents the code from
# changing the permissions to something wonky.
id -u "$user" >/dev/null 2>&1 ||
user=root
# We're in a repository which is owned by a 3rd
# user. Not root or the current user.
[ "$user" = root ] || [ "$user" = root ] ||
log "Dropping permissions to $user for pull" log "Dropping permissions to $user for pull"
case $su in # 'sudo' and 'doas' properly parse command-line
su) "$su" -c "git fetch && git merge" "$user" ;; # arguments and split them in the common way. 'su'
*) "$su" -u "$user" git fetch # on the other hand requires that each argument be
"$su" -u "$user" git merge # properly quoted as the command passed to it must
esac # be a string... This sets quotes where needed.
git_cmd="git fetch && git merge"
case $su in *su) git_cmd="'$git_cmd'"; esac
# Spawn a subshell to run multiple commands as
# root at once. This makes things easier on users
# who aren't using persist/timestamps for auth
# caching.
user=$user as_root sh -c "$git_cmd"
) )
fi fi
} }
@ -1471,29 +1477,19 @@ args() {
set -- "${PWD##*/}" set -- "${PWD##*/}"
esac esac
# Parse some arguments earlier to remove the need to duplicate code. # Rerun the script as root with a fixed environment if needed. We sadly
case $action in # can't run singular functions as root so this is needed.
s|search) case $action in a|alternatives|i|install|r|remove)
[ "$1" ] || die "'kiss $action' requires an argument"
;;
a|alternatives)
# Rerun the script with 'su' if the user isn't root.
# Cheeky but 'su' can't be used on shell functions themselves.
[ -z "$1" ] || [ -w "$KISS_ROOT/" ] || [ "$uid" = 0 ] || { [ -z "$1" ] || [ -w "$KISS_ROOT/" ] || [ "$uid" = 0 ] || {
as_root kiss "$action" "$@" as_root HOME="$HOME" \
return XDG_CACHE_HOME="$XDG_CACHE_HOME" \
} KISS_PATH="$KISS_PATH" \
;; KISS_FORCE="$KISS_FORCE" \
KISS_ROOT="$KISS_ROOT" \
kiss "$action" "$@"
i|install|r|remove)
# Rerun the script with 'su' if the user isn't root.
# Cheeky but 'su' can't be used on shell functions themselves.
[ -w "$KISS_ROOT/" ] || [ "$uid" = 0 ] || {
KISS_FORCE="$KISS_FORCE" as_root kiss "$action" "$@"
return return
} }
;;
esac esac
# Actions can be abbreviated to their first letter. This saves # Actions can be abbreviated to their first letter. This saves
@ -1529,19 +1525,19 @@ args() {
continue continue
} }
pkg_checksums "$pkg" | { pkg_checksums "$pkg" |
if [ -w "$repo_dir" ]; then
if touch "$repo_dir/checksums" 2>/dev/null; then
tee "$repo_dir/checksums" tee "$repo_dir/checksums"
else else
log "$pkg" "Need permissions to generate checksums" log "$pkg" "Need permissions to generate checksums"
read -r _ _ user _ <<-EOF || user=root file_owner "$repo_dir"
$(ls -ld "$PWD") pkg_checksums "$pkg" |
EOF
user=$user as_root tee "$repo_dir/checksums" user=$user as_root tee "$repo_dir/checksums"
fi fi
}
log "$pkg" "Generated checksums" log "$pkg" "Generated checksums"
done done