Skip to content

Instantly share code, notes, and snippets.

@micw
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save micw/339fcf01b4c99c728080 to your computer and use it in GitHub Desktop.
Save micw/339fcf01b4c99c728080 to your computer and use it in GitHub Desktop.
#!/bin/bash
# This script can be used as wrapper for rsync in authorized_keys. It restricts rsync the following way:
# - restrict target directory to be under /backups/backup-rsync-push/${1}/target/ where $1 is an argument from authorized_keys
# - restrict target directory to be exactly 1 level below this directory
# - restrict flags
# - restrict arguments
# - force --fake-super argument
err() {
echo "--------------------------------------------------------------------" >&2
echo "ERROR ON REMOTE SIDE:" >&2
echo "$*" >&2
echo "--------------------------------------------------------------------" >&2
}
if [ $# -ne 1 ]; then
err "CLIENT not set in authorized_keys"
exit 1
fi
DIR="/backups/backup-rsync-push/${1}/target/"
if [ ! -d "$DIR" ]; then
err "Client dir not found."
exit 1
fi
ARGS=( $SSH_ORIGINAL_COMMAND )
ARG_COUNT="${#ARGS[@]}"
shopt -s extglob
do_rsync() {
CMD="/usr/bin/rsync --fake-super --server"
if [ $ARG_COUNT -lt 3 ]; then
err "Supplied rsync command had too few args"
exit 1
fi
ARG_N1="${ARGS[$(( ARG_COUNT - 2 ))]}"
if [ "$ARG_N1" != "." ]; then
err "the arg before the last arg must be a dot, not $ARG_N1"
exit 1
fi
PATH="${ARGS[$(( ARG_COUNT - 1 ))]}"
if ! [[ "$PATH" =~ ^[a-zA-Z0-9_-]+/$ ]]; then
err "The last arg must be a path that matches [a-zA-Z0-9_-]+/ , not $PATH"
exit 1
fi
for ARG in "${ARGS[@]:1:$(( ARG_COUNT - 3 ))}"; do
case $ARG in
-+(v|l|o|g|D|t|p|A|X|r|e.|i)Lsf )
# allowed flags. requires "shopt -s extglob" to be set outside this function
CMD="$CMD $ARG"
;;
"--sender"|"--delete-during"|"--numeric-ids")
# added to command
CMD="$CMD $ARG"
;;
"--fake-super"|"--server")
# silently ignored
;;
*)
err "rsync arg not allowed: $ARG"
exit 1
;;
esac
done
TARGET="${DIR}${PATH}"
$CMD . "${TARGET}"
exit 1
}
case "${ARGS[0]}" in
"rsync")
do_rsync
;;
*)
err "Command denied: $SSH_ORIGINAL_COMMAND"
exit 1
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment