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

128
kiss
View File

@ -51,19 +51,32 @@ as_root() {
# 'doas' or 'su'. Hurrah for choice.
[ "$uid" = 0 ] || log "Using '${su:-su}' (to become ${user:=root})"
# Add the following environment variables to the root environment
# so that the non-root user's cache can be used. This is the
# portable method of doing so and works across all tools.
set -- env HOME="$HOME" XDG_CACHE_HOME="$XDG_CACHE_HOME" \
KISS_PATH="$KISS_PATH" KISS_FORCE="$KISS_FORCE" "$@"
case $su in
*sudo) sudo -iu "$user" -- "$@" ;;
*doas) doas -u "$user" -- "$@" ;;
*) su -lc "$* <&3" "$user" 3<&0 </dev/tty ;;
case ${su##*/} in
sudo) sudo -u "$user" -- env "$@" ;;
doas) doas -u "$user" -- env "$@" ;;
su) su -c "env $* <&3" "$user" 3<&0 </dev/tty ;;
*) die "Invalid KISS_SU value: $su (valid: doas, sudo, su)"
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() {
# Provide a default post-build hook to remove files
# and directories for things we don't support out of
@ -1339,33 +1352,26 @@ pkg_updates() {
# ownership of files and directories in the rare
# case that the repository is owned by a 3rd user.
(
# Grab the owner of the 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..
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
file_owner "$PWD"
# We're in a repository which is owned by a 3rd
# user. Not root or the current user.
[ "$user" = root ] ||
log "Dropping permissions to $user for pull"
case $su in
su) "$su" -c "git fetch && git merge" "$user" ;;
*) "$su" -u "$user" git fetch
"$su" -u "$user" git merge
esac
# 'sudo' and 'doas' properly parse command-line
# arguments and split them in the common way. 'su'
# on the other hand requires that each argument be
# properly quoted as the command passed to it must
# 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
}
@ -1471,29 +1477,19 @@ args() {
set -- "${PWD##*/}"
esac
# Parse some arguments earlier to remove the need to duplicate code.
case $action in
s|search)
[ "$1" ] || die "'kiss $action' requires an argument"
;;
# Rerun the script as root with a fixed environment if needed. We sadly
# can't run singular functions as root so this is needed.
case $action in a|alternatives|i|install|r|remove)
[ -z "$1" ] || [ -w "$KISS_ROOT/" ] || [ "$uid" = 0 ] || {
as_root HOME="$HOME" \
XDG_CACHE_HOME="$XDG_CACHE_HOME" \
KISS_PATH="$KISS_PATH" \
KISS_FORCE="$KISS_FORCE" \
KISS_ROOT="$KISS_ROOT" \
kiss "$action" "$@"
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 ] || {
as_root kiss "$action" "$@"
return
}
;;
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
# Actions can be abbreviated to their first letter. This saves
@ -1529,19 +1525,19 @@ args() {
continue
}
pkg_checksums "$pkg" | {
if [ -w "$repo_dir" ]; then
tee "$repo_dir/checksums"
else
log "$pkg" "Need permissions to generate checksums"
pkg_checksums "$pkg" |
read -r _ _ user _ <<-EOF || user=root
$(ls -ld "$PWD")
EOF
if touch "$repo_dir/checksums" 2>/dev/null; then
tee "$repo_dir/checksums"
user=$user as_root tee "$repo_dir/checksums"
fi
}
else
log "$pkg" "Need permissions to generate checksums"
file_owner "$repo_dir"
pkg_checksums "$pkg" |
user=$user as_root tee "$repo_dir/checksums"
fi
log "$pkg" "Generated checksums"
done