Skip to content

Instantly share code, notes, and snippets.

@lo48576
Last active August 6, 2018 04:49
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 lo48576/d120d139e091f2338d35e1de85f9315f to your computer and use it in GitHub Desktop.
Save lo48576/d120d139e091f2338d35e1de85f9315f to your computer and use it in GitHub Desktop.
[unmaintained, NOT SAFE] rrsync replacement without perl, useful for limited environment like CoreOS
#!/bin/sh
# Copyright (C) 2004 Joe Smith <js-cgi@inwap.com>
# Copyright (C) 2004-2015 Wayne Davison <wayned@samba.org>
# Copyright (C) 2016-2018 YOSHIOKA Takuma <tashioka.256@gmail.com>
#
# 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/>.
# 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}/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"
}
# 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.
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 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
shift
done
# Arguments are safe!
# Execute rsync.
exec $SSH_ORIGINAL_COMMAND
@dbishop
Copy link

dbishop commented Nov 2, 2016

Hi! I was wondering if this code was open source, and if so, under what license you like to share it?

Thanks!
Darrell

@lo48576
Copy link
Author

lo48576 commented Jun 27, 2017

@dbishop
This script is based on rrsync distributed in rsync package by samba project and it is licensed under GPLv3 (See rsync's license).
I don't understand GPLv3 very well, but I think rrsync.sh script should inherit GPL license.

Sorry for my late reply.

@michaelherger
Copy link

michaelherger commented Apr 18, 2018

Please note that this script is NOT safe without further modification. rsync 3 introduced the --protect-args (-s) parameter which would no longer send the path as part of the rsync command line arguments. With that parameter set this script would accept any path.

The original script explicitly disallows the -s parameter. See https://git.samba.org/?p=rsync.git;a=commitdiff;h=2e8259bb0bc5ffe64df9075ef8f1e8050caf951c.

It also ignores any of the long parameters.

@lo48576
Copy link
Author

lo48576 commented Aug 6, 2018

Thank you, noted that the script is unmaintained (at least now).
I might try to fix the problem if I can understand the problem correctly, but it is not guaranteed...

The code is licensed under GPLv3, feel free to modify and distribute the script if you want!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment