Last active
August 6, 2018 04:49
-
-
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
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/>. | |
# 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 |
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
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.