+ if (lp_transfer_logging(i) && !logfile_format)
+ logfile_format = lp_log_format(i);
+ if (log_format_has(logfile_format, 'i'))
+ logfile_format_has_i = 1;
+ if (logfile_format_has_i || log_format_has(logfile_format, 'o'))
+ logfile_format_has_o_or_i = 1;
+
+ am_root = (MY_UID() == 0);
+
+ if (am_root) {
+ p = lp_uid(i);
+ if (!name_to_uid(p, &uid)) {
+ if (!isDigit(p)) {
+ rprintf(FLOG, "Invalid uid %s\n", p);
+ io_printf(f_out, "@ERROR: invalid uid %s\n", p);
+ return -1;
+ }
+ uid = atoi(p);
+ }
+
+ p = lp_gid(i);
+ if (!name_to_gid(p, &gid)) {
+ if (!isDigit(p)) {
+ rprintf(FLOG, "Invalid gid %s\n", p);
+ io_printf(f_out, "@ERROR: invalid gid %s\n", p);
+ return -1;
+ }
+ gid = atoi(p);
+ }
+ }
+
+ /* TODO: If we're not root, but the configuration requests
+ * that we change to some uid other than the current one, then
+ * log a warning. */
+
+ /* TODO: Perhaps take a list of gids, and make them into the
+ * supplementary groups. */
+
+ if (use_chroot || (module_dirlen = strlen(lp_path(i))) == 1) {
+ module_dirlen = 0;
+ set_filter_dir("/", 1);
+ } else
+ set_filter_dir(lp_path(i), module_dirlen);
+
+ p = lp_filter(i);
+ parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT,
+ XFLG_ABS_IF_SLASH);
+
+ p = lp_include_from(i);
+ parse_filter_file(&server_filter_list, p, MATCHFLG_INCLUDE,
+ XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
+
+ p = lp_include(i);
+ parse_rule(&server_filter_list, p,
+ MATCHFLG_INCLUDE | MATCHFLG_WORD_SPLIT,
+ XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES);
+
+ p = lp_exclude_from(i);
+ parse_filter_file(&server_filter_list, p, 0,
+ XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS);
+
+ p = lp_exclude(i);
+ parse_rule(&server_filter_list, p, MATCHFLG_WORD_SPLIT,
+ XFLG_ABS_IF_SLASH | XFLG_OLD_PREFIXES);
+
+ log_init(1);
+
+#ifdef HAVE_PUTENV
+ if (*lp_prexfer_exec(i) || *lp_postxfer_exec(i)) {
+ char *modname, *modpath, *hostaddr, *hostname, *username;
+ int status;
+ if (asprintf(&modname, "RSYNC_MODULE_NAME=%s", name) < 0
+ || asprintf(&modpath, "RSYNC_MODULE_PATH=%s", lp_path(i)) < 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)
+ out_of_memory("rsync_module");
+ putenv(modname);
+ putenv(modpath);
+ putenv(hostaddr);
+ putenv(hostname);
+ putenv(username);
+ umask(orig_umask);
+ /* For post-xfer exec, fork a new process to run the rsync
+ * daemon while this process waits for the exit status and
+ * runs the indicated command at that point. */
+ if (*lp_postxfer_exec(i)) {
+ pid_t pid = fork();
+ if (pid < 0) {
+ rsyserr(FLOG, errno, "fork failed");
+ io_printf(f_out, "@ERROR: fork failed\n");
+ return -1;
+ }
+ if (pid) {
+ if (asprintf(&p, "RSYNC_PID=%ld", (long)pid) > 0)
+ putenv(p);
+ if (wait_process(pid, &status, 0) < 0)
+ status = -1;
+ if (asprintf(&p, "RSYNC_RAW_STATUS=%d", status) > 0)
+ putenv(p);
+ if (WIFEXITED(status))
+ status = WEXITSTATUS(status);
+ else
+ status = -1;
+ if (asprintf(&p, "RSYNC_EXIT_STATUS=%d", status) > 0)
+ putenv(p);
+ system(lp_postxfer_exec(i));
+ _exit(status);
+ }
+ }
+ /* For pre-xfer exec, fork a child process to run the indicated
+ * command, though it first waits for the parent process to
+ * send us the user's request via a pipe. */
+ if (*lp_prexfer_exec(i)) {
+ int fds[2];
+ if (asprintf(&p, "RSYNC_PID=%ld", (long)getpid()) > 0)
+ putenv(p);
+ if (pipe(fds) < 0 || (pre_exec_pid = fork()) < 0) {
+ rsyserr(FLOG, errno, "pre-xfer exec preparation failed");
+ io_printf(f_out, "@ERROR: pre-xfer exec preparation failed\n");
+ return -1;
+ }
+ if (pre_exec_pid == 0) {
+ char buf[BIGPATHBUFLEN];
+ int j, len;
+ close(fds[1]);
+ set_blocking(fds[0]);
+ len = read_arg_from_pipe(fds[0], buf, BIGPATHBUFLEN);
+ if (len <= 0)
+ _exit(1);
+ if (asprintf(&p, "RSYNC_REQUEST=%s", buf) > 0)
+ putenv(p);
+ for (j = 0; ; j++) {
+ len = read_arg_from_pipe(fds[0], buf,
+ BIGPATHBUFLEN);
+ if (len <= 0) {
+ if (!len)
+ break;
+ _exit(1);
+ }
+ if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) > 0)
+ putenv(p);
+ }
+ close(fds[0]);
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ status = system(lp_prexfer_exec(i));
+ if (!WIFEXITED(status))
+ _exit(1);
+ _exit(WEXITSTATUS(status));
+ }
+ close(fds[0]);
+ set_blocking(fds[1]);
+ pre_exec_fd = fds[1];
+ }
+ umask(0);
+ }
+#endif
+
+ if (use_chroot) {
+ /*
+ * XXX: The 'use chroot' flag is a fairly reliable
+ * source of confusion, because it fails under two
+ * important circumstances: running as non-root,
+ * running on Win32 (or possibly others). On the
+ * other hand, if you are running as root, then it
+ * might be better to always use chroot.
+ *
+ * So, perhaps if we can't chroot we should just issue
+ * a warning, unless a "require chroot" flag is set,
+ * in which case we fail.
+ */
+ if (chroot(lp_path(i))) {
+ rsyserr(FLOG, errno, "chroot %s failed",
+ lp_path(i));
+ io_printf(f_out, "@ERROR: chroot failed\n");
+ return -1;
+ }
+
+ if (!push_dir("/", 0)) {
+ rsyserr(FLOG, errno, "chdir %s failed\n",
+ lp_path(i));
+ io_printf(f_out, "@ERROR: chdir failed\n");
+ return -1;
+ }
+
+ } else {
+ if (!push_dir(lp_path(i), 0)) {
+ rsyserr(FLOG, errno, "chdir %s failed\n",
+ lp_path(i));
+ io_printf(f_out, "@ERROR: chdir failed\n");