X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/0b52f94da727c4881b58c1cd6f2cf2a824e02b30..cbbd8e2e8bf72aa46c84c7de43e19da40f040fa7:/clientserver.c diff --git a/clientserver.c b/clientserver.c index eb83867d..6bcbc81e 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 @@ -32,6 +32,7 @@ extern int am_daemon; extern int am_root; extern int rsync_port; extern int ignore_errors; +extern int preserve_xattrs; extern int kluge_around_eof; extern int daemon_over_rsh; extern int sanitize_paths; @@ -67,7 +68,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; @@ -119,6 +121,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); @@ -379,7 +385,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; @@ -390,7 +396,7 @@ 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_CONST +#ifdef ICONV_OPTION iconv_opt = lp_charset(i); if (*iconv_opt) setup_iconv(); @@ -479,18 +485,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 @@ -523,8 +543,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) @@ -624,13 +653,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: @@ -642,7 +673,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)) { @@ -715,9 +746,11 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) if (write_batch < 0) dry_run = 1; - if (lp_fake_super(i)) + if (lp_fake_super(i)) { + if (preserve_xattrs > 1) + preserve_xattrs = 1; am_root = -1; - else if (am_root < 0) /* Treat --fake-super from client as --super. */ + } else if (am_root < 0) /* Treat --fake-super from client as --super. */ am_root = 2; if (filesfrom_fd == 0) @@ -780,6 +813,7 @@ 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); @@ -790,6 +824,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host) ic_recv = (iconv_t)-1; } } +#endif if (!numeric_ids && (use_chroot ? lp_numeric_ids(i) != False : lp_numeric_ids(i) == True)) @@ -832,6 +867,17 @@ static void send_listing(int fd) io_printf(fd,"@RSYNCD: EXIT\n"); } +static int load_config(int globals_only) +{ + if (!config_file) { + if (am_server && am_root <= 0) + config_file = RSYNCD_USERCONF; + else + config_file = RSYNCD_SYSCONF; + } + return lp_load(config_file, globals_only); +} + /* this is called when a connection is established to a client and we want to start talking. The setup of the system is done from here */ @@ -847,7 +893,7 @@ int start_daemon(int f_in, int f_out) * might cause log-file output to occur. This ensures that the * "log file" param gets honored for the 2 non-forked use-cases * (when rsync is run by init and run by a remote shell). */ - if (!lp_load(config_file, 0)) + if (!load_config(0)) exit_cleanup(RERR_SYNTAX); addr = client_addr(f_in); @@ -956,13 +1002,6 @@ static void become_daemon(void) int daemon_main(void) { - if (!config_file) { - if (am_server && am_root <= 0) - config_file = RSYNCD_USERCONF; - else - config_file = RSYNCD_SYSCONF; - } - if (is_a_socket(STDIN_FILENO)) { int i; @@ -977,7 +1016,7 @@ int daemon_main(void) return start_daemon(STDIN_FILENO, STDIN_FILENO); } - if (!lp_load(config_file, 1)) { + if (!load_config(1)) { fprintf(stderr, "Failed to parse config file: %s\n", config_file); exit_cleanup(RERR_SYNTAX); }