1 This patch adds the --munge-links option, which works like the daemon's
2 "munge symlinks" parameter.
4 To use this patch, run these commands for a successful build:
6 patch -p1 <patches/remote-option.diff
7 patch -p1 <patches/munge-links.diff
8 ./configure (optional if already run)
11 based-on: patch/b3.0.x/remote-option
12 diff --git a/clientserver.c b/clientserver.c
15 @@ -37,6 +37,7 @@ extern int ignore_errors;
16 extern int preserve_xattrs;
17 extern int kluge_around_eof;
18 extern int daemon_over_rsh;
19 +extern int munge_symlinks;
20 extern int sanitize_paths;
21 extern int numeric_ids;
22 extern int filesfrom_fd;
23 @@ -64,7 +65,6 @@ extern iconv_t ic_send, ic_recv;
27 -int munge_symlinks = 0;
28 struct chmod_mode_struct *daemon_chmod_modes;
30 /* module_dirlen is the length of the module_dir string when in daemon
31 @@ -419,6 +419,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
32 char *name = lp_name(i);
33 int use_chroot = lp_use_chroot(i);
34 int ret, pre_exec_fd = -1;
35 + int save_munge_symlinks;
36 pid_t pre_exec_pid = 0;
39 @@ -694,9 +695,11 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
40 munge_symlinks = !use_chroot || module_dirlen;
43 - if (do_stat(SYMLINK_PREFIX, &st) == 0 && S_ISDIR(st.st_mode)) {
44 - rprintf(FLOG, "Symlink munging is unsupported when a %s directory exists.\n",
46 + char prefix[SYMLINK_PREFIX_LEN]; /* NOT +1 ! */
47 + strlcpy(prefix, SYMLINK_PREFIX, sizeof prefix); /* trim the trailing slash */
48 + if (do_stat(prefix, &st) == 0 && S_ISDIR(st.st_mode)) {
49 + rprintf(FLOG, "Symlink munging is unsafe when a %s directory exists.\n",
51 io_printf(f_out, "@ERROR: daemon security issue -- contact admin\n", name);
52 exit_cleanup(RERR_UNSUPPORTED);
54 @@ -756,6 +759,8 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
55 read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request);
58 + save_munge_symlinks = munge_symlinks;
60 verbose = 0; /* future verbosity is controlled by client options */
61 ret = parse_arguments(&argc, (const char ***) &argv);
62 if (protect_args && ret) {
63 @@ -767,6 +772,8 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
65 orig_early_argv = NULL;
67 + munge_symlinks = save_munge_symlinks; /* The client mustn't control this. */
70 err_msg = finish_pre_exec(pre_exec_pid, pre_exec_fd, request,
71 orig_early_argv, orig_argv);
72 diff --git a/options.c b/options.c
75 @@ -103,6 +103,7 @@ int connect_timeout = 0;
77 int safe_symlinks = 0;
78 int copy_unsafe_links = 0;
79 +int munge_symlinks = 0;
81 int daemon_bwlimit = 0;
83 @@ -337,6 +338,7 @@ void usage(enum logcode F)
84 rprintf(F," -L, --copy-links transform symlink into referent file/dir\n");
85 rprintf(F," --copy-unsafe-links only \"unsafe\" symlinks are transformed\n");
86 rprintf(F," --safe-links ignore symlinks that point outside the source tree\n");
87 + rprintf(F," --munge-links munge symlinks to make them safer (but unusable)\n");
88 rprintf(F," -k, --copy-dirlinks transform symlink to a dir into referent dir\n");
89 rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n");
90 rprintf(F," -H, --hard-links preserve hard links\n");
91 @@ -519,6 +521,8 @@ static struct poptOption long_options[] = {
92 {"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 },
93 {"copy-unsafe-links",0, POPT_ARG_NONE, ©_unsafe_links, 0, 0, 0 },
94 {"safe-links", 0, POPT_ARG_NONE, &safe_symlinks, 0, 0, 0 },
95 + {"munge-links", 0, POPT_ARG_VAL, &munge_symlinks, 1, 0, 0 },
96 + {"no-munge-links", 0, POPT_ARG_VAL, &munge_symlinks, 0, 0, 0 },
97 {"copy-dirlinks", 'k', POPT_ARG_NONE, ©_dirlinks, 0, 0, 0 },
98 {"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 },
99 {"hard-links", 'H', POPT_ARG_NONE, 0, 'H', 0, 0 },
100 @@ -1476,6 +1480,17 @@ int parse_arguments(int *argc_p, const char ***argv_p)
101 need_messages_from_generator = 1;
104 + if (munge_symlinks && !am_daemon) {
106 + char prefix[SYMLINK_PREFIX_LEN]; /* NOT +1 ! */
107 + strlcpy(prefix, SYMLINK_PREFIX, sizeof prefix); /* trim the trailing slash */
108 + if (do_stat(prefix, &st) == 0 && S_ISDIR(st.st_mode)) {
109 + rprintf(FERROR, "Symlink munging is unsafe when a %s directory exists.\n",
111 + exit_cleanup(RERR_UNSUPPORTED);
115 if (sanitize_paths) {
117 for (i = argc; i-- > 0; )
118 diff --git a/pipe.c b/pipe.c
121 @@ -26,6 +26,7 @@ extern int am_sender;
122 extern int am_server;
123 extern int blocking_io;
124 extern int filesfrom_fd;
125 +extern int munge_symlinks;
126 extern mode_t orig_umask;
127 extern char *logfile_name;
128 extern int remote_option_cnt;
129 @@ -133,6 +134,7 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
133 + munge_symlinks = 0; /* Each side needs its own option. */
134 chmod_modes = NULL; /* Let the sending side handle this. */
136 /* Let the client side handle this. */
137 diff --git a/rsync.yo b/rsync.yo
140 @@ -351,6 +351,7 @@ to the detailed description below for a complete description. verb(
141 -L, --copy-links transform symlink into referent file/dir
142 --copy-unsafe-links only "unsafe" symlinks are transformed
143 --safe-links ignore symlinks that point outside the tree
144 + --munge-links munge symlinks to make them safer
145 -k, --copy-dirlinks transform symlink to dir into referent dir
146 -K, --keep-dirlinks treat symlinked dir on receiver as dir
147 -H, --hard-links preserve hard links
148 @@ -839,6 +840,25 @@ which point outside the copied tree. All absolute symlinks are
149 also ignored. Using this option in conjunction with bf(--relative) may
150 give unexpected results.
152 +dit(bf(--munge-links)) This option tells rsync to (1) modify all symlinks on
153 +the receiving side in a way that makes them unusable but recoverable (see
154 +below), or (2) to unmunge symlinks on the sending side that had been stored in
155 +a munged state. This is useful if you don't quite trust the source of the data
156 +to not try to slip in a symlink to a unexpected place.
158 +The way rsync disables the use of symlinks is to prefix each one with the
159 +string "/rsyncd-munged/". This prevents the links from being used as long as
160 +that directory does not exist. When this option is enabled, rsync will refuse
161 +to run if that path is a directory or a symlink to a directory.
163 +The option only affects the client side of the transfer, so if you need it to
164 +affect the server, specify it via bf(--remote-option). (Note that in a local
165 +transfer, the client side is the sender.)
167 +This option has no affect on a daemon, since the daemon configures whether it
168 +wants munged symlinks via its "munge symlinks" parameter. See also the
169 +"munge-symlinks" perl script in the support directory of the source code.
171 dit(bf(-k, --copy-dirlinks)) This option causes the sending side to treat
172 a symlink to a directory as though it were a real directory. This is
173 useful if you don't want symlinks to non-directories to be affected, as
174 diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo
177 @@ -197,8 +197,9 @@ to translate names, and that it is not possible for a user to change those
180 dit(bf(munge symlinks)) This parameter tells rsync to modify
181 -all incoming symlinks in a way that makes them unusable but recoverable
182 -(see below). This should help protect your files from user trickery when
183 +all symlinks in the same way as the (non-daemon-affecting)
184 +bf(--munge-links) command-line option (using a method described below).
185 +This should help protect your files from user trickery when
186 your daemon module is writable. The default is disabled when "use chroot"
187 is on and the inside-chroot path is "/", otherwise it is enabled.