Use "use warnings" rather than -w on the #! line.
[rsync/rsync-patches.git] / munge-links.diff
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 @@ -418,6 +418,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 @@ -688,9 +689,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 @@ -746,6 +749,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 @@ -757,6 +762,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 @@ -339,6 +340,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 @@ -521,6 +523,8 @@ static struct poptOption long_options[] = {
91    {"copy-links",      'L', POPT_ARG_NONE,   &copy_links, 0, 0, 0 },
92    {"copy-unsafe-links",0,  POPT_ARG_NONE,   &copy_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,   &copy_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 @@ -1472,6 +1476,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 @@ -338,6 +338,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 @@ -795,6 +796,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 @@ -191,8 +191,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