X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/a8167c6611e582ef826e4ee06b590706385470ef..5e1f082d0c0af5fdb8096023772eb4f5013f78a0:/util.c diff --git a/util.c b/util.c index 875af11e..afe1f884 100644 --- 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. */ @@ -981,7 +1021,7 @@ char *full_fname(const char *fn) if (*fn == '/') p1 = p2 = ""; else { - p1 = curr_dir; + p1 = curr_dir + module_dirlen; for (p2 = p1; *p2 == '/'; p2++) {} if (*p2) p2 = "/"; @@ -990,17 +1030,11 @@ char *full_fname(const char *fn) m1 = " (in "; m2 = lp_name(module_id); m3 = ")"; - if (p1 == curr_dir) { - if (!lp_use_chroot(module_id)) { - char *p = lp_path(module_id); - if (*p != '/' || p[1]) - p1 += strlen(p); - } - } } else m1 = m2 = m3 = ""; - asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3); + if (asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3) <= 0) + out_of_memory("full_fname"); return result; } @@ -1026,13 +1060,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 +1090,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;