From 7eb80497f6308a8f0f6ffaa96cd43d903582d963 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 10:06:56 +0200 Subject: [PATCH 01/22] kiss: Simpler elevation method --- kiss | 60 ++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/kiss b/kiss index c353568..2528e3d 100755 --- a/kiss +++ b/kiss @@ -45,6 +45,33 @@ prompt() { read -r _ } +root_cache() { + # This function simply mimics a 'su' prompt to then store + # the user's root password for the lifetime of the package + # manager. + # + # Think of this as the simplest method of "elevating" + # permissions where needed without the endless stream of + # password prompts. + printf 'Password: ' + stty -echo + read -r pass || read -r pass ||: + stty echo + printf '\n' + + # Validate the password now with a simple 'true' command + # as we don't yet need to elevate permissions. + root_run true +} + +root_run() { + # Run a command as root using the cached password. The 'su' + # command allows you to input a password via stdin. To hide + # the prompt, the command's output is sent to '/dev/tty' + # and the output of 'su' is sent to '/dev/null'. + echo "$pass" | su -c "$* >/dev/tty" >/dev/null +} + pkg_lint() { # Check that each mandatory file in the package entry exists. log "$1" "Checking repository files" @@ -880,17 +907,8 @@ pkg_updates() { git fetch git merge else - log "$PWD" "Need root to update" - - if command -v sudo >/dev/null; then - sudo git fetch - sudo git merge - elif command -v doas >/dev/null; then - doas git fetch - doas git merge - else - su -c 'git fetch && git merge' - fi + root_run git fetch + root_run git merge fi } done @@ -995,22 +1013,12 @@ args() { [ "$1" ] || die "'kiss $action' requires an argument" ;; - i|install|r|remove) - [ "$1" ] || die "'kiss $action' requires an argument" + i|install|r|remove|u|update) + [ "$1" ] || [ -z "${action##u*}" ] || + die "'kiss $action' requires an argument" - # Rerun the script with 'su' if the user isn't root. - # Cheeky but 'su' can't be used on shell functions themselves. - [ "$(id -u)" = 0 ] || { - if command -v sudo >/dev/null; then - sudo -E KISS_FORCE="$KISS_FORCE" kiss "$action" "$@" - elif command -v doas >/dev/null; then - KISS_FORCE="$KISS_FORCE" doas kiss "$action" "$@" - else - su -pc "KISS_FORCE=$KISS_FORCE kiss $action $*" - fi - - return - } + # Cache the root password for use where needed. + [ "$(id -u)" = 0 ] || root_cache ;; esac From 7ab295a76ba627ca3e8fd5e550595fb84b3506ed Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 10:54:39 +0200 Subject: [PATCH 02/22] kiss: Run as root where needed --- kiss | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/kiss b/kiss index 2528e3d..47744b7 100755 --- a/kiss +++ b/kiss @@ -61,10 +61,10 @@ root_cache() { # Validate the password now with a simple 'true' command # as we don't yet need to elevate permissions. - root_run true + dosu true } -root_run() { +dosu() { # Run a command as root using the cached password. The 'su' # command allows you to input a password via stdin. To hide # the prompt, the command's output is sent to '/dev/tty' @@ -719,9 +719,9 @@ pkg_remove() { [ "${file##/etc/*}" ] || continue if [ -d "$KISS_ROOT/$file" ]; then - rmdir "$KISS_ROOT/$file" 2>/dev/null || continue + dosu rmdir "$KISS_ROOT/$file" 2>/dev/null || continue else - rm -f "$KISS_ROOT/$file" + dosu rm -f "$KISS_ROOT/$file" fi done < "$sys_db/$1/manifest" @@ -797,7 +797,7 @@ pkg_install() { # This is repeated multiple times. Better to make it a function. pkg_rsync() { - rsync --chown=root:root --chmod=Du-s,Dg-s,Do-s \ + dosu rsync --chown=root:root --chmod=Du-s,Dg-s,Do-s \ -WhHKa --no-compress "$1" --exclude /etc \ "$tar_dir/$pkg_name/" "$KISS_ROOT/" } @@ -808,7 +808,7 @@ pkg_install() { # If '/etc/' exists in the package, install it but don't overwrite. [ -d "$tar_dir/$pkg_name/etc" ] && - rsync --chown=root:root -WhHKa --no-compress --ignore-existing \ + dosu rsync --chown=root:root -WhHKa --no-compress --ignore-existing \ "$tar_dir/$pkg_name/etc" "$KISS_ROOT/" # Remove any leftover files if this is an upgrade. @@ -826,18 +826,18 @@ pkg_install() { # Remove files. if [ -f "$file" ] && [ ! -L "$file" ]; then - rm -f "$file" + dosu rm -f "$file" # Remove file symlinks. elif [ -L "$file" ] && [ ! -d "$file" ]; then - unlink "$file" ||: + dosu unlink "$file" ||: # Skip directory symlinks. elif [ -L "$file" ] && [ -d "$file" ]; then : # Remove directories if empty. elif [ -d "$file" ]; then - rmdir "$file" 2>/dev/null ||: + dosu rmdir "$file" 2>/dev/null ||: fi done ||: } @@ -853,7 +853,7 @@ pkg_install() { if [ -x "$sys_db/$pkg_name/post-install" ]; then log "$pkg_name" "Running post-install script" - "$sys_db/$pkg_name/post-install" ||: + dosu "$sys_db/$pkg_name/post-install" ||: fi log "$pkg_name" "Installed successfully" @@ -907,8 +907,8 @@ pkg_updates() { git fetch git merge else - root_run git fetch - root_run git merge + dosu git fetch + dosu git merge fi } done From a01483a2610cdedcba4ce87a273175b46551466c Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 11:10:53 +0200 Subject: [PATCH 03/22] kiss: fix args i issues --- kiss | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/kiss b/kiss index 47744b7..731f6e1 100755 --- a/kiss +++ b/kiss @@ -65,6 +65,8 @@ root_cache() { } dosu() { + [ "$pass" ] || root_cache + # Run a command as root using the cached password. The 'su' # command allows you to input a password via stdin. To hide # the prompt, the command's output is sent to '/dev/tty' @@ -494,7 +496,9 @@ pkg_build() { # to 'su' to elevate permissions. [ -f "$bin_dir/$pkg#$version-$release.tar.gz" ] && { log "$pkg" "Found pre-built binary, installing" - (KISS_FORCE=1 args i "$bin_dir/$pkg#$version-$release.tar.gz") + + dosu KISS_FORCE=1 \ + kiss i "$bin_dir/$pkg#$version-$release.tar.gz" ||: # Remove the now installed package from the build # list. No better way than using 'sed' in POSIX 'sh'. @@ -581,7 +585,8 @@ pkg_build() { contains "$explicit" "$pkg" && [ -z "$pkg_update" ] && continue log "$pkg" "Needed as a dependency or has an update, installing" - (KISS_FORCE=1 args i "$pkg") + + dosu KISS_FORCE=1 kiss i "$bin_dir/$pkg#$version-$release.tar.gz" ||: done # End here as this was a system update and all packages have been installed. @@ -599,7 +604,7 @@ pkg_build() { log "Install built packages? [$*]" prompt && { - args i "$@" + dosu kiss i "$@" ||: return } } @@ -941,7 +946,7 @@ pkg_updates() { prompt pkg_build kiss - args i kiss + dosu kiss i kiss ||: log "Updated the package manager" log "Re-run 'kiss update' to update your system" @@ -974,6 +979,8 @@ pkg_updates() { pkg_clean() { # Clean up on exit or error. This removes everything related # to the build. + stty echo 2>/dev/null + [ "$KISS_DEBUG" != 1 ] || return # Block 'Ctrl+C' while cache is being cleaned. From b23afcc3b4d93041e267d8b613abded79ed5ba0f Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 11:16:51 +0200 Subject: [PATCH 04/22] kiss: fix args i issues --- kiss | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/kiss b/kiss index 731f6e1..ce45dc3 100755 --- a/kiss +++ b/kiss @@ -497,8 +497,8 @@ pkg_build() { [ -f "$bin_dir/$pkg#$version-$release.tar.gz" ] && { log "$pkg" "Found pre-built binary, installing" - dosu KISS_FORCE=1 \ - kiss i "$bin_dir/$pkg#$version-$release.tar.gz" ||: + KISS_FORCE=1 \ + pkg_install "$bin_dir/$pkg#$version-$release.tar.gz" # Remove the now installed package from the build # list. No better way than using 'sed' in POSIX 'sh'. @@ -586,7 +586,8 @@ pkg_build() { log "$pkg" "Needed as a dependency or has an update, installing" - dosu KISS_FORCE=1 kiss i "$bin_dir/$pkg#$version-$release.tar.gz" ||: + KISS_FORCE=1 \ + pkg_install "$bin_dir/$pkg#$version-$release.tar.gz" done # End here as this was a system update and all packages have been installed. @@ -604,7 +605,7 @@ pkg_build() { log "Install built packages? [$*]" prompt && { - dosu kiss i "$@" ||: + dosu kiss i "$@" return } } @@ -945,8 +946,8 @@ pkg_updates() { prompt - pkg_build kiss - dosu kiss i kiss ||: + pkg_build kiss + pkg_install kiss log "Updated the package manager" log "Re-run 'kiss update' to update your system" From 164afb3b48d0730280ac380723db9b743dc10a82 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 11:19:08 +0200 Subject: [PATCH 05/22] kiss: Fix install issues --- kiss | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kiss b/kiss index ce45dc3..cb6753c 100755 --- a/kiss +++ b/kiss @@ -497,8 +497,8 @@ pkg_build() { [ -f "$bin_dir/$pkg#$version-$release.tar.gz" ] && { log "$pkg" "Found pre-built binary, installing" - KISS_FORCE=1 \ - pkg_install "$bin_dir/$pkg#$version-$release.tar.gz" + (KISS_FORCE=1 \ + pkg_install "$bin_dir/$pkg#$version-$release.tar.gz") # Remove the now installed package from the build # list. No better way than using 'sed' in POSIX 'sh'. @@ -586,8 +586,8 @@ pkg_build() { log "$pkg" "Needed as a dependency or has an update, installing" - KISS_FORCE=1 \ - pkg_install "$bin_dir/$pkg#$version-$release.tar.gz" + (KISS_FORCE=1 \ + pkg_install "$bin_dir/$pkg#$version-$release.tar.gz") done # End here as this was a system update and all packages have been installed. @@ -1129,6 +1129,11 @@ args() { } main() { + # Ensure that debug mode is never enabled to + # prevent internal package manager information + # from leaking to stdout. + set +x + # Set the location to the repository and package database. pkg_db=var/db/kiss/installed From 7493ccb17beb5803c535772ec2315f64448b63e7 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 11:24:58 +0200 Subject: [PATCH 06/22] kiss: Only cache root on first need --- kiss | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/kiss b/kiss index cb6753c..5107ff7 100755 --- a/kiss +++ b/kiss @@ -54,9 +54,9 @@ root_cache() { # permissions where needed without the endless stream of # password prompts. printf 'Password: ' - stty -echo - read -r pass || read -r pass ||: - stty echo + stty -F /dev/tty -echo + read -r pass /dev/null + stty -F /dev/tty echo 2>/dev/null [ "$KISS_DEBUG" != 1 ] || return @@ -1017,17 +1017,9 @@ args() { # Parse some arguments earlier to remove the need to duplicate code. case $action in - c|checksum|s|search) + c|checksum|s|search|i|install|r|remove) [ "$1" ] || die "'kiss $action' requires an argument" ;; - - i|install|r|remove|u|update) - [ "$1" ] || [ -z "${action##u*}" ] || - die "'kiss $action' requires an argument" - - # Cache the root password for use where needed. - [ "$(id -u)" = 0 ] || root_cache - ;; esac # Actions can be abbreviated to their first letter. This saves From d61986721d5639b1cd98186969572660d0c46589 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 11:29:20 +0200 Subject: [PATCH 07/22] kiss: drop root when running git if needed --- kiss | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kiss b/kiss index 5107ff7..aa094a3 100755 --- a/kiss +++ b/kiss @@ -71,7 +71,7 @@ dosu() { # command allows you to input a password via stdin. To hide # the prompt, the command's output is sent to '/dev/tty' # and the output of 'su' is sent to '/dev/null'. - echo "$pass" | su -c "$* >/dev/tty" >/dev/null + echo "$pass" | su "${drop_to:-root}" -c "$* >/dev/tty" >/dev/null } pkg_lint() { @@ -912,9 +912,16 @@ pkg_updates() { if [ -w "$PWD" ]; then git fetch git merge + else + log "$PWD" "Need root to update" + + # Find out the owner of the repository and spawn + # git as this user below. + (drop_to=$(stat -c %U "$PWD") + dosu git fetch - dosu git merge + dosu git merge) fi } done From d43673e340786669bae5db923d21d47bdff30105 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 11:32:16 +0200 Subject: [PATCH 08/22] kiss: remove calling itself --- kiss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kiss b/kiss index aa094a3..07c4dca 100755 --- a/kiss +++ b/kiss @@ -605,7 +605,7 @@ pkg_build() { log "Install built packages? [$*]" prompt && { - dosu kiss i "$@" + args i "$@" return } } From 613d5e696770ba76bb4cd6545d91fa7f0e43b6c3 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 11:34:37 +0200 Subject: [PATCH 09/22] kiss: use heredoc --- .editorconfig | 7 +++++++ kiss | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7b8413b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root = true + +# Force GitHub to display tabs +# mixed with [4] spaces properly. +[kiss] +indent_style = tab +indent_size = 4 diff --git a/kiss b/kiss index 07c4dca..bd95417 100755 --- a/kiss +++ b/kiss @@ -71,7 +71,9 @@ dosu() { # command allows you to input a password via stdin. To hide # the prompt, the command's output is sent to '/dev/tty' # and the output of 'su' is sent to '/dev/null'. - echo "$pass" | su "${drop_to:-root}" -c "$* >/dev/tty" >/dev/null + su "${drop_to:-root}" -c "$* >/dev/tty" <<-EOF >/dev/null + $pass + EOF } pkg_lint() { From 1376de2f31157ffca243d6b05e0f09c825d91c5e Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 13:42:29 +0200 Subject: [PATCH 10/22] kiss: prompt for password before multi-build --- kiss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kiss b/kiss index bd95417..7d49ca7 100755 --- a/kiss +++ b/kiss @@ -479,7 +479,11 @@ pkg_build() { log "Building: $*" # Only ask for confirmation if more than one package needs to be built. - [ $# -gt 1 ] || [ "$pkg_update" ] && prompt + [ $# -gt 1 ] || [ "$pkg_update" ] && { + prompt + + [ "$pass" ] || root_cache + } log "Checking to see if any dependencies have already been built" log "Installing any pre-built dependencies" From 8240ae8fe01409d4689b4bb53e1b02ec73bb6130 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 13:49:41 +0200 Subject: [PATCH 11/22] kiss: don't run as root --- kiss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kiss b/kiss index 7d49ca7..8303bae 100755 --- a/kiss +++ b/kiss @@ -1139,6 +1139,10 @@ main() { # from leaking to stdout. set +x + # Prevent the package manager from running as root. The package + # manager will elevate permissions where needed. + [ "$(id -u)" != 0 ] || die "kiss must be run as a normal user" + # Set the location to the repository and package database. pkg_db=var/db/kiss/installed From d80f714268f7414107716f16807cdf00821bd04f Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 22:18:20 +0200 Subject: [PATCH 12/22] docs: update --- kiss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kiss b/kiss index 8303bae..13283d9 100755 --- a/kiss +++ b/kiss @@ -61,7 +61,7 @@ root_cache() { # Validate the password now with a simple 'true' command # as we don't yet need to elevate permissions. - dosu true + dosu /bin/true } dosu() { From a2684a765b4889b993787e48d25c29331f28870e Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 23:26:20 +0200 Subject: [PATCH 13/22] kiss: Add comments --- kiss | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/kiss b/kiss index 13283d9..3f1aef1 100755 --- a/kiss +++ b/kiss @@ -47,33 +47,98 @@ prompt() { root_cache() { # This function simply mimics a 'su' prompt to then store - # the user's root password for the lifetime of the package - # manager. + # the root password for the lifetime of the package manager. # - # Think of this as the simplest method of "elevating" - # permissions where needed without the endless stream of - # password prompts. + # This function is called once when needed to cache the + # password. The password is not accessible to any subprocesses + # and should never leave the package manager's process. + # + # This behavior is needed as there is no POSIX shell method + # of running a shell function as a different user. We can't + # selectively lower or raise permissions in a seamless way + # through "normal" means. + # + # Root is only needed when installing/removing packages whereas + # non-root permissions are needed in countless places throughout. + # + # This is the only *workable* solution to 1) not run the entire + # package manager as root and 2) avoid prompting for password + # before, during and after builds numerous times. + # + # NOTE: Careful consideration has been taken in regards to this + # change and I would have loved an inconspicuous solution + # to this problem... but it doesn't exist. + # + # This change was needed as the existing behavior was not ideal + # in any way and needed to be fixed. printf 'Password: ' + + # Disable echoing to the terminal while the password is inputted + # by the user. The below commands read from '/dev/tty' to ensure + # they work when run from a subshell. stty -F /dev/tty -echo - read -r pass /dev/tty" <<-EOF >/dev/null - $pass - EOF + dosudo() { su "${drop_to:-root}" -c "$* >/dev/tty" >/dev/null; } + + # The code below uses the most secure method of sending + # data over stdin based on what is available in the system. + # + # The great debate: Use a heredoc or echo+pipe for password + # input over stdin? Time to explain. + # + # 1) 'printf | cmd' is the most secure IF 'printf' is built + # into the shell and NOT an external command. When 'printf' + # is external, the password WILL be leaked over '/proc'. + # + # Safe shells here are anything with a builtin 'printf', + # 'ash', 'dash', 'bash' and most other shells. + # + # 2) Using a heredoc is as secure as the above method (when + # builtin) IF and only IF the user's shell implements + # heredocs WITHOUT the use of temporary files (See bash!). + # + # When using heredocs and a temporary file the risk is a + # tiny window in which the input is available inside of + # a temporary file. + # + # 'ash' and 'dash' are safe here, 'bash' is not ('bash' + # falls under (1) however). + # + # Which is best? (order is best to worst) + # + # 1) builtin 'printf'. + # 2) heredocs with no temporary file. + # 3) heredocs with a temporary file. + # + # This code below follows the above ordering when deciding + # which method to use. The '$heredocs' variable is declared + # in 'main()' after a check to see if 'printf' is builtin. + if [ "$heredocs" ]; then + dosudo "$@" <<-EOF + $pass + EOF + else + printf '%s\n' "$pass" | dosudo "$@" + fi } pkg_lint() { @@ -1143,6 +1208,10 @@ main() { # manager will elevate permissions where needed. [ "$(id -u)" != 0 ] || die "kiss must be run as a normal user" + # Use the most secure method of sending data over stdin based on + # whether or not the 'printf' command is built into the shell. + [ "$(command -v printf)" = printf ] || heredocs=1 + # Set the location to the repository and package database. pkg_db=var/db/kiss/installed From 87e0cfd973fbff3f83bde265446bd116ff1fdd05 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 23:27:34 +0200 Subject: [PATCH 14/22] docs: update --- kiss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kiss b/kiss index 3f1aef1..acd1582 100755 --- a/kiss +++ b/kiss @@ -1199,9 +1199,8 @@ args() { } main() { - # Ensure that debug mode is never enabled to - # prevent internal package manager information - # from leaking to stdout. + # Ensure that debug mode is never enabled to prevent internal + # package manager information from leaking to stdout. set +x # Prevent the package manager from running as root. The package From 4f4d2200569283f468ea88d2dc4072d443b41d1b Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 23:33:30 +0200 Subject: [PATCH 15/22] kiss: Don't use pass where unneeded --- kiss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kiss b/kiss index acd1582..dd3b6bd 100755 --- a/kiss +++ b/kiss @@ -84,11 +84,11 @@ root_cache() { # Validate the password now with a simple 'true' command as we # don't yet need to elevate permissions. - dosu /bin/true + dosu /bin/true && have_pw=1 } dosu() { - [ "$pass" ] || root_cache + [ "$have_pw" ] || root_cache # Declare this as a function to avoid repeating it twice # below. Great naming of functions all around. @@ -547,7 +547,7 @@ pkg_build() { [ $# -gt 1 ] || [ "$pkg_update" ] && { prompt - [ "$pass" ] || root_cache + [ "$have_pw" ] || root_cache } log "Checking to see if any dependencies have already been built" From 3962f64385ced3cc5b0ae4506badacba29fe3234 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 23:36:51 +0200 Subject: [PATCH 16/22] kiss: comment --- kiss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kiss b/kiss index dd3b6bd..fbd2ccb 100755 --- a/kiss +++ b/kiss @@ -84,6 +84,10 @@ root_cache() { # Validate the password now with a simple 'true' command as we # don't yet need to elevate permissions. + # + # Rather than checking if the '$pass' variable is non-empty, + # use an additional variable. The '[' command can be external + # which would result in '/proc' leakage. dosu /bin/true && have_pw=1 } From fd892ccd7b164f8d1c0f3dbe339f406a8b135db2 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 23:46:26 +0200 Subject: [PATCH 17/22] kiss: fix cache --- kiss | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/kiss b/kiss index fbd2ccb..dc33b8a 100755 --- a/kiss +++ b/kiss @@ -77,22 +77,18 @@ root_cache() { # by the user. The below commands read from '/dev/tty' to ensure # they work when run from a subshell. stty -F /dev/tty -echo - read -r pass < /dev/tty ||: + read -r pass < /dev/tty && cached=1 stty -F /dev/tty echo printf '\n' # Validate the password now with a simple 'true' command as we # don't yet need to elevate permissions. - # - # Rather than checking if the '$pass' variable is non-empty, - # use an additional variable. The '[' command can be external - # which would result in '/proc' leakage. - dosu /bin/true && have_pw=1 + dosu /bin/true } dosu() { - [ "$have_pw" ] || root_cache + [ "$cached" ] || root_cache # Declare this as a function to avoid repeating it twice # below. Great naming of functions all around. @@ -551,7 +547,7 @@ pkg_build() { [ $# -gt 1 ] || [ "$pkg_update" ] && { prompt - [ "$have_pw" ] || root_cache + [ "$cached" ] || root_cache } log "Checking to see if any dependencies have already been built" From 5796f2a69f8a6e6fc4d6b9fa23abe65d30253231 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 23:51:31 +0200 Subject: [PATCH 18/22] kiss: comment --- kiss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kiss b/kiss index dc33b8a..db2f13f 100755 --- a/kiss +++ b/kiss @@ -76,6 +76,10 @@ root_cache() { # Disable echoing to the terminal while the password is inputted # by the user. The below commands read from '/dev/tty' to ensure # they work when run from a subshell. + # + # The variable '$cached' is used to check if we've been here + # before. We cannot check whether or not '$pass' is empty as the + # '[' command may be external which would result in /proc leakage. stty -F /dev/tty -echo read -r pass < /dev/tty && cached=1 stty -F /dev/tty echo From 33a89dbe88ca8b2142c94d45ab300d4bb91d0e59 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 23:53:36 +0200 Subject: [PATCH 19/22] kiss: comment --- kiss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kiss b/kiss index db2f13f..0243004 100755 --- a/kiss +++ b/kiss @@ -551,6 +551,10 @@ pkg_build() { [ $# -gt 1 ] || [ "$pkg_update" ] && { prompt + # Prompt for password prior to the build if more than one package + # will be built and installed. No use in forcing the user to wait + # for the first password prompt (before caching) if it may take a + # long long while. [ "$cached" ] || root_cache } From 6fc8b89b82c7c28185b044e9f8e3473a8e0b7404 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Mon, 27 Jan 2020 23:58:08 +0200 Subject: [PATCH 20/22] kiss: comment --- kiss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kiss b/kiss index 0243004..7db2fd4 100755 --- a/kiss +++ b/kiss @@ -997,6 +997,10 @@ pkg_updates() { # Find out the owner of the repository and spawn # git as this user below. + # + # This prevents 'git' from changing the original + # ownership of files and directories in the rare + # case that the repository is owned by a 3rd user. (drop_to=$(stat -c %U "$PWD") dosu git fetch From 63b655bdf7a0eaa4912eaa10e9cc1094a3364c88 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Tue, 28 Jan 2020 00:10:09 +0200 Subject: [PATCH 21/22] kiss: Ensure all arguments sent to dosu are quoted --- kiss | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kiss b/kiss index 7db2fd4..3b7de2e 100755 --- a/kiss +++ b/kiss @@ -804,9 +804,9 @@ pkg_remove() { [ "${file##/etc/*}" ] || continue if [ -d "$KISS_ROOT/$file" ]; then - dosu rmdir "$KISS_ROOT/$file" 2>/dev/null || continue + dosu rmdir "'$KISS_ROOT/$file'" 2>/dev/null || continue else - dosu rm -f "$KISS_ROOT/$file" + dosu rm -f "'$KISS_ROOT/$file'" fi done < "$sys_db/$1/manifest" @@ -884,7 +884,7 @@ pkg_install() { pkg_rsync() { dosu rsync --chown=root:root --chmod=Du-s,Dg-s,Do-s \ -WhHKa --no-compress "$1" --exclude /etc \ - "$tar_dir/$pkg_name/" "$KISS_ROOT/" + "'$tar_dir/$pkg_name/'" "'$KISS_ROOT/'" } # Install the package by using 'rsync' and overwrite any existing files @@ -894,7 +894,7 @@ pkg_install() { # If '/etc/' exists in the package, install it but don't overwrite. [ -d "$tar_dir/$pkg_name/etc" ] && dosu rsync --chown=root:root -WhHKa --no-compress --ignore-existing \ - "$tar_dir/$pkg_name/etc" "$KISS_ROOT/" + "'$tar_dir/$pkg_name/etc'" "'$KISS_ROOT/'" # Remove any leftover files if this is an upgrade. [ "$old_manifest" ] && { @@ -911,18 +911,18 @@ pkg_install() { # Remove files. if [ -f "$file" ] && [ ! -L "$file" ]; then - dosu rm -f "$file" + dosu rm -f "'$file'" # Remove file symlinks. elif [ -L "$file" ] && [ ! -d "$file" ]; then - dosu unlink "$file" ||: + dosu unlink "'$file'" ||: # Skip directory symlinks. elif [ -L "$file" ] && [ -d "$file" ]; then : # Remove directories if empty. elif [ -d "$file" ]; then - dosu rmdir "$file" 2>/dev/null ||: + dosu rmdir "'$file'" 2>/dev/null ||: fi done ||: } @@ -938,7 +938,7 @@ pkg_install() { if [ -x "$sys_db/$pkg_name/post-install" ]; then log "$pkg_name" "Running post-install script" - dosu "$sys_db/$pkg_name/post-install" ||: + dosu "'$sys_db/$pkg_name/post-install'" ||: fi log "$pkg_name" "Installed successfully" From b3485bf4300a450b9294e0fe5286567cb4136297 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Tue, 28 Jan 2020 00:41:10 +0200 Subject: [PATCH 22/22] kiss: read empty IFS --- kiss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kiss b/kiss index 3b7de2e..28b0161 100755 --- a/kiss +++ b/kiss @@ -81,7 +81,7 @@ root_cache() { # before. We cannot check whether or not '$pass' is empty as the # '[' command may be external which would result in /proc leakage. stty -F /dev/tty -echo - read -r pass < /dev/tty && cached=1 + IFS= read -r pass < /dev/tty && cached=1 stty -F /dev/tty echo printf '\n'