From fe62d30de8d52fc8eb0e7efa3401226d68a9a868 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Fri, 26 Sep 2008 21:19:51 -0700 Subject: [PATCH] Fix the %P logfile escape inside a chroot. --- clientserver.c | 86 ++++++++++++++++++++++++-------------------------- log.c | 4 +-- util.c | 28 ++++++++++++++++ 3 files changed, 72 insertions(+), 46 deletions(-) diff --git a/clientserver.c b/clientserver.c index f78c61c3..9500bf01 100644 --- a/clientserver.c +++ b/clientserver.c @@ -75,6 +75,8 @@ struct chmod_mode_struct *daemon_chmod_modes; char *module_dir = NULL; unsigned int module_dirlen = 0; +char *full_module_path; + static int rl_nulls = 0; #ifdef HAVE_SIGACTION @@ -395,10 +397,20 @@ static int read_arg_from_pipe(int fd, char *buf, int limit) return bp - buf; } +static int path_failure(int f_out, const char *dir, BOOL was_chdir) +{ + if (was_chdir) + rsyserr(FLOG, errno, "chdir %s failed\n", dir); + else + rprintf(FLOG, "normalize_path(%s) failed\n", dir); + io_printf(f_out, "@ERROR: chdir failed\n"); + return -1; +} + static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) { int argc; - char **argv, **orig_argv, **orig_early_argv, *chroot_path = NULL; + char **argv, **orig_argv, **orig_early_argv, *module_chdir; char line[BIGPATHBUFLEN]; uid_t uid = (uid_t)-2; /* canonically "nobody" */ gid_t gid = (gid_t)-2; @@ -501,27 +513,27 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) module_dir = lp_path(i); if (use_chroot) { if ((p = strstr(module_dir, "/./")) != NULL) { - *p = '\0'; - p += 2; - } else if ((p = strdup("/")) == NULL) /* MEMORY LEAK */ - out_of_memory("rsync_module"); - } - - /* We do a change_dir() that doesn't actually call chdir() - * just to make a relative path absolute. */ - strlcpy(line, curr_dir, sizeof line); - if (!change_dir(module_dir, CD_SKIP_CHDIR)) - goto chdir_failed; - if (strcmp(curr_dir, module_dir) != 0 - && (module_dir = strdup(curr_dir)) == NULL) - out_of_memory("rsync_module"); - change_dir(line, CD_SKIP_CHDIR); /* Restore curr_dir. */ - - if (use_chroot) { - chroot_path = module_dir; - module_dir = p; /* p is "/" or our inside-chroot path */ + *p = '\0'; /* Temporary... */ + if (!(module_chdir = normalize_path(module_dir, True, NULL))) + return path_failure(f_out, module_dir, False); + *p = '/'; + if (!(p = normalize_path(p + 2, True, &module_dirlen))) + return path_failure(f_out, strstr(module_dir, "/./"), False); + if (!(full_module_path = normalize_path(module_dir, False, NULL))) + full_module_path = module_dir; + module_dir = p; + } else { + if (!(module_chdir = normalize_path(module_dir, False, NULL))) + return path_failure(f_out, module_dir, False); + full_module_path = module_chdir; + module_dir = "/"; + module_dirlen = 1; + } + } else { + if (!(module_chdir = normalize_path(module_dir, False, &module_dirlen))) + return path_failure(f_out, module_dir, False); + full_module_path = module_dir = module_chdir; } - module_dirlen = clean_fname(module_dir, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR); if (module_dirlen == 1) { module_dirlen = 0; @@ -557,16 +569,8 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) char *modname, *modpath, *hostaddr, *hostname, *username; int status; - if (!use_chroot) - p = module_dir; - else if (module_dirlen) { - pathjoin(line, sizeof line, chroot_path, module_dir+1); - p = line; - } else - p = chroot_path; - if (asprintf(&modname, "RSYNC_MODULE_NAME=%s", name) < 0 - || asprintf(&modpath, "RSYNC_MODULE_PATH=%s", p) < 0 + || asprintf(&modpath, "RSYNC_MODULE_PATH=%s", full_module_path) < 0 || asprintf(&hostaddr, "RSYNC_HOST_ADDR=%s", addr) < 0 || asprintf(&hostname, "RSYNC_HOST_NAME=%s", host) < 0 || asprintf(&username, "RSYNC_USER_NAME=%s", auth_user) < 0) @@ -666,25 +670,19 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) * a warning, unless a "require chroot" flag is set, * in which case we fail. */ - if (chroot(chroot_path)) { - rsyserr(FLOG, errno, "chroot %s failed", chroot_path); + if (chroot(module_chdir)) { + rsyserr(FLOG, errno, "chroot %s failed", module_chdir); io_printf(f_out, "@ERROR: chroot failed\n"); return -1; } - if (!change_dir(module_dir, CD_NORMAL)) - goto chdir_failed; - if (module_dirlen) - sanitize_paths = 1; - } else { - if (!change_dir(module_dir, CD_NORMAL)) { - chdir_failed: - rsyserr(FLOG, errno, "chdir %s failed\n", module_dir); - io_printf(f_out, "@ERROR: chdir failed\n"); - return -1; - } - sanitize_paths = 1; + module_chdir = module_dir; } + if (!change_dir(module_chdir, CD_NORMAL)) + return path_failure(f_out, module_chdir, True); + if (module_dirlen || !use_chroot) + sanitize_paths = 1; + if ((munge_symlinks = lp_munge_symlinks(i)) < 0) munge_symlinks = !use_chroot || module_dirlen; if (munge_symlinks) { diff --git a/log.c b/log.c index 2dfa1275..1e18c9e1 100644 --- a/log.c +++ b/log.c @@ -55,7 +55,7 @@ extern iconv_t ic_chck; extern iconv_t ic_send, ic_recv; #endif extern char curr_dir[]; -extern char *module_dir; +extern char *full_module_path; extern unsigned int module_dirlen; static int log_initialised; @@ -603,7 +603,7 @@ static void log_formatted(enum logcode code, const char *format, const char *op, n = timestring(time(NULL)); break; case 'P': - n = module_dir; + n = full_module_path; break; case 'u': n = auth_user; diff --git a/util.c b/util.c index 634f9cf5..2f7ea914 100644 --- a/util.c +++ b/util.c @@ -1025,6 +1025,34 @@ int change_dir(const char *dir, int set_path_only) return 1; } +/* This will make a relative path absolute and clean it up via clean_fname(). + * Returns the string, which might be newly allocated, or NULL on error. */ +char *normalize_path(char *path, BOOL force_newbuf, unsigned int *len_ptr) +{ + unsigned int len; + + if (*path != '/') { /* Make path absolute. */ + int len = strlen(path); + if (curr_dir_len + 1 + len >= sizeof curr_dir) + return NULL; + curr_dir[curr_dir_len] = '/'; + memcpy(curr_dir + curr_dir_len + 1, path, len + 1); + if (!(path = strdup(curr_dir))) + out_of_memory("normalize_path"); + curr_dir[curr_dir_len] = '\0'; + } else if (force_newbuf) { + if (!(path = strdup(path))) + out_of_memory("normalize_path"); + } + + len = clean_fname(path, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR); + + if (len_ptr) + *len_ptr = len; + + return path; +} + /** * Return a quoted string with the full pathname of the indicated filename. * The string " (in MODNAME)" may also be appended. The returned pointer -- 2.34.1