Some improvements to the file-name cleaning code:
[rsync/rsync.git] / main.c
diff --git a/main.c b/main.c
index b2dcb52..5985f80 100644 (file)
--- a/main.c
+++ b/main.c
@@ -4,7 +4,7 @@
  * Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
  * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003-2007 Wayne Davison
+ * Copyright (C) 2003-2008 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -45,6 +45,7 @@ extern int got_xfer_error;
 extern int module_id;
 extern int copy_links;
 extern int copy_dirlinks;
+extern int copy_unsafe_links;
 extern int keep_dirlinks;
 extern int preserve_hard_links;
 extern int protocol_version;
@@ -65,6 +66,7 @@ extern int batch_fd;
 extern int filesfrom_fd;
 extern int connect_timeout;
 extern pid_t cleanup_child_pid;
+extern unsigned int module_dirlen;
 extern struct stats stats;
 extern char *filesfrom_host;
 extern char *partial_dir;
@@ -76,11 +78,9 @@ extern char *batch_name;
 extern char *password_file;
 extern char curr_dir[MAXPATHLEN];
 extern struct file_list *first_flist;
-extern struct filter_list_struct server_filter_list;
-#ifdef ICONV_OPTION
-extern iconv_t ic_send;
-#endif
+extern struct filter_list_struct daemon_filter_list;
 
+uid_t our_uid;
 int local_server = 0;
 int daemon_over_rsh = 0;
 mode_t orig_umask = 0;
@@ -277,7 +277,7 @@ static void output_summary(void)
                rprintf(FINFO, "total size is %s  speedup is %.2f%s\n",
                        human_num(stats.total_size),
                        (double)stats.total_size / (total_written+total_read),
-                       dry_run ? " (DRY RUN)" : "");
+                       write_batch < 0 ? " (BATCH ONLY)" : dry_run ? " (DRY RUN)" : "");
        }
 
        fflush(stdout);
