*/
#include "rsync.h"
-#include "ifuncs.h"
+#include "itypes.h"
extern int quiet;
-extern int verbose;
extern int dry_run;
extern int output_motd;
extern int list_only;
extern int preserve_xattrs;
extern int kluge_around_eof;
extern int daemon_over_rsh;
+extern int munge_symlinks;
extern int sanitize_paths;
extern int numeric_ids;
extern int filesfrom_fd;
extern int logfile_format_has_o_or_i;
extern mode_t orig_umask;
extern char *bind_address;
-extern char *sockopts;
extern char *config_file;
extern char *logfile_format;
extern char *files_from;
extern char *tmpdir;
extern struct chmod_mode_struct *chmod_modes;
extern struct filter_list_struct daemon_filter_list;
-extern char curr_dir[];
+extern char curr_dir[MAXPATHLEN];
#ifdef ICONV_OPTION
extern char *iconv_opt;
extern iconv_t ic_send, ic_recv;
char *auth_user;
int read_only = 0;
int module_id = -1;
-int munge_symlinks = 0;
struct chmod_mode_struct *daemon_chmod_modes;
/* module_dirlen is the length of the module_dir string when in daemon
char *module_dir = NULL;
unsigned int module_dirlen = 0;
+char *full_module_path;
+
static int rl_nulls = 0;
#ifdef HAVE_SIGACTION
if (fd == -1)
exit_cleanup(RERR_SOCKETIO);
- set_socket_options(fd, sockopts);
-
#ifdef ICONV_CONST
setup_iconv();
#endif
sargs[sargc] = NULL;
- if (verbose > 1)
+ if (DEBUG_GTE(CMD, 1))
print_child_argv("sending daemon args:", sargs);
io_printf(f_out, "%.*s\n", modlen, modname);
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;
char *name = lp_name(i);
int use_chroot = lp_use_chroot(i);
int ret, pre_exec_fd = -1;
+ int save_munge_symlinks;
pid_t pre_exec_pid = 0;
char *request = NULL;
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 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)) == NULL)
- out_of_memory("rsync_module");
- push_dir(line, 1); /* 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;
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)
status = -1;
if (asprintf(&p, "RSYNC_EXIT_STATUS=%d", status) > 0)
putenv(p);
- system(lp_postxfer_exec(i));
+ if (system(lp_postxfer_exec(i)) < 0)
+ status = -1;
_exit(status);
}
}
* 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 (!push_dir(module_dir, 0))
- goto chdir_failed;
- if (module_dirlen)
- sanitize_paths = 1;
- } else {
- if (!push_dir(module_dir, 0)) {
- 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) {
STRUCT_STAT st;
- if (do_stat(SYMLINK_PREFIX, &st) == 0 && S_ISDIR(st.st_mode)) {
- rprintf(FLOG, "Symlink munging is unsupported when a %s directory exists.\n",
- SYMLINK_PREFIX);
+ char prefix[SYMLINK_PREFIX_LEN]; /* NOT +1 ! */
+ strlcpy(prefix, SYMLINK_PREFIX, sizeof prefix); /* trim the trailing slash */
+ if (do_stat(prefix, &st) == 0 && S_ISDIR(st.st_mode)) {
+ rprintf(FLOG, "Symlink munging is unsafe when a %s directory exists.\n",
+ prefix);
io_printf(f_out, "@ERROR: daemon security issue -- contact admin\n", name);
exit_cleanup(RERR_UNSUPPORTED);
}
read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request);
orig_argv = argv;
- verbose = 0; /* future verbosity is controlled by client options */
+ save_munge_symlinks = munge_symlinks;
+
+ reset_output_levels(); /* future verbosity is controlled by client options */
ret = parse_arguments(&argc, (const char ***) &argv);
if (protect_args && ret) {
orig_early_argv = orig_argv;
} else
orig_early_argv = NULL;
+ munge_symlinks = save_munge_symlinks; /* The client mustn't control this. */
+
if (pre_exec_pid) {
err_msg = finish_pre_exec(pre_exec_pid, pre_exec_fd, request,
orig_early_argv, orig_argv);
#ifndef DEBUG
/* don't allow the logs to be flooded too fast */
- if (verbose > lp_max_verbosity(i))
- verbose = lp_max_verbosity(i);
+ limit_output_verbosity(lp_max_verbosity(i));
#endif
if (protocol_version < 23
with "list = False". */
static void send_listing(int fd)
{
- int n = lp_numservices();
+ int n = lp_num_modules();
int i;
for (i = 0; i < n; i++) {
if (!am_server) {
set_socket_options(f_in, "SO_KEEPALIVE");
- if (sockopts)
- set_socket_options(f_in, sockopts);
- else
- set_socket_options(f_in, lp_socket_options());
set_nonblocking(f_in);
}
char *pid_file = lp_pid_file();
char pidbuf[16];
pid_t pid = getpid();
- int fd;
+ int fd, len;
if (!pid_file || !*pid_file)
return;
cleanup_set_pid(pid);
if ((fd = do_open(pid_file, O_WRONLY|O_CREAT|O_EXCL, 0666 & ~orig_umask)) == -1) {
+ failure:
cleanup_set_pid(0);
fprintf(stderr, "failed to create pid file %s: %s\n", pid_file, strerror(errno));
rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);
exit_cleanup(RERR_FILEIO);
}
snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);
- write(fd, pidbuf, strlen(pidbuf));
+ len = strlen(pidbuf);
+ if (write(fd, pidbuf, len) != len)
+ goto failure;
close(fd);
}
fprintf(stderr, "Failed to parse config file: %s\n", config_file);
exit_cleanup(RERR_SYNTAX);
}
+ set_dparams(0);
if (no_detach)
create_pid_file();