mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-10-21 13:24:15 -04:00
Enhanced the "pre-xfer exec" handling so that it gets the user's
request info and puts that into the environment as RSYNC_REQUEST.
This commit is contained in:
1 parent
97d8e7095f
commit
c95ca2a228
1 file changed
+83
-24
+83
-24
@@ -59,6 +59,8 @@ int module_id = -1;
|
||||
/* Length of lp_path() string when in daemon mode & not chrooted, else 0. */
|
||||
unsigned int module_dirlen = 0;
|
||||
|
||||
#define MAX_REQ_LEN (MAXPATHLEN + 255)
|
||||
|
||||
/**
|
||||
* Run a client connected to an rsyncd. The alternative to this
|
||||
* function for remote-shell connections is do_cmd().
|
||||
@@ -216,7 +218,27 @@ int start_inband_exchange(char *user, char *path, int f_in, int f_out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *finish_pre_exec(pid_t pid, int fd, char *request)
|
||||
{
|
||||
int status = -1;
|
||||
|
||||
if (request) {
|
||||
int len = strlen(request);
|
||||
if (len > MAX_REQ_LEN)
|
||||
len = MAX_REQ_LEN;
|
||||
write(fd, request, len);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
if (wait_process(pid, &status, 0) < 0
|
||||
|| !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
char *e;
|
||||
if (asprintf(&e, "pre-xfer exec returned failure (%d)\n", status) < 0)
|
||||
out_of_memory("finish_pre_exec");
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int rsync_module(int f_in, int f_out, int i)
|
||||
{
|
||||
@@ -226,16 +248,14 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
char line[BIGPATHBUFLEN];
|
||||
uid_t uid = (uid_t)-2; /* canonically "nobody" */
|
||||
gid_t gid = (gid_t)-2;
|
||||
char *p;
|
||||
#ifdef HAVE_PUTENV
|
||||
char *s;
|
||||
#endif
|
||||
char *p, *err_msg = NULL;
|
||||
char *addr = client_addr(f_in);
|
||||
char *host = client_name(f_in);
|
||||
char *name = lp_name(i);
|
||||
int use_chroot = lp_use_chroot(i);
|
||||
int start_glob = 0;
|
||||
int ret;
|
||||
int ret, pre_exec_fd = -1;
|
||||
pid_t pre_exec_pid = 0;
|
||||
char *request = NULL;
|
||||
|
||||
if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
|
||||
@@ -351,9 +371,7 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
log_init();
|
||||
|
||||
#ifdef HAVE_PUTENV
|
||||
s = lp_prexfer_exec(i);
|
||||
p = lp_postxfer_exec(i);
|
||||
if ((s && *s) || (p && *p)) {
|
||||
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
|
||||
@@ -368,15 +386,10 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
putenv(hostname);
|
||||
putenv(username);
|
||||
umask(orig_umask);
|
||||
if (s && *s) {
|
||||
status = system(s);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
rprintf(FLOG, "prexfer-exec failed\n");
|
||||
io_printf(f_out, "@ERROR: prexfer-exec failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (p && *p) {
|
||||
/* 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");
|
||||
@@ -385,7 +398,8 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
}
|
||||
if (pid) {
|
||||
char *ret1, *ret2;
|
||||
waitpid(pid, &status, 0);
|
||||
if (wait_process(pid, &status, 0) < 0)
|
||||
status = -1;
|
||||
if (asprintf(&ret1, "RSYNC_RAW_STATUS=%d", status) > 0)
|
||||
putenv(ret1);
|
||||
if (WIFEXITED(status))
|
||||
@@ -394,10 +408,44 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
status = -1;
|
||||
if (asprintf(&ret2, "RSYNC_EXIT_STATUS=%d", status) > 0)
|
||||
putenv(ret2);
|
||||
system(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 (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[MAX_REQ_LEN+1];
|
||||
int len;
|
||||
close(fds[1]);
|
||||
set_blocking(fds[0]);
|
||||
len = read(fds[0], buf, MAX_REQ_LEN);
|
||||
close(fds[0]);
|
||||
if (len <= 0)
|
||||
_exit(1);
|
||||
buf[len] = '\0';
|
||||
if (asprintf(&p, "RSYNC_REQUEST=%s", buf) < 0)
|
||||
out_of_memory("rsync_module");
|
||||
putenv(p);
|
||||
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
|
||||
@@ -515,15 +563,24 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
start_glob = 1;
|
||||
break;
|
||||
case 1:
|
||||
if (pre_exec_pid) {
|
||||
err_msg = finish_pre_exec(pre_exec_pid,
|
||||
pre_exec_fd, p);
|
||||
pre_exec_pid = 0;
|
||||
}
|
||||
request = strdup(p);
|
||||
start_glob = 2;
|
||||
/* FALL THROUGH */
|
||||
default:
|
||||
glob_expand(name, &argv, &argc, &maxargs);
|
||||
if (!err_msg)
|
||||
glob_expand(name, &argv, &argc, &maxargs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pre_exec_pid)
|
||||
err_msg = finish_pre_exec(pre_exec_pid, pre_exec_fd, request);
|
||||
|
||||
verbose = 0; /* future verbosity is controlled by client options */
|
||||
ret = parse_arguments(&argc, (const char ***) &argv, 0);
|
||||
|
||||
@@ -552,7 +609,7 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
if (protocol_version < 23
|
||||
&& (protocol_version == 22 || am_sender))
|
||||
io_start_multiplex_out();
|
||||
else if (!ret) {
|
||||
else if (!ret || err_msg) {
|
||||
/* We have to get I/O multiplexing started so that we can
|
||||
* get the error back to the client. This means getting
|
||||
* the protocol setup finished first in later versions. */
|
||||
@@ -578,8 +635,11 @@ static int rsync_module(int f_in, int f_out, int i)
|
||||
io_start_multiplex_out();
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
option_error();
|
||||
if (!ret || err_msg) {
|
||||
if (err_msg)
|
||||
rprintf(FERROR, err_msg);
|
||||
else
|
||||
option_error();
|
||||
msleep(400);
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
@@ -684,7 +744,6 @@ int start_daemon(int f_in, int f_out)
|
||||
return rsync_module(f_in, f_out, i);
|
||||
}
|
||||
|
||||
|
||||
int daemon_main(void)
|
||||
{
|
||||
char *pid_file;
|
||||
|
||||
Reference in new issue
Block a user