Some demon_log_* variables changed into logfile_* variables that are
[rsync/rsync.git] / util.c
diff --git a/util.c b/util.c
index 875af11..12b88ed 100644 (file)
--- a/util.c
+++ b/util.c
@@ -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;