Files
rsync/support/rrsync.1.md
T
Filipe Casal c3abc6c095 rrsync: protect no-overwrite auxiliary paths
--ignore-existing protects the live transfer destination, but three
peer-selectable options reach other existing objects inside the
restricted directory: --log-file appends to one, --partial-dir consumes
and then renames or unlinks one, and --delay-updates does the same
through its implicit .~tmp~ directory.  Refuse all three under
-no-overwrite.

Refusal rather than confinement, because confining these paths does not
help: keeping the --log-file append inside the tree still appends to an
existing file, and for the partial directories the peer controls both
the directory and the transferred basename, so a collision is always
reachable.  A pre-exec emptiness check would be raceable.  The cost is
that a push naming --partial-dir on the remote receiver, or using
--delay-updates, is now refused for a -no-overwrite account.

Each regression drives the option through a wrapper WITHOUT
-no-overwrite as well, and requires that to be accepted.  Without that
control the tests cannot tell "refused under -no-overwrite" from
"refused always", and would still pass if the options were disabled for
every rrsync deployment -- verified by making the refusal unconditional,
which the controls then catch.

The wrapper is handed a shim rather than RSYNC directly: RSYNC is a
multi-word command whenever the runner forces --protocol=N, and rrsync
execlp()s its RSYNC as a single executable name, so every one of these
tests died before reaching the policy under test.  A fleet run caught it
on the protocol columns of three targets.

Backup mode belongs in the same set.  Publishing a backup onto a name
that already exists deletes what is there (backup.c make_backup()), and
deleting a file backs it up first (delete.c), so a --delete of an
unrelated file can land on a protected name -- overwriting a file that
--ignore-existing was holding, with rc=0 and no diagnostic.  Disable -b
and --backup-dir.  --suffix is left enabled: with both of those refused
nothing can turn backups on, so it is inert.

The short option must be disabled before short_no_arg_re is built, since
a stock client sends b inside the remote short-option bundle and the
regex is snapshotted there; the whole -no-overwrite block therefore
moves up beside the other policy gates rather than sitting after the
chdir.  Its regression drives the collision through a wrapper without
-no-overwrite, passing --ignore-existing by hand, which both proves the
refusal is conditional and shows the primitive defeating the very
protection -no-overwrite forces.

rrsync.1.md now states what -no-overwrite costs: no explicit
--partial-dir, no --delay-updates, no server-side --log-file, no backups.
2026-07-31 13:18:39 +10:00

6.4 KiB

NAME

rrsync - a script to setup restricted rsync users via ssh logins

SYNOPSIS

rrsync [-ro|-wo] [-munge] [-absolute] [-no-del] [-no-lock] [-no-overwrite] DIR

The single non-option argument specifies the restricted DIR to use. It can be relative to the user's home directory or an absolute path.

The online version of this manpage (that includes cross-linking of topics) is available at https://download.samba.org/pub/rsync/rrsync.1.

DESCRIPTION

A user's ssh login can be restricted to only allow the running of an rsync transfer in one of two easy ways:

  • forcing the running of the rrsync script
  • forcing the running of an rsync daemon-over-ssh command.

Both of these setups use a feature of ssh that allows a command to be forced to run instead of an interactive shell. However, if the user's home shell is bash, please see BASH SECURITY ISSUE for a potential issue.

To use the rrsync script, edit the user's ~/.ssh/authorized_keys file and add a prefix like one of the following (followed by a space) in front of each ssh-key line that should be restricted:

command="rrsync DIR"
command="rrsync -ro DIR"
command="rrsync -munge -no-del DIR"

Then, ensure that the rrsync script has your desired option restrictions. You may want to copy the script to a local bin dir with a unique name if you want to have multiple configurations. One or more rrsync options can be specified prior to the DIR if you want to further restrict the transfer.

To use an rsync daemon setup, edit the user's ~/.ssh/authorized_keys file and add a prefix like one of the following (followed by a space) in front of each ssh-key line that should be restricted:

