The print_child_argv() function should be outputting FCLIENT
[rsync/rsync.git] / util.c
diff --git a/util.c b/util.c
index 875af11..8dd1b1c 100644 (file)
--- a/util.c
+++ b/util.c
@@ -92,7 +92,7 @@ int fd_pair(int fd[2])
 
 void print_child_argv(char **cmd)
 {
-       rprintf(FINFO, "opening connection using ");
+       rprintf(FCLIENT, "opening connection using ");
        for (; *cmd; cmd++) {
                /* Look for characters that ought to be quoted.  This
                * is not a great quoting algorithm, but it's
@@ -101,12 +101,12 @@ void print_child_argv(char **cmd)
                           "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                           "0123456789"
                           ",.-_=+@/") != strlen(*cmd)) {
-                       rprintf(FINFO, "\"%s\" ", *cmd);
+                       rprintf(FCLIENT, "\"%s\" ", *cmd);
                } else {
-                       rprintf(FINFO, "%s ", *cmd);
+                       rprintf(FCLIENT, "%s ", *cmd);
                }
        }
-       rprintf(FINFO, "\n");
+       rprintf(FCLIENT, "\n");
 }
 
 void out_of_memory(char *str)
@@ -900,6 +900,46 @@ int safe_stat(const char *fname, STRUCT_STAT *stp)
 #endif
 }
 
+void die_on_unsafe_path(char *path, int strip_filename)
+{
+#ifdef SUPPORT_LINKS
+       char *final_slash, *p;
+       STRUCT_STAT st;
+
+       if (!path)
+               return;
+       if (strip_filename) {
+               if (!(final_slash = strrchr(path, '/')))
+                       return;
+               *final_slash = '\0';
+       } else
+               final_slash = NULL;
+
+       p = path;
+       if (*p == '/')
+               p += module_dirlen + 1;
+       while (*p) {
+               if ((p = strchr(p, '/')) != NULL)
+                       *p = '\0';
+               if (safe_stat(path, &st) < 0) {
+                       *p++ = '/';
+                       goto done;
+               }
+               if (S_ISLNK(st.st_mode)) {
+                       rprintf(FERROR, "Unsafe path: %s\n", path);
+                       exit_cleanup(RERR_SYNTAX);
+               }
+               if (!p)
+                       break;
+               *p++ = '/';
+       }
+
+  done:
+       if (final_slash)
+               *final_slash = '/';
+#endif
+}
+
 /* Like chdir(), but it keeps track of the current directory (in the
  * global "curr_dir"), and ensures that the path size doesn't overflow.
  * Also cleans the path using the clean_fname() function. */
@@ -1026,13 +1066,11 @@ char *partial_dir_fname(const char *fname)
        if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
                return NULL;
        if (server_filter_list.head) {
-               static int len;
-               if (!len)
-                       len = strlen(partial_dir);
-               t[len] = '\0';
+               t = strrchr(partial_fname, '/');
+               *t = '\0';
                if (check_filter(&server_filter_list, partial_fname, 1) < 0)
                        return NULL;
-               t[len] = '/';
+               *t = '/';
                if (check_filter(&server_filter_list, partial_fname, 0) < 0)
                        return NULL;
        }
@@ -1058,6 +1096,8 @@ int handle_partial_dir(const char *fname, int create)
        if (create) {
                STRUCT_STAT st;
                int statret = do_lstat(dir, &st);
+               if (sanitize_paths && *partial_dir != '/')
+                       die_on_unsafe_path(dir, 1); /* lstat handles last element */
                if (statret == 0 && !S_ISDIR(st.st_mode)) {
                        if (do_unlink(dir) < 0)
                                return 0;