From 177a33ec1a54227da17479318a6b7728ce9b3d96 Mon Sep 17 00:00:00 2001 From: SebMtn <102696928+SebMtn@users.noreply.github.com> Date: Sat, 2 May 2026 17:47:28 +0100 Subject: [PATCH] rrsync: add -absolute argument to support calling rsync with absolute path Signed-off-by: SebMtn <102696928+SebMtn@users.noreply.github.com> --- support/rrsync | 14 +++++++++----- support/rrsync.1.md | 8 +++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/support/rrsync b/support/rrsync index 56389c52c..d69c17cfc 100755 --- a/support/rrsync +++ b/support/rrsync @@ -302,12 +302,12 @@ def validated_arg(opt, arg, typ=3, wild=False): if arg.startswith('./'): arg = arg[1:] arg = arg.replace('//', '/') - arg = arg.lstrip('/') + is_absolute_arg = args.absolute and opt == 'arg' and args.dir != '/' and (arg == args.dir or arg.startswith(args.dir_slash)) + if not is_absolute_arg: + arg = arg.lstrip('/') if args.dir != '/': if HAS_DOT_DOT_RE.search(arg): die("do not use .. in", opt, "(anchor the path at the root of your restricted dir)") - if arg.startswith('/'): - arg = args.dir + arg if wild: got = glob.glob(arg) @@ -328,12 +328,15 @@ def validated_arg(opt, arg, typ=3, wild=False): arg = arg[:-2] real_arg = os.path.realpath(arg) if arg != real_arg and not real_arg.startswith(args.dir_slash): - die('unsafe arg:', orig_arg, [arg, real_arg]) + if not (is_absolute_arg and real_arg == args.dir): + die('unsafe arg:', orig_arg, [arg, real_arg]) if arg_has_trailing_slash: arg += '/' elif arg_has_trailing_slash_dot: arg += '/.' - if opt == 'arg' and arg.startswith(args.dir_slash): + if is_absolute_arg and arg == args.dir: + arg = '.' + elif opt == 'arg' and arg.startswith(args.dir_slash): arg = arg[args.dir_slash_len:] if arg == '': arg = '.' @@ -372,6 +375,7 @@ if __name__ == '__main__': only_group.add_argument('-ro', action='store_true', help="Allow only reading from the DIR. Implies -no-del and -no-lock.") only_group.add_argument('-wo', action='store_true', help="Allow only writing to the DIR.") arg_parser.add_argument('-munge', action='store_true', help="Enable rsync's --munge-links on the server side.") + arg_parser.add_argument('-absolute', action='store_true', help="Allow transfer args to use absolute server paths under DIR.") arg_parser.add_argument('-no-del', action='store_true', help="Disable rsync's --delete* and --remove* options.") arg_parser.add_argument('-no-lock', action='store_true', help="Avoid the single-run (per-user) lock check.") arg_parser.add_argument('-no-overwrite', action='store_true', help="Prevent overwriting existing files by enforcing --ignore-existing") diff --git a/support/rrsync.1.md b/support/rrsync.1.md index 09b2f2822..a3ee858dd 100644 --- a/support/rrsync.1.md +++ b/support/rrsync.1.md @@ -5,7 +5,7 @@ rrsync - a script to setup restricted rsync users via ssh logins ## SYNOPSIS ``` -rrsync [-ro|-wo] [-munge] [-no-del] [-no-lock] [-no-overwrite] DIR +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 @@ -77,6 +77,12 @@ The remainder of this manpage is dedicated to using the rrsync script. Enable rsync's [`--munge-links`](rsync.1#opt) on the server side. +0. `-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`. + 0. `-no-del` Disable rsync's `--delete*` and `--remove*` options.