command="rsync --server --daemon ."
command="rsync --server --daemon --config=/PATH/TO/rsyncd.conf ."

Then, ensure that the rsyncd.conf file is created with one or more module names with the appropriate path and option restrictions. If rsync's --config option is omitted, it defaults to ~/rsyncd.conf. See the rsyncd.conf(5) manpage for details of how to configure an rsync daemon.

When using rrsync, there can be just one restricted dir per authorized key. A daemon setup, on the other hand, allows multiple module names inside the config file, each one with its own path setting.

The remainder of this manpage is dedicated to using the rrsync script.

OPTIONS

  1. -ro

    Allow only reading from the DIR. Implies -no-del and -no-lock.

  2. -wo

    Allow only writing to the DIR.

  3. -munge

    Enable rsync's --munge-links on the server side.

  4. -absolute

    Allow file-transfer arguments to name the restricted directory using its absolute server path. For example, with rrsync -absolute /path/to/root, the transfer arg /path/to/root/dir1 is accepted as an alias for dir1.

  5. -no-del

    Disable rsync's --delete* and --remove* options.

  6. -no-lock

    Avoid the single-run (per-user) lock check. Useful with -munge.

  7. -no-overwrite

    Enforce --ignore-existing on the server. Prevents overwriting existing files when the server is the receiver.

    Because --ignore-existing protects only the file being transferred, this also refuses the options that can reach a different existing file in the restricted dir: --log-file, --partial-dir, --delay-updates, and backup mode (-b, --backup-dir, whose published backup replaces whatever already occupies the backup name). Resumable uploads with an explicit --partial-dir, --delay-updates, and server-side logging are therefore unavailable under this option.

  8. -help, -h

    Output this help message and exit.

SECURITY RESTRICTIONS

The rrsync script validates the path arguments it is sent to try to restrict them to staying within the specified DIR.

The rrsync script rejects rsync's --copy-links option (by default) so that a copy cannot dereference a symlink within the DIR to get to a file outside the DIR.

The rrsync script rejects rsync's --protect-args (-s) option because it would allow options to be sent to the server-side that the script cannot check. If you want to support --protect-args, use a daemon-over-ssh setup.

The rrsync script accepts just a subset of rsync's options that the real rsync uses when running the server command. A few extra convenience options are also included to help it to interact with BackupPC and accept some convenient user overrides.

The script (or a copy of it) can be manually edited if you want it to customize the option handling.

BASH SECURITY ISSUE

If your users have bash set as their home shell, bash may try to be overly helpful and ensure that the user's login bashrc files are run prior to executing the forced command. This can be a problem if the user can somehow update their home bashrc files, perhaps via the restricted copy, a shared home directory, or something similar.

One simple way to avoid the issue is to switch the user to a simpler shell, such as dash. When choosing the new home shell, make sure that you're not choosing bash in disguise, as it is unclear if it avoids the security issue.

Another potential fix is to ensure that the user's home directory is not a shared mount and that they have no means of copying files outside of their restricted directories. This may require you to force the enabling of symlink munging on the server side.

A future version of openssh may have a change to the handling of forced commands that allows it to avoid using the user's home shell.

EXAMPLES

The ~/.ssh/authorized_keys file might have lines in it like this:

command="rrsync client/logs" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAzG...
command="rrsync -ro results" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAmk...

FILES

~/.ssh/authorized_keys

SEE ALSO

rsync(1), rsyncd.conf(5)

VERSION

This manpage is current for version @VERSION@ of rsync.

CREDITS

rsync is distributed under the GNU General Public License. See the file COPYING for details.

An rsync web site is available at https://rsync.samba.org/ and its github project is https://github.com/RsyncProject/rsync.

AUTHOR

The original rrsync perl script was written by Joe Smith. Many people have later contributed to it. The python version was created by Wayne Davison.