"munge symlinks" parameter.
extern int preserve_xattrs;
extern int kluge_around_eof;
extern int daemon_over_rsh;
+extern int munge_symlinks;
extern int sanitize_paths;
extern int numeric_ids;
extern int filesfrom_fd;
char *auth_user;
int read_only = 0;
int module_id = -1;
-int munge_symlinks = 0;
struct chmod_mode_struct *daemon_chmod_modes;
/* module_dirlen is the length of the module_dir string when in daemon
char *name = lp_name(i);
int use_chroot = lp_use_chroot(i);
int ret, pre_exec_fd = -1;
+ int save_munge_symlinks;
pid_t pre_exec_pid = 0;
char *request = NULL;
munge_symlinks = !use_chroot || module_dirlen;
if (munge_symlinks) {
STRUCT_STAT st;
- if (do_stat(SYMLINK_PREFIX, &st) == 0 && S_ISDIR(st.st_mode)) {
- rprintf(FLOG, "Symlink munging is unsupported when a %s directory exists.\n",
- SYMLINK_PREFIX);
+ char prefix[SYMLINK_PREFIX_LEN]; /* NOT +1 ! */
+ strlcpy(prefix, SYMLINK_PREFIX, sizeof prefix); /* trim the trailing slash */
+ if (do_stat(prefix, &st) == 0 && S_ISDIR(st.st_mode)) {
+ rprintf(FLOG, "Symlink munging is unsafe when a %s directory exists.\n",
+ prefix);
io_printf(f_out, "@ERROR: daemon security issue -- contact admin\n", name);
exit_cleanup(RERR_UNSUPPORTED);
}
read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request);
orig_argv = argv;
+ save_munge_symlinks = munge_symlinks;
+
reset_output_levels(); /* future verbosity is controlled by client options */
ret = parse_arguments(&argc, (const char ***) &argv);
if (protect_args && ret) {
} else
orig_early_argv = NULL;
+ munge_symlinks = save_munge_symlinks; /* The client mustn't control this. */
+
if (pre_exec_pid) {
err_msg = finish_pre_exec(pre_exec_pid, pre_exec_fd, request,
orig_early_argv, orig_argv);
int keep_partial = 0;
int safe_symlinks = 0;
int copy_unsafe_links = 0;
+int munge_symlinks = 0;
int size_only = 0;
int daemon_bwlimit = 0;
int bwlimit = 0;
rprintf(F," -L, --copy-links transform symlink into referent file/dir\n");
rprintf(F," --copy-unsafe-links only \"unsafe\" symlinks are transformed\n");
rprintf(F," --safe-links ignore symlinks that point outside the source tree\n");
+ rprintf(F," --munge-links munge symlinks to make them safer (but unusable)\n");
rprintf(F," -k, --copy-dirlinks transform symlink to a dir into referent dir\n");
rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n");
rprintf(F," -H, --hard-links preserve hard links\n");
{"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 },
{"copy-unsafe-links",0, POPT_ARG_NONE, ©_unsafe_links, 0, 0, 0 },
{"safe-links", 0, POPT_ARG_NONE, &safe_symlinks, 0, 0, 0 },
+ {"munge-links", 0, POPT_ARG_VAL, &munge_symlinks, 1, 0, 0 },
+ {"no-munge-links", 0, POPT_ARG_VAL, &munge_symlinks, 0, 0, 0 },
{"copy-dirlinks", 'k', POPT_ARG_NONE, ©_dirlinks, 0, 0, 0 },
{"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 },
{"hard-links", 'H', POPT_ARG_NONE, 0, 'H', 0, 0 },
need_messages_from_generator = 1;
}
+ if (munge_symlinks && !am_daemon) {
+ STRUCT_STAT st;
+ char prefix[SYMLINK_PREFIX_LEN]; /* NOT +1 ! */
+ strlcpy(prefix, SYMLINK_PREFIX, sizeof prefix); /* trim the trailing slash */
+ if (do_stat(prefix, &st) == 0 && S_ISDIR(st.st_mode)) {
+ rprintf(FERROR, "Symlink munging is unsafe when a %s directory exists.\n",
+ prefix);
+ exit_cleanup(RERR_UNSUPPORTED);
+ }
+ }
+
if (sanitize_paths) {
int i;
for (i = argc; i-- > 0; )
extern int am_server;
extern int blocking_io;
extern int filesfrom_fd;
+extern int munge_symlinks;
extern mode_t orig_umask;
extern char *logfile_name;
extern int remote_option_cnt;
am_sender = 0;
am_server = 1;
filesfrom_fd = -1;
+ munge_symlinks = 0; /* Each side needs its own option. */
chmod_modes = NULL; /* Let the sending side handle this. */
/* Let the client side handle this. */
#define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock"
#define URL_PREFIX "rsync://"
-#define SYMLINK_PREFIX "/rsyncd-munged/"
+#define SYMLINK_PREFIX "/rsyncd-munged/" /* This MUST have a trailing slash! */
#define SYMLINK_PREFIX_LEN ((int)sizeof SYMLINK_PREFIX - 1)
#define BACKUP_SUFFIX "~"
-L, --copy-links transform symlink into referent file/dir
--copy-unsafe-links only "unsafe" symlinks are transformed
--safe-links ignore symlinks that point outside the tree
+ --munge-links munge symlinks to make them safer
-k, --copy-dirlinks transform symlink to dir into referent dir
-K, --keep-dirlinks treat symlinked dir on receiver as dir
-H, --hard-links preserve hard links
also ignored. Using this option in conjunction with bf(--relative) may
give unexpected results.
+dit(bf(--munge-links)) This option tells rsync to (1) modify all symlinks on
+the receiving side in a way that makes them unusable but recoverable (see
+below), or (2) to unmunge symlinks on the sending side that had been stored in
+a munged state. This is useful if you don't quite trust the source of the data
+to not try to slip in a symlink to a unexpected place.
+
+The way rsync disables the use of symlinks is to prefix each one with the
+string "/rsyncd-munged/". This prevents the links from being used as long as
+that directory does not exist. When this option is enabled, rsync will refuse
+to run if that path is a directory or a symlink to a directory.
+
+The option only affects the client side of the transfer, so if you need it to
+affect the server, specify it via bf(--remote-option). (Note that in a local
+transfer, the client side is the sender.)
+
+This option has no affect on a daemon, since the daemon configures whether it
+wants munged symlinks via its "munge symlinks" parameter. See also the
+"munge-symlinks" perl script in the support directory of the source code.
+
dit(bf(-k, --copy-dirlinks)) This option causes the sending side to treat
a symlink to a directory as though it were a real directory. This is
useful if you don't want symlinks to non-directories to be affected, as
resources.
dit(bf(munge symlinks)) This parameter tells rsync to modify
-all incoming symlinks in a way that makes them unusable but recoverable
-(see below). This should help protect your files from user trickery when
+all symlinks in the same way as the (non-daemon-affecting)
+bf(--munge-links) command-line option (using a method described below).
+This should help protect your files from user trickery when
your daemon module is writable. The default is disabled when "use chroot"
is on and the inside-chroot path is "/", otherwise it is enabled.
a user can't try to create it.
Note: rsync makes no attempt to verify that any pre-existing symlinks in
-the hierarchy are as safe as you want them to be. If you setup an rsync
+the module's hierarchy are as safe as you want them to be (unless, of
+course, it just copied in the whole hierarchy). If you setup an rsync
daemon on a new area or locally add symlinks, you can manually protect your
symlinks from being abused by prefixing "/rsyncd-munged/" to the start of
every symlink's value. There is a perl script in the support directory