@@ -331,8 +331,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
 {
        int i, argc = 0;
        char *args[MAX_ARGS];
-       pid_t ret;
-       char *dir = NULL;
+       pid_t pid;
        int dash_l_set = 0;
 
        if (!read_batch && !local_server) {
@@ -342,7 +341,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
                        cmd = rsh_env;
                if (!cmd)
                        cmd = RSYNC_RSH;
-               cmd = strdup(cmd);
+               cmd = strdup(cmd); /* MEMORY LEAK */
                if (!cmd)
                        goto oom;
 
@@ -451,7 +450,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
                batch_gen_fd = from_gen_pipe[0];
                *f_out_p = from_gen_pipe[1];
                *f_in_p = batch_fd;
-               ret = -1; /* no child pid */
+               pid = (pid_t)-1; /* no child pid */
 #ifdef ICONV_CONST
                setup_iconv();
 #endif
@@ -461,57 +460,20 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
                if (whole_file < 0 && !write_batch)
                        whole_file = 1;
                set_allow_inc_recurse();
-               ret = local_child(argc, args, f_in_p, f_out_p, child_main);
+               pid = local_child(argc, args, f_in_p, f_out_p, child_main);
 #ifdef ICONV_CONST
                setup_iconv();
 #endif
        } else {
+               pid = piped_child(args, f_in_p, f_out_p);
 #ifdef ICONV_CONST
                setup_iconv();
 #endif
-               if (protect_args) {
-                       int fd;
-#ifdef ICONV_OPTION
-                       int convert = ic_send != (iconv_t)-1;
-                       xbuf outbuf, inbuf;
-
-                       if (convert)
-                               alloc_xbuf(&outbuf, 1024);
-#endif
-
-                       ret = piped_child(args, f_in_p, f_out_p);
-
-                       for (i = 0; args[i]; i++) {} /* find first NULL */
-                       args[i] = "rsync"; /* set a new arg0 */
-                       if (verbose > 1)
-                               print_child_argv("protected args:", args + i + 1);
-                       fd = *f_out_p;
-                       do {
-#ifdef ICONV_OPTION
-                               if (convert) {
-                                       INIT_XBUF_STRLEN(inbuf, args[i]);
-                                       iconvbufs(ic_send, &inbuf, &outbuf,
-                                                 ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
-                                       outbuf.buf[outbuf.len] = '\0';
-                                       write_buf(fd, outbuf.buf, outbuf.len + 1);
-                                       outbuf.len = 0;
-                               } else
-#endif
-                                       write_buf(fd, args[i], strlen(args[i]) + 1);
-                       } while (args[++i]);
-                       write_byte(fd, 0);
-#ifdef ICONV_OPTION
-                       if (convert)
-                               free(outbuf.buf);
-#endif
-               } else
-                       ret = piped_child(args, f_in_p, f_out_p);
+               if (protect_args)
+                       send_protected_args(*f_out_p, args);
        }
 
-       if (dir)
-               free(dir);
-
-       return ret;
+       return pid;
 
   oom:
        out_of_memory("do_cmd");
@@ -545,6 +507,14 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
        if (!dest_path || list_only)
                return NULL;
 
+       if (daemon_filter_list.head
+        && (check_filter(&daemon_filter_list, dest_path, 0 != 0) < 0
+         || check_filter(&daemon_filter_list, dest_path, 1 != 0) < 0)) {
+               rprintf(FERROR, "skipping daemon-excluded destination \"%s\"\n",
+                       dest_path);
+               exit_cleanup(RERR_FILESELECT);
+       }
+
        /* See what currently exists at the destination. */
        if ((statret = do_stat(dest_path, &st)) == 0) {
                /* If the destination is a dir, enter it and use mode 1. */
@@ -643,7 +613,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
  * dry-run mode and the destination dir does not yet exist, we'll try to
  * tweak any dest-relative paths to make them work for a dry-run (the
  * destination dir must be in curr_dir[] when this function is called).
- * We also report if any arg that is non-existent or not a directory. */
+ * We also warn about any arg that is non-existent or not a directory. */
 static void check_alt_basis_dirs(void)
 {
        STRUCT_STAT st;
@@ -761,7 +731,7 @@ static int do_recv(int f_in, int f_out, char *local_name)
 
        /* The receiving side mustn't obey this, or an existing symlink that
         * points to an identical file won't be replaced by the referent. */
-       copy_links = copy_dirlinks = 0;
+       copy_links = copy_dirlinks = copy_unsafe_links = 0;
 
 #ifdef SUPPORT_HARD_LINKS
        if (preserve_hard_links && !inc_recurse)
@@ -869,7 +839,6 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
        int exit_code;
        struct file_list *flist;
        char *local_name = NULL;
-       char *dir = NULL;
        int save_verbose = verbose;
 
        if (filesfrom_fd >= 0) {
@@ -890,7 +859,7 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
        }
 
        if (argc > 0) {
-               dir = argv[0];
+               char *dir = argv[0];
                argc--;
                argv++;
                if (!am_daemon && !push_dir(dir, 0)) {
@@ -933,22 +902,25 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
        if (sanitize_paths) {
                char **dir_p;
                for (dir_p = basis_dir; *dir_p; dir_p++)
-                       *dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth);
+                       *dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth, SP_DEFAULT);
                if (partial_dir)
-                       partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth);
+                       partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth, SP_DEFAULT);
        }
        check_alt_basis_dirs();
 
-       if (server_filter_list.head) {
-               char **dir;
-               struct filter_list_struct *elp = &server_filter_list;
+       if (daemon_filter_list.head) {
+               char **dir_p;
+               struct filter_list_struct *elp = &daemon_filter_list;
 
-               for (dir = basis_dir; *dir; dir++) {
-                       if (check_filter(elp, *dir, 1) < 0)
+               for (dir_p = basis_dir; *dir_p; dir_p++) {
+                       char *dir = *dir_p;
+                       if (*dir == '/')
+                               dir += module_dirlen;
+                       if (check_filter(elp, dir, 1) < 0)
                                goto options_rejected;
                }
                if (partial_dir && *partial_dir == '/'
-                && check_filter(elp, partial_dir, 1) < 0) {
+                && check_filter(elp, partial_dir + module_dirlen, 1) < 0) {
                    options_rejected:
                        rprintf(FERROR,
                                "Your options have been rejected by the server.\n");
@@ -1428,7 +1400,8 @@ int main(int argc,char *argv[])
 #endif
 
        starttime = time(NULL);
-       am_root = (MY_UID() == 0);
+       our_uid = MY_UID();
+       am_root = our_uid == 0;
 
        memset(&stats, 0, sizeof(stats));
 
@@ -1445,7 +1418,7 @@ int main(int argc,char *argv[])
        setlocale(LC_CTYPE, "");
 #endif
 
-       if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
+       if (!parse_arguments(&argc, (const char ***) &argv)) {
                /* FIXME: We ought to call the same error-handling
                 * code here, rather than relying on getopt. */
                option_error();
@@ -1510,7 +1483,7 @@ int main(int argc,char *argv[])
                char buf[MAXPATHLEN];
                protect_args = 2;
                read_args(STDIN_FILENO, NULL, buf, sizeof buf, 1, &argv, &argc, NULL);
-               if (!parse_arguments(&argc, (const char ***) &argv, 1)) {
+               if (!parse_arguments(&argc, (const char ***) &argv)) {
                        option_error();
                        exit_cleanup(RERR_SYNTAX);
                }