-
-
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 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 | |
# Copyright (C) 2004 Joe Smith <[email protected]> | |
# Copyright (C) 2004-2015 Wayne Davison <[email protected]> | |
# Copyright (C) 2016-2018 YOSHIOKA Takuma <[email protected]> | |
# | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
# see https://www.samba.org/ftp/unpacked/rsync/support/rrsync for reference | |
# bash version: https://gist.github.com/lo48576/d120d139e091f2338d35e1de85f9315f | |
# This script is based on `support/rrsync` perl script in rsync-3.1.2. | |
USAGE="Use command=\"$0 [-ro|-wo] SUBDIR\" | |
in front of lines in ${HOME}/.ssh/authorized_keys" | |
LOGFILE="${HOME}/logs/rrsync.log" | |
CMDNAME="$0" | |
# Log the given 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" | |
} | |
#debug ">>>>>>>>>>>>>>>>>>>>>>>>>" | |
#debug "$SSH_ORIGINAL_COMMAND" | |
# 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" || die 'Failed to change current directory' | |
# 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. | |
AM_SENDER=0 | |
if echo "$SSH_ORIGINAL_COMMAND" | grep -sqE '^rsync\s+--server\s+--sender\s' ; then | |
AM_SENDER=1 | |
# 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: | |
CHECK_TYPE=0 | |
while [ $# -ge 1 ] ; do | |
# Collapse continuous slashes in the argument. | |
ARG="$(echo "$1" | sed -e 's!///*!/!g')" | |
# Ensure the argument has no ".." as path component. | |
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 | |
# values copied from https://www.samba.org/ftp/unpacked/rsync/support/rrsync -> $short_no_arg less $short_disabled | |
if echo "$ARG" | grep -sqE '^-([ACDEHIJKLORSWXbcdgklmnoprtuvxyz]*s[ACDEHIJKLORSWXbcdgklmnoprtuvxyz]*(e\d*\.\w*)?$)'; then | |
debug "command line: ${SSH_ORIGINAL_COMMAND}\ndangerous argument: --protect-args / -s" | |
die "--protect-args is not allowed as we need to inspect the target path" | |
fi | |
shift | |
done | |
#debug "$SSH_ORIGINAL_COMMAND" | |
# Arguments are safer! | |
# Execute rsync. | |
exec $SSH_ORIGINAL_COMMAND | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment