You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

97 lines
3.2 KiB

#!/bin/bash
## Note that the shebang is not used, but it's the login shell that
## will execute this command.
exname=$(basename "$0")
mkdir -p /var/log/rsync
LOG="/var/log/rsync/$exname.log"
ssh_connection=(${SSH_CONNECTION})
SSH_SOURCE_IP="${ssh_connection[0]}:${ssh_connection[1]}"
log() {
printf "%s [%s] %s - %s\n" \
"$(date --rfc-3339=seconds)" "$$" "$SSH_SOURCE_IP" "$*" \
>> "$LOG"
}
log "NEW BACKUP CONNECTION"
if [ -z "$1" ] || ! [[ "$1" =~ ^[a-zA-Z0-9._-]+$ ]]; then
log "INVALID SETUP, ARG IS: '$1'"
echo "Your command has been rejected. Contact administrator."
exit 1
fi
ident="$1"
log "IDENTIFIED AS $ident"
reject() {
log "REJECTED: $SSH_ORIGINAL_COMMAND"
# echo "ORIG: $SSH_ORIGINAL_COMMAND" >&2
echo "Your command has been rejected and reported to sys admin." >&2
exit 1
}
sudo /usr/local/sbin/ssh-update-keys
if [[ "$SSH_ORIGINAL_COMMAND" =~ [\&\(\{\;\<\>\`\$\}] ]]; then
log "BAD CHARS DETECTED"
# echo "Bad chars: $SSH_ORIGINAL_COMMAND" >&2
reject
fi
if [[ "$SSH_ORIGINAL_COMMAND" =~ ^"rsync --server -"[vnloHgDtpArRzCeiLsfx\.]+(" --"[a-z=%-]+|" --partial-dir .rsync-partial")*" . /var/mirror/$ident"$ ]]; then
log "ACCEPTED BACKUP COMMAND: $SSH_ORIGINAL_COMMAND"
## Interpret \ to allow passing spaces (want to avoid possible issue with \n)
#read -a ssh_args <<< "${SSH_ORIGINAL_COMMAND}"
ssh_args=(${SSH_ORIGINAL_COMMAND})
exec sudo "${ssh_args[@]::3}" \
"--log-file=/var/log/rsync/target_$1_rsync.log" \
"--log-file-format=%i %o %f %l %b" \
"${ssh_args[@]:3}"
elif [[ "$SSH_ORIGINAL_COMMAND" =~ ^"rsync --server --sender -"[vnloHgDtpArRzCeiLsfx\.]+(" --"[a-z=%-]+|" --partial-dir .rsync-partial")*" . /var/mirror/$ident"(|/.*)$ ]]; then
## Interpret \ to allow passing spaces (want to avoid possible issue with \n)
#read -a ssh_args <<< "${SSH_ORIGINAL_COMMAND}"
ssh_args=(${SSH_ORIGINAL_COMMAND})
last_arg="${ssh_args[@]: -1:1}"
if ! new_path=$(realpath "$last_arg" 2>/dev/null); then
log "FINAL PATH INVALID"
reject
fi
if [[ "$new_path" != "$last_arg" ]] &&
[[ "$new_path" != "/var/mirror/$ident/"* ]] &&
[[ "$new_path" != "/var/mirror/$ident" ]]; then
log "FINAL PATH SUSPICIOUS"
reject
fi
log "ACCEPTED RECOVER COMMAND: $SSH_ORIGINAL_COMMAND"
exec sudo "${ssh_args[@]}"
elif [[ "$SSH_ORIGINAL_COMMAND" =~ ^"request-recovery-key"$ ]]; then
log "ACCEPTED RECOVERY KEY REQUEST: $SSH_ORIGINAL_COMMAND"
exec sudo /usr/local/sbin/request-recovery-key "" "$ident"
else
log "REFUSED COMMAND AS IT DOESN'T MATCH ANY EXPECTED COMMAND"
reject
fi
## For other commands, like `find` or `md5`, that could be used to
## challenge the backups and check that archive is actually
## functional, I would suggest to write a simple command that takes no
## arguments, so as to prevent allowing wildcards or suspicious
## contents. Letting `find` go through is dangerous for instance
## because of the `-exec`. And path traversal can be done also when
## allowing /my/path/* by using '..'. This is why a fixed purpose
## embedded executable will be much simpler to handle, and to be honest
## we don't need much more.