X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/d348d5fd5ffb55ccddb11d5428a7a3a3445ce037..d3d07a5e860f1cde0e234ec7a1aff7111a2c514f:/clientserver.c diff --git a/clientserver.c b/clientserver.c index 71cb9791..a3301117 100644 --- a/clientserver.c +++ b/clientserver.c @@ -3,7 +3,7 @@ * * Copyright (C) 1998-2001 Andrew Tridgell * Copyright (C) 2001-2002 Martin Pool - * Copyright (C) 2002-2007 Wayne Davison + * Copyright (C) 2002-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 @@ -35,6 +35,7 @@ extern int ignore_errors; extern int kluge_around_eof; extern int daemon_over_rsh; extern int sanitize_paths; +extern int numeric_ids; extern int filesfrom_fd; extern int remote_protocol; extern int protocol_version; @@ -54,6 +55,10 @@ extern char *tmpdir; extern struct chmod_mode_struct *chmod_modes; extern struct filter_list_struct server_filter_list; extern char curr_dir[]; +#ifdef ICONV_OPTION +extern char *iconv_opt; +extern iconv_t ic_send, ic_recv; +#endif char *auth_user; int read_only = 0; @@ -62,7 +67,8 @@ int munge_symlinks = 0; struct chmod_mode_struct *daemon_chmod_modes; /* module_dirlen is the length of the module_dir string when in daemon - * mode, not chrooted, and the path is not "/"; otherwise 0. */ + * mode and module_dir is not "/"; otherwise 0. (Note that a chroot- + * enabled module can have a non-"/" module_dir these days.) */ char *module_dir = NULL; unsigned int module_dirlen = 0; @@ -114,6 +120,10 @@ int start_socket_client(char *host, int remote_argc, char *remote_argv[], set_socket_options(fd, sockopts); +#ifdef ICONV_CONST + setup_iconv(); +#endif + ret = start_inband_exchange(fd, fd, user, remote_argc, remote_argv); return ret ? ret : client_run(fd, fd, -1, argc, argv); @@ -374,7 +384,7 @@ static int read_arg_from_pipe(int fd, char *buf, int limit) static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) { int argc, opt_cnt; - char **argv; + char **argv, *chroot_path = NULL; char line[BIGPATHBUFLEN]; uid_t uid = (uid_t)-2; /* canonically "nobody" */ gid_t gid = (gid_t)-2; @@ -385,6 +395,13 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) pid_t pre_exec_pid = 0; char *request = NULL; +#ifdef ICONV_OPTION + iconv_opt = lp_charset(i); + if (*iconv_opt) + setup_iconv(); + iconv_opt = NULL; +#endif + if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) { rprintf(FLOG, "rsync denied on module %s from %s (%s)\n", name, host, addr); @@ -467,18 +484,32 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) /* TODO: Perhaps take a list of gids, and make them into the * supplementary groups. */ - /* We do a push_dir() without actually calling chdir() in order - * to make sure that the module's path is absolute. After this - * check, module_dir will be set to an absolute path. */ module_dir = lp_path(i); + if (use_chroot) { + if ((p = strstr(module_dir, "/./")) != NULL) { + *p = '\0'; + p += 2; + } else if ((p = strdup("/")) == NULL) + out_of_memory("rsync_module"); + } + + /* We do a push_dir() that doesn't actually call chdir() + * just to make a relative path absolute. */ strlcpy(line, curr_dir, sizeof line); if (!push_dir(module_dir, 1)) goto chdir_failed; - if (strcmp(curr_dir, module_dir) != 0) - module_dir = strdup(curr_dir); + if (strcmp(curr_dir, module_dir) != 0 + && (module_dir = strdup(curr_dir)) == NULL) + out_of_memory("rsync_module"); push_dir(line, 1); /* Restore curr_dir. */ - if (use_chroot || (module_dirlen = strlen(module_dir)) == 1) { + if (use_chroot) { + chroot_path = module_dir; + module_dir = p; /* p is "/" or our inside-chroot path */ + } + module_dirlen = clean_fname(module_dir, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR); + + if (module_dirlen == 1) { module_dirlen = 0; set_filter_dir("/", 1); } else @@ -511,8 +542,17 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) if (*lp_prexfer_exec(i) || *lp_postxfer_exec(i)) { 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", module_dir) < 0 + || asprintf(&modpath, "RSYNC_MODULE_PATH=%s", p) < 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) @@ -612,13 +652,15 @@ 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(module_dir)) { - rsyserr(FLOG, errno, "chroot %s failed", module_dir); + if (chroot(chroot_path)) { + rsyserr(FLOG, errno, "chroot %s failed", chroot_path); io_printf(f_out, "@ERROR: chroot failed\n"); return -1; } - if (!push_dir("/", 0)) + if (!push_dir(module_dir, 0)) goto chdir_failed; + if (module_dirlen) + sanitize_paths = 1; } else { if (!push_dir(module_dir, 0)) { chdir_failed: @@ -630,7 +672,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) } if ((munge_symlinks = lp_munge_symlinks(i)) < 0) - munge_symlinks = !use_chroot; + munge_symlinks = !use_chroot || module_dirlen; if (munge_symlinks) { STRUCT_STAT st; if (stat(SYMLINK_PREFIX, &st) == 0 && S_ISDIR(st.st_mode)) { @@ -703,10 +745,6 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) if (write_batch < 0) dry_run = 1; -#ifdef ICONV_CONST - setup_iconv(); -#endif - if (lp_fake_super(i)) am_root = -1; else if (am_root < 0) /* Treat --fake-super from client as --super. */ @@ -772,6 +810,23 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) exit_cleanup(RERR_UNSUPPORTED); } +#ifdef ICONV_OPTION + if (!iconv_opt) { + if (ic_send != (iconv_t)-1) { + iconv_close(ic_send); + ic_send = (iconv_t)-1; + } + if (ic_recv != (iconv_t)-1) { + iconv_close(ic_recv); + ic_recv = (iconv_t)-1; + } + } +#endif + + if (!numeric_ids + && (use_chroot ? lp_numeric_ids(i) != False : lp_numeric_ids(i) == True)) + numeric_ids = -1; /* Set --numeric-ids w/o breaking protocol. */ + if (lp_timeout(i) && lp_timeout(i) > io_timeout) set_io_timeout(lp_timeout(i));