-
-
Save michaelherger/63f29db06a755e42a92f8f00b3a12d45 to your computer and use it in GitHub Desktop.
rrsync replacement without perl, useful for limited environment like CoreOS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
USAGE="Use command=\"$0 [-ro|-wo] SUBDIR\" | |
in front of lines in ${HOME}/.ssh/authorized_keys" | |
LOGFILE="${HOME}/rsync.log" | |
CMDNAME="$0" | |
# Die with the given error message. | |
die() { | |
DATETIME="$(LANG=C date '+%F %T')" | |
echo "[$DATETIME] $CMDNAME: $1" >>"$LOGFILE" | |
echo >>"$LOGFILE" | |
exit 2 | |
} | |
# Die with the given error message. | |
debug() { | |
DATETIME="$(LANG=C date '+%F %T')" | |
echo "[$DATETIME][DEBUG] $1" | tr '\n' '\0' | sed -e 's/\0/\n[DEBUG]'"$DATETIME"'/g' >>"$LOGFILE" | |
} | |
# Get "only" option. | |
# It would be "w" for `-wo` (write only), "r" for `-ro` (read only), or empty string (neither `-ro` nor `-wo`). | |
ONLY="" | |
while [ "x$1" = "x-ro" -o "x$1" = "x-wo" ] ; do | |
if [ "x$1" = "x-ro" ] ; then | |
if [ "x$ONLY" = "xw" ] ; then | |
die "the -ro and -wo options conflict." | |
fi | |
ONLY="r" | |
shift | |
else | |
if [ "x$ONLY" = "xr" ] ; then | |
die "the -ro and -wo options conflict." | |
fi | |
ONLY="w" | |
shift | |
fi | |
done | |
# Now "$ONLY" has "r", "w" or "". | |
# Ensure the subdirectory is given. | |
if [ $# -lt 1 ] ; then | |
die "No subdirectory specified.\n${USAGE}" | |
fi | |
ALLOWED_DIR="$1" | |
cd "$ALLOWED_DIR" | |
# Ensure the rrsync is invoked via sshd. | |
if [ -z "$SSH_ORIGINAL_COMMAND" ] ; then | |
die "Not invoked via sshd.\n${USAGE}" | |
fi | |
# Ensure the rrsync is invoked in server mode via remote rsync. | |
if ! echo "$SSH_ORIGINAL_COMMAND" | grep -sqE '^rsync\s+--server' ; then | |
die "SSH_ORIGINAL_COMMAND='$SSH_ORIGINAL_COMMAND' is not 'rsync --server' or '--server' is not specified first." | |
fi | |
# Check whether the rsync server should be sender or receiver. | |
if echo "$SSH_ORIGINAL_COMMAND" | grep -sqE '^rsync\s+--server\s+--sender\s' ; then | |
# The local rsync is sender mode, i.e. files should be sent from local to remote. | |
if [ "x$ONLY" = "xw" ] ; then | |
die "Sending to read-only server not allowed." | |
fi | |
else | |
# The local rsync is receiver mode, i.e. files should be sent from remote to local. | |
if [ "x$ONLY" = "xr" ] ; then | |
die "Reading to write-only server not allowed." | |
fi | |
fi | |
# Command line sanity check. | |
set -f | |
set -- $SSH_ORIGINAL_COMMAND | |
# For each argument: | |
while [ $# -ge 1 ] ; do | |
# Collapse continuous slashes in the argument. | |
ARG="$(echo "$1" | sed -e 's!///*!/!g')" | |
# Ensure the argument has no ".." as argument. | |
if echo "$ARG" | grep -sqE '(^(-[a-zA-Z0-9-]+=?)?|/)\.\.(/|$)' ; then | |
debug "command line: ${SSH_ORIGINAL_COMMAND}\ndangerous argument: `$1`" | |
die "Do not use .. in option argument, anchor the path at the root of your restricted dir." | |
fi | |
# Ensure the argument has no absolute path. | |
if echo "$ARG" | grep -sq '^/' ; then | |
debug "command line: ${SSH_ORIGINAL_COMMAND}\ndangerous argument: `$1`" | |
die "Do not use absolute path in argument, anchor the path at the root of your restricted dir." | |
fi | |
shift | |
done | |
# Arguments are safe! | |
# Execute rsync. | |
exec $SSH_ORIGINAL_COMMAND |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment