Commit | Line | Data |
---|---|---|
36e715fd WD |
1 | This patch adds the --munge-links option, which works like the daemon's |
2 | "munge symlinks" parameter. | |
3 | ||
4 | To use this patch, run these commands for a successful build: | |
5 | ||
6 | patch -p1 <patches/remote-option.diff | |
7 | patch -p1 <patches/munge-links.diff | |
8 | ./configure (optional if already run) | |
9 | make | |
10 | ||
11 | diff --git a/clientserver.c b/clientserver.c | |
12 | --- a/clientserver.c | |
13 | +++ b/clientserver.c | |
14 | @@ -37,6 +37,7 @@ extern int ignore_errors; | |
15 | extern int preserve_xattrs; | |
16 | extern int kluge_around_eof; | |
17 | extern int daemon_over_rsh; | |
18 | +extern int munge_symlinks; | |
19 | extern int sanitize_paths; | |
20 | extern int numeric_ids; | |
21 | extern int filesfrom_fd; | |
22 | @@ -66,7 +67,6 @@ extern iconv_t ic_send, ic_recv; | |
23 | char *auth_user; | |
24 | int read_only = 0; | |
25 | int module_id = -1; | |
26 | -int munge_symlinks = 0; | |
27 | struct chmod_mode_struct *daemon_chmod_modes; | |
28 | ||
29 | /* module_dirlen is the length of the module_dir string when in daemon | |
30 | @@ -406,6 +406,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) | |
31 | char *name = lp_name(i); | |
32 | int use_chroot = lp_use_chroot(i); | |
33 | int ret, pre_exec_fd = -1; | |
34 | + int save_munge_symlinks; | |
35 | pid_t pre_exec_pid = 0; | |
36 | char *request = NULL; | |
37 | ||
38 | @@ -689,9 +690,11 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) | |
39 | munge_symlinks = !use_chroot || module_dirlen; | |
40 | if (munge_symlinks) { | |
41 | STRUCT_STAT st; | |
42 | - if (do_stat(SYMLINK_PREFIX, &st) == 0 && S_ISDIR(st.st_mode)) { | |
43 | - rprintf(FLOG, "Symlink munging is unsupported when a %s directory exists.\n", | |
44 | - SYMLINK_PREFIX); | |
45 | + char prefix[SYMLINK_PREFIX_LEN]; /* NOT +1 ! */ | |
46 | + strlcpy(prefix, SYMLINK_PREFIX, sizeof prefix); /* trim the trailing slash */ | |
47 | + if (do_stat(prefix, &st) == 0 && S_ISDIR(st.st_mode)) { | |
48 | + rprintf(FLOG, "Symlink munging is unsafe when a %s directory exists.\n", | |
49 | + prefix); | |
50 | io_printf(f_out, "@ERROR: daemon security issue -- contact admin\n", name); | |
51 | exit_cleanup(RERR_UNSUPPORTED); | |
52 | } | |
53 | @@ -747,6 +750,8 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) | |
54 | read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request); | |
55 | orig_argv = argv; | |
56 | ||
57 | + save_munge_symlinks = munge_symlinks; | |
58 | + | |
59 | verbose = 0; /* future verbosity is controlled by client options */ | |
60 | ret = parse_arguments(&argc, (const char ***) &argv); | |
61 | if (protect_args && ret) { | |
62 | @@ -758,6 +763,8 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) | |
63 | } else | |
64 | orig_early_argv = NULL; | |
65 | ||
66 | + munge_symlinks = save_munge_symlinks; /* The client mustn't control this. */ | |
67 | + | |
68 | if (pre_exec_pid) { | |
69 | err_msg = finish_pre_exec(pre_exec_pid, pre_exec_fd, request, | |
70 | orig_early_argv, orig_argv); | |
71 | diff --git a/options.c b/options.c | |
72 | --- a/options.c | |
73 | +++ b/options.c | |
74 | @@ -105,6 +105,7 @@ int connect_timeout = 0; | |
75 | int keep_partial = 0; | |
76 | int safe_symlinks = 0; | |
77 | int copy_unsafe_links = 0; | |
78 | +int munge_symlinks = 0; | |
79 | int size_only = 0; | |
80 | int daemon_bwlimit = 0; | |
81 | int bwlimit = 0; | |
82 | @@ -338,6 +339,7 @@ void usage(enum logcode F) | |
83 | rprintf(F," -L, --copy-links transform symlink into referent file/dir\n"); | |
84 | rprintf(F," --copy-unsafe-links only \"unsafe\" symlinks are transformed\n"); | |
85 | rprintf(F," --safe-links ignore symlinks that point outside the source tree\n"); | |
86 | + rprintf(F," --munge-links munge symlinks to make them safer (but unusable)\n"); | |
87 | rprintf(F," -k, --copy-dirlinks transform symlink to a dir into referent dir\n"); | |
88 | rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); | |
89 | rprintf(F," -H, --hard-links preserve hard links\n"); | |
90 | @@ -520,6 +522,8 @@ static struct poptOption long_options[] = { | |
91 | {"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 }, | |
92 | {"copy-unsafe-links",0, POPT_ARG_NONE, ©_unsafe_links, 0, 0, 0 }, | |
93 | {"safe-links", 0, POPT_ARG_NONE, &safe_symlinks, 0, 0, 0 }, | |
94 | + {"munge-links", 0, POPT_ARG_VAL, &munge_symlinks, 1, 0, 0 }, | |
95 | + {"no-munge-links", 0, POPT_ARG_VAL, &munge_symlinks, 0, 0, 0 }, | |
96 | {"copy-dirlinks", 'k', POPT_ARG_NONE, ©_dirlinks, 0, 0, 0 }, | |
97 | {"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 }, | |
98 | {"hard-links", 'H', POPT_ARG_NONE, 0, 'H', 0, 0 }, | |
99 | @@ -1471,6 +1475,17 @@ int parse_arguments(int *argc_p, const char ***argv_p) | |
100 | need_messages_from_generator = 1; | |
101 | } | |
102 | ||
103 | + if (munge_symlinks && !am_daemon) { | |
104 | + STRUCT_STAT st; | |
105 | + char prefix[SYMLINK_PREFIX_LEN]; /* NOT +1 ! */ | |
106 | + strlcpy(prefix, SYMLINK_PREFIX, sizeof prefix); /* trim the trailing slash */ | |
107 | + if (do_stat(prefix, &st) == 0 && S_ISDIR(st.st_mode)) { | |
108 | + rprintf(FERROR, "Symlink munging is unsafe when a %s directory exists.\n", | |
109 | + prefix); | |
110 | + exit_cleanup(RERR_UNSUPPORTED); | |
111 | + } | |
112 | + } | |
113 | + | |
114 | if (sanitize_paths) { | |
115 | int i; | |
116 | for (i = argc; i-- > 0; ) | |
117 | diff --git a/pipe.c b/pipe.c | |
118 | --- a/pipe.c | |
119 | +++ b/pipe.c | |
120 | @@ -26,6 +26,7 @@ extern int am_sender; | |
121 | extern int am_server; | |
122 | extern int blocking_io; | |
123 | extern int filesfrom_fd; | |
124 | +extern int munge_symlinks; | |
125 | extern mode_t orig_umask; | |
126 | extern char *logfile_name; | |
127 | extern int remote_option_cnt; | |
128 | @@ -133,6 +134,7 @@ pid_t local_child(int argc, char **argv, int *f_in, int *f_out, | |
129 | am_sender = 0; | |
130 | am_server = 1; | |
131 | filesfrom_fd = -1; | |
132 | + munge_symlinks = 0; /* Each side needs its own option. */ | |
133 | chmod_modes = NULL; /* Let the sending side handle this. */ | |
134 | ||
135 | /* Let the client side handle this. */ | |
136 | diff --git a/rsync.h b/rsync.h | |
137 | --- a/rsync.h | |
138 | +++ b/rsync.h | |
139 | @@ -32,7 +32,7 @@ | |
140 | #define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock" | |
141 | #define URL_PREFIX "rsync://" | |
142 | ||
143 | -#define SYMLINK_PREFIX "/rsyncd-munged/" | |
144 | +#define SYMLINK_PREFIX "/rsyncd-munged/" /* This MUST have a trailing slash! */ | |
145 | #define SYMLINK_PREFIX_LEN ((int)sizeof SYMLINK_PREFIX - 1) | |
146 | ||
147 | #define BACKUP_SUFFIX "~" | |
148 | diff --git a/rsync.yo b/rsync.yo | |
149 | --- a/rsync.yo | |
150 | +++ b/rsync.yo | |
151 | @@ -334,6 +334,7 @@ to the detailed description below for a complete description. verb( | |
152 | -L, --copy-links transform symlink into referent file/dir | |
153 | --copy-unsafe-links only "unsafe" symlinks are transformed | |
154 | --safe-links ignore symlinks that point outside the tree | |
155 | + --munge-links munge symlinks to make them safer | |
156 | -k, --copy-dirlinks transform symlink to dir into referent dir | |
157 | -K, --keep-dirlinks treat symlinked dir on receiver as dir | |
158 | -H, --hard-links preserve hard links | |
159 | @@ -791,6 +792,25 @@ which point outside the copied tree. All absolute symlinks are | |
160 | also ignored. Using this option in conjunction with bf(--relative) may | |
161 | give unexpected results. | |
162 | ||
163 | +dit(bf(--munge-links)) This option tells rsync to (1) modify all symlinks on | |
164 | +the receiving side in a way that makes them unusable but recoverable (see | |
165 | +below), or (2) to unmunge symlinks on the sending side that had been stored in | |
166 | +a munged state. This is useful if you don't quite trust the source of the data | |
167 | +to not try to slip in a symlink to a unexpected place. | |
168 | + | |
169 | +The way rsync disables the use of symlinks is to prefix each one with the | |
170 | +string "/rsyncd-munged/". This prevents the links from being used as long as | |
171 | +that directory does not exist. When this option is enabled, rsync will refuse | |
172 | +to run if that path is a directory or a symlink to a directory. | |
173 | + | |
174 | +The option only affects the client side of the transfer, so if you need it to | |
175 | +affect the server, specify it via bf(--remote-option). (Note that in a local | |
176 | +transfer, the client side is the sender.) | |
177 | + | |
178 | +This option has no affect on a daemon, since the daemon configures whether it | |
179 | +wants munged symlinks via its "munge symlinks" parameter. See also the | |
180 | +"munge-symlinks" perl script in the support directory of the source code. | |
181 | + | |
182 | dit(bf(-k, --copy-dirlinks)) This option causes the sending side to treat | |
183 | a symlink to a directory as though it were a real directory. This is | |
184 | useful if you don't want symlinks to non-directories to be affected, as | |
185 | diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo | |
186 | --- a/rsyncd.conf.yo | |
187 | +++ b/rsyncd.conf.yo | |
188 | @@ -192,8 +192,9 @@ to translate names, and that it is not possible for a user to change those | |
189 | resources. | |
190 | ||
191 | dit(bf(munge symlinks)) This parameter tells rsync to modify | |
192 | -all incoming symlinks in a way that makes them unusable but recoverable | |
193 | -(see below). This should help protect your files from user trickery when | |
194 | +all symlinks in the same way as the (non-daemon-affecting) | |
195 | +bf(--munge-links) command-line option (using a method described below). | |
196 | +This should help protect your files from user trickery when | |
197 | your daemon module is writable. The default is disabled when "use chroot" | |
198 | is on and the inside-chroot path is "/", otherwise it is enabled. | |
199 | ||
200 | @@ -213,7 +214,8 @@ to the exclude setting for the module so that | |
201 | a user can't try to create it. | |
202 | ||
203 | Note: rsync makes no attempt to verify that any pre-existing symlinks in | |
204 | -the hierarchy are as safe as you want them to be. If you setup an rsync | |
205 | +the module's hierarchy are as safe as you want them to be (unless, of | |
206 | +course, it just copied in the whole hierarchy). If you setup an rsync | |
207 | daemon on a new area or locally add symlinks, you can manually protect your | |
208 | symlinks from being abused by prefixing "/rsyncd-munged/" to the start of | |
209 | every symlink's value. There is a perl script in the support directory |