ssh_filter_btrbk.sh: minor improvements

• Set shell options in one command.
• Homogeneously use local variables for function positional parameters in all
  places.
• In redirections, omit `1` for standard output.
• Homogeneously use `if`-compount-commands instead of `[ … ] && …` in all
  places.
• Homogeneously use curly brackets with parameter expansion.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
pull/511/head
Christoph Anton Mitterer 2022-11-21 22:12:13 +01:00
parent 4888cc51e5
commit 7db20c9d16
1 changed files with 35 additions and 23 deletions

View File

@ -1,7 +1,6 @@
#!/bin/sh #!/bin/sh
set -e set -e -u
set -u
export PATH='/usr/bin:/bin' export PATH='/usr/bin:/bin'
@ -16,44 +15,53 @@ compress_list='gzip|pigz|bzip2|pbzip2|bzip3|xz|lzop|lz4|zstd'
# note that the backslash is NOT a metacharacter in a POSIX bracket expression! # note that the backslash is NOT a metacharacter in a POSIX bracket expression!
option_match='-[a-zA-Z0-9=-]+' # matches short as well as long options option_match='-[a-zA-Z0-9=-]+' # matches short as well as long options
file_match_sane='/[0-9a-zA-Z_@+./-]*' # matches file path (equal to $file_match in btrbk < 0.32.0) file_match_sane='/[0-9a-zA-Z_@+./-]*' # matches file path (equal to ${file_match} in btrbk < 0.32.0)
file_match="/[^']*" # btrbk >= 0.32.0 quotes file arguments: match all but single quote file_match="/[^']*" # btrbk >= 0.32.0 quotes file arguments: match all but single quote
file_arg_match="('${file_match}'|${file_match_sane})" # support btrbk < 0.32.0 file_arg_match="('${file_match}'|${file_match_sane})" # support btrbk < 0.32.0
log_cmd() log_cmd()
{ {
if [ -n "$enable_log" ]; then local priority="$1"
logger -p "$1" -t ssh_filter_btrbk.sh "$2 (Name: ${LOGNAME:-<unknown>}; Connection: ${SSH_CONNECTION:-<unknown>})${3:+: $3}: $SSH_ORIGINAL_COMMAND" local authorisation_decision="$2"
local reason="${3-}"
if [ -n "${enable_log}" ]; then
logger -p "${priority}" -t ssh_filter_btrbk.sh "${authorisation_decision} (Name: ${LOGNAME:-<unknown>}; Connection: ${SSH_CONNECTION:-<unknown>})${reason:+: ${reason}}: ${SSH_ORIGINAL_COMMAND}"
fi fi
} }
allow_cmd() allow_cmd()
{ {
allow_list="${allow_list}|$1" local cmd="$1"
allow_list="${allow_list}|${cmd}"
} }
allow_exact_cmd() allow_exact_cmd()
{ {
allow_exact_list="${allow_exact_list}|$1" local cmd="$1"
allow_exact_list="${allow_exact_list}|${cmd}"
} }
reject_and_die() reject_and_die()
{ {
local reason="$1" local reason="$1"
log_cmd 'auth.err' 'btrbk REJECT' "$reason"
printf 'ERROR: ssh_filter_btrbk.sh: ssh command rejected: %s: %s\n' "$reason" "$SSH_ORIGINAL_COMMAND" 1>&2 log_cmd 'auth.err' 'btrbk REJECT' "${reason}"
printf 'ERROR: ssh_filter_btrbk.sh: ssh command rejected: %s: %s\n' "${reason}" "${SSH_ORIGINAL_COMMAND}" >&2
exit 1 exit 1
} }
run_cmd() run_cmd()
{ {
log_cmd 'auth.info' 'btrbk ACCEPT' log_cmd 'auth.info' 'btrbk ACCEPT'
eval " $SSH_ORIGINAL_COMMAND" eval " ${SSH_ORIGINAL_COMMAND}"
} }
reject_filtered_cmd() reject_filtered_cmd()
{ {
if [ -n "$restrict_path_list" ]; then if [ -n "${restrict_path_list}" ]; then
# match any of restrict_path_list, # match any of restrict_path_list,
# or any file/directory (matching file_match) below restrict_path # or any file/directory (matching file_match) below restrict_path
path_match="'(${restrict_path_list})(${file_match})?'" path_match="'(${restrict_path_list})(${file_match})?'"
@ -66,7 +74,7 @@ reject_filtered_cmd()
# btrbk >= 0.32.0 quotes files, allow both (legacy) # btrbk >= 0.32.0 quotes files, allow both (legacy)
path_match="(${path_match}|${path_match_legacy})" path_match="(${path_match}|${path_match_legacy})"
if [ -n "$allow_compress" ]; then if [ -n "${allow_compress}" ]; then
decompress_match="(${compress_list}) -d -c( -[pT][0-9]+)?" decompress_match="(${compress_list}) -d -c( -[pT][0-9]+)?"
compress_match="(${compress_list}) -c( -[0-9])?( -[pT][0-9]+)?" compress_match="(${compress_list}) -c( -[0-9])?( -[pT][0-9]+)?"
else else
@ -76,7 +84,7 @@ reject_filtered_cmd()
# rate_limit_remote and stream_buffer_remote use combined # rate_limit_remote and stream_buffer_remote use combined
# "mbuffer" as of btrbk-0.29.0 # "mbuffer" as of btrbk-0.29.0
if [ -n "$allow_stream_buffer" ] || [ -n "$allow_rate_limit" ]; then if [ -n "${allow_stream_buffer}" ] || [ -n "${allow_rate_limit}" ]; then
mbuffer_match='mbuffer -v 1 -q( -s [0-9]+[kmgKMG]?)?( -m [0-9]+[kmgKMG]?)?( -[rR] [0-9]+[kmgtKMGT]?)?' mbuffer_match='mbuffer -v 1 -q( -s [0-9]+[kmgKMG]?)?( -m [0-9]+[kmgKMG]?)?( -[rR] [0-9]+[kmgtKMGT]?)?'
else else
mbuffer_match= mbuffer_match=
@ -91,31 +99,35 @@ reject_filtered_cmd()
# when an error occurred. # when an error occurred.
allow_stream_match="^${stream_in_match}${allow_cmd_match}${stream_out_match}" allow_stream_match="^${stream_in_match}${allow_cmd_match}${stream_out_match}"
if printf '%s' "$SSH_ORIGINAL_COMMAND" | grep -E "$allow_stream_match" >/dev/null 2>/dev/null; then if printf '%s' "${SSH_ORIGINAL_COMMAND}" | grep -E "${allow_stream_match}" >/dev/null 2>/dev/null; then
return 0 return 0
fi fi
exact_cmd_match="^(${allow_exact_list})$"; exact_cmd_match="^(${allow_exact_list})$";
if printf '%s' "$SSH_ORIGINAL_COMMAND" | grep -E "$exact_cmd_match" >/dev/null 2>/dev/null; then if printf '%s' "${SSH_ORIGINAL_COMMAND}" | grep -E "${exact_cmd_match}" >/dev/null 2>/dev/null; then
return 0 return 0
fi fi
local formatted_restrict_path_list="$(printf '%s' "$restrict_path_list" | sed 's/|/", "/g')" local formatted_restrict_path_list="$(printf '%s' "${restrict_path_list}" | sed 's/|/", "/g')"
reject_and_die "disallowed command${restrict_path_list:+ (restrict-path: \"$formatted_restrict_path_list\")}" reject_and_die "disallowed command${restrict_path_list:+ (restrict-path: \"${formatted_restrict_path_list}\")}"
} }
# check for "--sudo" option before processing other options # check for "--sudo" option before processing other options
sudo_prefix= sudo_prefix=
for key in "$@"; do for key in "$@"; do
[ "$key" = '--sudo' ] && sudo_prefix='sudo -n ' if [ "${key}" = '--sudo' ]; then
[ "$key" = '--doas' ] && sudo_prefix='doas -n ' sudo_prefix='sudo -n '
fi
if [ "${key}" = '--doas' ]; then
sudo_prefix='doas -n '
fi
done done
while [ "$#" -ge 1 ]; do while [ "$#" -ge 1 ]; do
key="$1" key="$1"
case "$key" in case "${key}" in
-l|--log) -l|--log)
enable_log=1 enable_log=1
;; ;;
@ -165,7 +177,7 @@ while [ "$#" -ge 1 ]; do
;; ;;
*) *)
printf 'ERROR: ssh_filter_btrbk.sh: failed to parse command line option: %s\n' "$key" 1>&2 printf 'ERROR: ssh_filter_btrbk.sh: failed to parse command line option: %s\n' "${key}" >&2
exit 2 exit 2
;; ;;
esac esac
@ -185,7 +197,7 @@ allow_list="${allow_list#\|}"
allow_exact_list="${allow_exact_list#\|}" allow_exact_list="${allow_exact_list#\|}"
restrict_path_list="${restrict_path_list#\|}" restrict_path_list="${restrict_path_list#\|}"
case "$SSH_ORIGINAL_COMMAND" in case "${SSH_ORIGINAL_COMMAND}" in
*\.\./*) reject_and_die 'directory traversal' ;; *\.\./*) reject_and_die 'directory traversal' ;;
*\$*) reject_and_die 'unsafe character "$"' ;; *\$*) reject_and_die 'unsafe character "$"' ;;
*\&*) reject_and_die 'unsafe character "&"' ;; *\&*) reject_and_die 'unsafe character "&"' ;;
@ -195,7 +207,7 @@ case "$SSH_ORIGINAL_COMMAND" in
*\<*) reject_and_die 'unsafe character "<"' ;; *\<*) reject_and_die 'unsafe character "<"' ;;
*\>*) reject_and_die 'unsafe character ">"' ;; *\>*) reject_and_die 'unsafe character ">"' ;;
*\`*) reject_and_die 'unsafe character "`"' ;; *\`*) reject_and_die 'unsafe character "`"' ;;
*\|*) [ -n "$allow_compress" ] || [ -n "$allow_rate_limit" ] || [ -n "$allow_stream_buffer" ] || reject_and_die 'unsafe character "|"' ;; *\|*) [ -n "${allow_compress}" ] || [ -n "${allow_rate_limit}" ] || [ -n "${allow_stream_buffer}" ] || reject_and_die 'unsafe character "|"' ;;
esac esac
reject_filtered_cmd reject_filtered_cmd