qrexec: handle data vchan directly from qrexec-client-vm
This way qrexec-client-vm will have much more information, at least: - will know whether the service call was accepted or refused - potentially will know remote process exit code This commit implements the first point - the local process will not be started if service call was refused.
This commit is contained in:
parent
203691fae0
commit
1aa05ebc36
@ -6,7 +6,7 @@ LDLIBS=`pkg-config --libs vchan-$(BACKEND_VMM)` -lqrexec-utils
|
|||||||
all: qrexec-agent qrexec-client-vm qrexec-fork-server
|
all: qrexec-agent qrexec-client-vm qrexec-fork-server
|
||||||
qrexec-agent: qrexec-agent.o qrexec-agent-data.o
|
qrexec-agent: qrexec-agent.o qrexec-agent-data.o
|
||||||
qrexec-fork-server: qrexec-fork-server.o qrexec-agent-data.o
|
qrexec-fork-server: qrexec-fork-server.o qrexec-agent-data.o
|
||||||
qrexec-client-vm: qrexec-client-vm.o
|
qrexec-client-vm: qrexec-client-vm.o qrexec-agent-data.o
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *~ qrexec-agent qrexec-client-vm
|
rm -f *.o *~ qrexec-agent qrexec-client-vm
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <libvchan.h>
|
#include <libvchan.h>
|
||||||
|
#include <assert.h>
|
||||||
#include "qrexec.h"
|
#include "qrexec.h"
|
||||||
#include "libqrexec-utils.h"
|
#include "libqrexec-utils.h"
|
||||||
#include "qrexec-agent.h"
|
#include "qrexec-agent.h"
|
||||||
@ -42,6 +43,7 @@ static volatile int child_exited;
|
|||||||
static volatile int stdio_socket_requested;
|
static volatile int stdio_socket_requested;
|
||||||
int stdout_msg_type = MSG_DATA_STDOUT;
|
int stdout_msg_type = MSG_DATA_STDOUT;
|
||||||
pid_t child_process_pid;
|
pid_t child_process_pid;
|
||||||
|
int remote_process_status = 0;
|
||||||
|
|
||||||
static void sigchld_handler(int __attribute__((__unused__))x)
|
static void sigchld_handler(int __attribute__((__unused__))x)
|
||||||
{
|
{
|
||||||
@ -386,45 +388,37 @@ void process_child_io(libvchan_t *data_vchan,
|
|||||||
stdout_fd = -1;
|
stdout_fd = -1;
|
||||||
close(stderr_fd);
|
close(stderr_fd);
|
||||||
stderr_fd = -1;
|
stderr_fd = -1;
|
||||||
|
/* we do not care for any local process */
|
||||||
|
return;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t handle_new_process(int type, int connect_domain, int connect_port,
|
/* Behaviour depends on type parameter:
|
||||||
char *cmdline, int cmdline_len)
|
* MSG_SERVICE_CONNECT - create vchan server, pass the data to/from given FDs
|
||||||
|
* (stdin_fd, stdout_fd, stderr_fd), then return 0
|
||||||
|
* MSG_JUST_EXEC - connect to vchan server, fork+exec process given by cmdline
|
||||||
|
* parameter, send artificial exit code "0" (local process can still be
|
||||||
|
* running), then return 0
|
||||||
|
* MSG_EXEC_CMDLINE - connect to vchan server, fork+exec process given by
|
||||||
|
* cmdline parameter, pass the data to/from that process, then return local
|
||||||
|
* process exit code
|
||||||
|
*/
|
||||||
|
int handle_new_process_common(int type, int connect_domain, int connect_port,
|
||||||
|
char *cmdline, int cmdline_len, /* MSG_JUST_EXEC and MSG_EXEC_CMDLINE */
|
||||||
|
int stdin_fd, int stdout_fd, int stderr_fd /* MSG_SERVICE_CONNECT */)
|
||||||
{
|
{
|
||||||
struct service_params *svc_params = (struct service_params*)cmdline;
|
|
||||||
libvchan_t *data_vchan;
|
libvchan_t *data_vchan;
|
||||||
|
int exit_code = 0;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int stdin_fd, stdout_fd, stderr_fd;
|
|
||||||
char pid_s[10];
|
char pid_s[10];
|
||||||
|
|
||||||
if (type == MSG_SERVICE_CONNECT) {
|
if (type != MSG_SERVICE_CONNECT) {
|
||||||
if (cmdline_len != sizeof(*svc_params)) {
|
assert(cmdline != NULL);
|
||||||
fprintf(stderr, "Invalid MSG_SERVICE_CONNECT packet (cmdline len %d)\n", cmdline_len);
|
cmdline[cmdline_len-1] = 0;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sscanf(cmdline, "%d %d %d", &stdin_fd, &stdout_fd, &stderr_fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (pid=fork()){
|
|
||||||
case -1:
|
|
||||||
perror("fork");
|
|
||||||
return -1;
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (type == MSG_SERVICE_CONNECT) {
|
|
||||||
/* no longer needed in parent process */
|
|
||||||
close(stdin_fd);
|
|
||||||
close(stdout_fd);
|
|
||||||
close(stderr_fd);
|
|
||||||
}
|
|
||||||
return pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* child process */
|
|
||||||
if (type == MSG_SERVICE_CONNECT) {
|
if (type == MSG_SERVICE_CONNECT) {
|
||||||
data_vchan = libvchan_server_init(connect_domain, connect_port,
|
data_vchan = libvchan_server_init(connect_domain, connect_port,
|
||||||
VCHAN_BUFFER_SIZE, VCHAN_BUFFER_SIZE);
|
VCHAN_BUFFER_SIZE, VCHAN_BUFFER_SIZE);
|
||||||
@ -448,13 +442,13 @@ pid_t handle_new_process(int type, int connect_domain, int connect_port,
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case MSG_JUST_EXEC:
|
case MSG_JUST_EXEC:
|
||||||
send_exit_code(data_vchan, handle_just_exec(cmdline));
|
send_exit_code(data_vchan, handle_just_exec(cmdline));
|
||||||
libvchan_close(data_vchan);
|
|
||||||
break;
|
break;
|
||||||
case MSG_EXEC_CMDLINE:
|
case MSG_EXEC_CMDLINE:
|
||||||
do_fork_exec(cmdline, &pid, &stdin_fd, &stdout_fd, &stderr_fd);
|
do_fork_exec(cmdline, &pid, &stdin_fd, &stdout_fd, &stderr_fd);
|
||||||
fprintf(stderr, "executed %s pid %d\n", cmdline, pid);
|
fprintf(stderr, "executed %s pid %d\n", cmdline, pid);
|
||||||
child_process_pid = pid;
|
child_process_pid = pid;
|
||||||
process_child_io(data_vchan, stdin_fd, stdout_fd, stderr_fd);
|
exit_code = process_child_io(data_vchan, stdin_fd, stdout_fd, stderr_fd);
|
||||||
|
fprintf(stderr, "pid %d exited with %d\n", pid, exit_code);
|
||||||
break;
|
break;
|
||||||
case MSG_SERVICE_CONNECT:
|
case MSG_SERVICE_CONNECT:
|
||||||
child_process_pid = 0;
|
child_process_pid = 0;
|
||||||
@ -462,7 +456,44 @@ pid_t handle_new_process(int type, int connect_domain, int connect_port,
|
|||||||
process_child_io(data_vchan, stdin_fd, stdout_fd, stderr_fd);
|
process_child_io(data_vchan, stdin_fd, stdout_fd, stderr_fd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
exit(0);
|
libvchan_close(data_vchan);
|
||||||
|
return exit_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns PID of data processing process */
|
||||||
|
pid_t handle_new_process(int type, int connect_domain, int connect_port,
|
||||||
|
char *cmdline, int cmdline_len)
|
||||||
|
{
|
||||||
|
int exit_code;
|
||||||
|
pid_t pid;
|
||||||
|
assert(type != MSG_SERVICE_CONNECT);
|
||||||
|
|
||||||
|
switch (pid=fork()){
|
||||||
|
case -1:
|
||||||
|
perror("fork");
|
||||||
|
return -1;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* child process */
|
||||||
|
exit_code = handle_new_process_common(type, connect_domain, connect_port,
|
||||||
|
cmdline, cmdline_len,
|
||||||
|
-1, -1, -1);
|
||||||
|
|
||||||
|
exit(exit_code);
|
||||||
/* suppress warning */
|
/* suppress warning */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handle_data_client(int type, int connect_domain, int connect_port,
|
||||||
|
int stdin_fd, int stdout_fd, int stderr_fd)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(type == MSG_SERVICE_CONNECT);
|
||||||
|
|
||||||
|
handle_new_process_common(type, connect_domain, connect_port,
|
||||||
|
NULL, 0, stdin_fd, stdout_fd, stderr_fd);
|
||||||
|
}
|
||||||
|
@ -55,7 +55,6 @@ struct _connection_info connection_info[MAX_FDS];
|
|||||||
libvchan_t *ctrl_vchan;
|
libvchan_t *ctrl_vchan;
|
||||||
|
|
||||||
int trigger_fd;
|
int trigger_fd;
|
||||||
int passfd_socket;
|
|
||||||
|
|
||||||
int meminfo_write_started = 0;
|
int meminfo_write_started = 0;
|
||||||
|
|
||||||
@ -107,11 +106,8 @@ void init()
|
|||||||
if (handle_handshake(ctrl_vchan) < 0)
|
if (handle_handshake(ctrl_vchan) < 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
umask(0);
|
umask(0);
|
||||||
mkfifo(QREXEC_AGENT_TRIGGER_PATH, 0666);
|
trigger_fd = get_server_socket(QREXEC_AGENT_TRIGGER_PATH);
|
||||||
passfd_socket = get_server_socket(QREXEC_AGENT_FDPASS_PATH);
|
|
||||||
umask(077);
|
umask(077);
|
||||||
trigger_fd =
|
|
||||||
open(QREXEC_AGENT_TRIGGER_PATH, O_RDONLY | O_NONBLOCK);
|
|
||||||
register_exec_func(do_exec);
|
register_exec_func(do_exec);
|
||||||
|
|
||||||
/* wait for qrexec daemon */
|
/* wait for qrexec daemon */
|
||||||
@ -229,6 +225,7 @@ void handle_server_exec_request(struct msg_header *hdr)
|
|||||||
struct exec_params params;
|
struct exec_params params;
|
||||||
char buf[hdr->len-sizeof(params)];
|
char buf[hdr->len-sizeof(params)];
|
||||||
pid_t child_agent;
|
pid_t child_agent;
|
||||||
|
int client_fd;
|
||||||
|
|
||||||
assert(hdr->len >= sizeof(params));
|
assert(hdr->len >= sizeof(params));
|
||||||
|
|
||||||
@ -248,7 +245,24 @@ void handle_server_exec_request(struct msg_header *hdr)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (hdr->type == MSG_SERVICE_CONNECT && sscanf(buf, "SOCKET%d", &client_fd)) {
|
||||||
|
/* FIXME: Maybe add some check if client_fd is really FD to some
|
||||||
|
* qrexec-client-vm process; but this data comes from qrexec-daemon
|
||||||
|
* (which sends back what it got from us earlier), so it isn't critical.
|
||||||
|
*/
|
||||||
|
write(client_fd, ¶ms, sizeof(params));
|
||||||
|
/* No need to send request_id (buf) - the client don't need it, there
|
||||||
|
* is only meaningless (for the client) socket FD */
|
||||||
|
/* Register connection even if there was an error sending params to
|
||||||
|
* qrexec-client-vm. This way the mainloop will clean the things up
|
||||||
|
* (close socket, send MSG_CONNECTION_TERMINATED) when qrexec-client-vm
|
||||||
|
* will close the socket (terminate itself). */
|
||||||
|
register_vchan_connection(-1, client_fd,
|
||||||
|
params.connect_domain, params.connect_port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No fork server case */
|
||||||
child_agent = handle_new_process(hdr->type,
|
child_agent = handle_new_process(hdr->type,
|
||||||
params.connect_domain, params.connect_port,
|
params.connect_domain, params.connect_port,
|
||||||
buf, hdr->len-sizeof(params));
|
buf, hdr->len-sizeof(params));
|
||||||
@ -260,7 +274,7 @@ void handle_server_exec_request(struct msg_header *hdr)
|
|||||||
void handle_service_refused(struct msg_header *hdr)
|
void handle_service_refused(struct msg_header *hdr)
|
||||||
{
|
{
|
||||||
struct service_params params;
|
struct service_params params;
|
||||||
int stdin_fd, stdout_fd, stderr_fd;
|
int socket_fd;
|
||||||
|
|
||||||
if (hdr->len != sizeof(params)) {
|
if (hdr->len != sizeof(params)) {
|
||||||
fprintf(stderr, "Invalid msg 0x%x length (%d)\n", MSG_SERVICE_REFUSED, hdr->len);
|
fprintf(stderr, "Invalid msg 0x%x length (%d)\n", MSG_SERVICE_REFUSED, hdr->len);
|
||||||
@ -270,11 +284,10 @@ void handle_service_refused(struct msg_header *hdr)
|
|||||||
if (libvchan_recv(ctrl_vchan, ¶ms, sizeof(params)) < 0)
|
if (libvchan_recv(ctrl_vchan, ¶ms, sizeof(params)) < 0)
|
||||||
handle_vchan_error("read exec params");
|
handle_vchan_error("read exec params");
|
||||||
|
|
||||||
sscanf(params.ident, "%d %d %d", &stdin_fd, &stdout_fd, &stderr_fd);
|
if (sscanf(params.ident, "SOCKET%d", &socket_fd))
|
||||||
/* TODO: send some signal? some response? */
|
close(socket_fd);
|
||||||
close(stdin_fd);
|
else
|
||||||
close(stdout_fd);
|
fprintf(stderr, "Received REFUSED for unknown service request '%s'\n", params.ident);
|
||||||
close(stderr_fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_server_cmd()
|
void handle_server_cmd()
|
||||||
@ -360,9 +373,6 @@ int fill_fds_for_select(fd_set * rdset, fd_set * wrset)
|
|||||||
FD_SET(trigger_fd, rdset);
|
FD_SET(trigger_fd, rdset);
|
||||||
if (trigger_fd > max)
|
if (trigger_fd > max)
|
||||||
max = trigger_fd;
|
max = trigger_fd;
|
||||||
FD_SET(passfd_socket, rdset);
|
|
||||||
if (passfd_socket > max)
|
|
||||||
max = passfd_socket;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_FDS; i++) {
|
for (i = 0; i < MAX_FDS; i++) {
|
||||||
if (connection_info[i].pid != 0 && connection_info[i].fd != -1) {
|
if (connection_info[i].pid != 0 && connection_info[i].fd != -1) {
|
||||||
@ -374,41 +384,31 @@ int fill_fds_for_select(fd_set * rdset, fd_set * wrset)
|
|||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_new_passfd()
|
|
||||||
{
|
|
||||||
int fd = do_accept(passfd_socket);
|
|
||||||
if (fd >= MAX_FDS) {
|
|
||||||
fprintf(stderr, "too many clients ?\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
// let client know what fd has been allocated
|
|
||||||
if (write(fd, &fd, sizeof(fd)) != sizeof(fd)) {
|
|
||||||
perror("write to client");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_trigger_io()
|
void handle_trigger_io()
|
||||||
{
|
{
|
||||||
struct msg_header hdr;
|
struct msg_header hdr;
|
||||||
struct trigger_service_params params;
|
struct trigger_service_params params;
|
||||||
int ret;
|
int ret;
|
||||||
|
int client_fd;
|
||||||
|
|
||||||
|
client_fd = do_accept(trigger_fd);
|
||||||
|
if (client_fd < 0)
|
||||||
|
return;
|
||||||
hdr.len = sizeof(params);
|
hdr.len = sizeof(params);
|
||||||
ret = read(trigger_fd, ¶ms, sizeof(params));
|
ret = read(client_fd, ¶ms, sizeof(params));
|
||||||
if (ret == sizeof(params)) {
|
if (ret == sizeof(params)) {
|
||||||
hdr.type = MSG_TRIGGER_SERVICE;
|
hdr.type = MSG_TRIGGER_SERVICE;
|
||||||
|
snprintf(params.request_id.ident, sizeof(params.request_id), "SOCKET%d", client_fd);
|
||||||
if (libvchan_send(ctrl_vchan, &hdr, sizeof(hdr)) < 0)
|
if (libvchan_send(ctrl_vchan, &hdr, sizeof(hdr)) < 0)
|
||||||
handle_vchan_error("write hdr");
|
handle_vchan_error("write hdr");
|
||||||
if (libvchan_send(ctrl_vchan, ¶ms, sizeof(params)) < 0)
|
if (libvchan_send(ctrl_vchan, ¶ms, sizeof(params)) < 0)
|
||||||
handle_vchan_error("write params");
|
handle_vchan_error("write params");
|
||||||
}
|
}
|
||||||
// trigger_fd is nonblock - so no need to reopen
|
|
||||||
// not really, need to reopen at EOF
|
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
close(trigger_fd);
|
close(client_fd);
|
||||||
trigger_fd =
|
|
||||||
open(QREXEC_AGENT_TRIGGER_PATH, O_RDONLY | O_NONBLOCK);
|
|
||||||
}
|
}
|
||||||
|
/* do not close client_fd - we'll need it to send the connection details
|
||||||
|
* later (when dom0 accepts the request) */
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_terminated_fork_client(fd_set *rdset) {
|
void handle_terminated_fork_client(fd_set *rdset) {
|
||||||
@ -454,9 +454,6 @@ int main()
|
|||||||
wait_for_vchan_or_argfd(ctrl_vchan, max, &rdset, &wrset);
|
wait_for_vchan_or_argfd(ctrl_vchan, max, &rdset, &wrset);
|
||||||
sigprocmask(SIG_UNBLOCK, &chld_set, NULL);
|
sigprocmask(SIG_UNBLOCK, &chld_set, NULL);
|
||||||
|
|
||||||
if (FD_ISSET(passfd_socket, &rdset))
|
|
||||||
handle_new_passfd();
|
|
||||||
|
|
||||||
while (libvchan_data_ready(ctrl_vchan))
|
while (libvchan_data_ready(ctrl_vchan))
|
||||||
handle_server_cmd();
|
handle_server_cmd();
|
||||||
|
|
||||||
|
@ -28,6 +28,10 @@ void do_exec(const char *cmd);
|
|||||||
pid_t handle_new_process(int type,
|
pid_t handle_new_process(int type,
|
||||||
int connect_domain, int connect_port,
|
int connect_domain, int connect_port,
|
||||||
char *cmdline, int cmdline_len);
|
char *cmdline, int cmdline_len);
|
||||||
|
void handle_data_client(int type,
|
||||||
|
int connect_domain, int connect_port,
|
||||||
|
int stdin_fd, int stdout_fd, int stderr_fd);
|
||||||
|
|
||||||
|
|
||||||
struct qrexec_cmd_info {
|
struct qrexec_cmd_info {
|
||||||
int type;
|
int type;
|
||||||
|
@ -20,14 +20,29 @@
|
|||||||
*/
|
*/
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "libqrexec-utils.h"
|
||||||
#include "qrexec.h"
|
#include "qrexec.h"
|
||||||
int connect_unix_socket()
|
#include "qrexec-agent.h"
|
||||||
|
|
||||||
|
void handle_vchan_error(const char *op)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error while vchan %s, exiting\n", op);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_exec(const char *cmd __attribute__((__unused__))) {
|
||||||
|
fprintf(stderr, "BUG: do_exec function shouldn't be called!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int connect_unix_socket(char *path)
|
||||||
{
|
{
|
||||||
int s, len;
|
int s, len;
|
||||||
struct sockaddr_un remote;
|
struct sockaddr_un remote;
|
||||||
@ -38,7 +53,7 @@ int connect_unix_socket()
|
|||||||
}
|
}
|
||||||
|
|
||||||
remote.sun_family = AF_UNIX;
|
remote.sun_family = AF_UNIX;
|
||||||
strncpy(remote.sun_path, QREXEC_AGENT_FDPASS_PATH,
|
strncpy(remote.sun_path, path,
|
||||||
sizeof(remote.sun_path));
|
sizeof(remote.sun_path));
|
||||||
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
|
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
|
||||||
if (connect(s, (struct sockaddr *) &remote, len) == -1) {
|
if (connect(s, (struct sockaddr *) &remote, len) == -1) {
|
||||||
@ -61,9 +76,12 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
int trigger_fd;
|
int trigger_fd;
|
||||||
struct trigger_service_params params;
|
struct trigger_service_params params;
|
||||||
int local_fd[3], remote_fd[3];
|
struct exec_params exec_params;
|
||||||
int i;
|
int ret, i;
|
||||||
char *abs_exec_path;
|
char *abs_exec_path;
|
||||||
|
pid_t child_pid;
|
||||||
|
int inpipe[2], outpipe[2];
|
||||||
|
char pid_s[10];
|
||||||
|
|
||||||
if (argc < 4) {
|
if (argc < 4) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@ -72,50 +90,76 @@ int main(int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger_fd = open(QREXEC_AGENT_TRIGGER_PATH, O_WRONLY);
|
trigger_fd = connect_unix_socket(QREXEC_AGENT_TRIGGER_PATH);
|
||||||
if (trigger_fd < 0) {
|
|
||||||
perror("open " QREXEC_AGENT_TRIGGER_PATH);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
|
||||||
local_fd[i] = connect_unix_socket();
|
|
||||||
if (read(local_fd[i], &remote_fd[i], sizeof(remote_fd[i])) != sizeof(remote_fd[i])) {
|
|
||||||
perror("read client fd");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (i != 2 || getenv("PASS_LOCAL_STDERR")) {
|
|
||||||
char *env;
|
|
||||||
if (asprintf(&env, "SAVED_FD_%d=%d", i, dup(i)) < 0) {
|
|
||||||
perror("prepare SAVED_FD_");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
putenv(env);
|
|
||||||
dup2(local_fd[i], i);
|
|
||||||
close(local_fd[i]);
|
|
||||||
} else
|
|
||||||
close(local_fd[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(¶ms, 0, sizeof(params));
|
memset(¶ms, 0, sizeof(params));
|
||||||
strncpy(params.service_name, argv[2], sizeof(params.service_name));
|
strncpy(params.service_name, argv[2], sizeof(params.service_name));
|
||||||
strncpy(params.target_domain, argv[1],
|
strncpy(params.target_domain, argv[1],
|
||||||
sizeof(params.target_domain));
|
sizeof(params.target_domain));
|
||||||
snprintf(params.request_id.ident,
|
snprintf(params.request_id.ident,
|
||||||
sizeof(params.request_id.ident), "%d %d %d",
|
sizeof(params.request_id.ident), "SOCKET");
|
||||||
remote_fd[0], remote_fd[1], remote_fd[2]);
|
|
||||||
|
|
||||||
if (write(trigger_fd, ¶ms, sizeof(params)) < 0) {
|
if (write(trigger_fd, ¶ms, sizeof(params)) < 0) {
|
||||||
if (!getenv("PASS_LOCAL_STDERR"))
|
perror("write to agent");
|
||||||
perror("write to agent");
|
exit(1);
|
||||||
|
}
|
||||||
|
ret = read(trigger_fd, &exec_params, sizeof(exec_params));
|
||||||
|
if (ret == 0) {
|
||||||
|
fprintf(stderr, "Request refused\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (ret < 0 || ret != sizeof(exec_params)) {
|
||||||
|
perror("read");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(trigger_fd);
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, inpipe) ||
|
||||||
|
socketpair(AF_UNIX, SOCK_STREAM, 0, outpipe)) {
|
||||||
|
perror("socketpair");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
snprintf(pid_s, sizeof(pid_s), "%d", getpid());
|
||||||
|
setenv("QREXEC_AGENT_PID", pid_s, 1);
|
||||||
|
|
||||||
abs_exec_path = strdup(argv[3]);
|
switch (child_pid = fork()) {
|
||||||
argv[3] = get_program_name(argv[3]);
|
case -1:
|
||||||
execv(abs_exec_path, argv + 3);
|
perror("fork");
|
||||||
perror("execv");
|
exit(-1);
|
||||||
return 1;
|
case 0:
|
||||||
|
close(inpipe[1]);
|
||||||
|
close(outpipe[0]);
|
||||||
|
close(trigger_fd);
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
if (i != 2 || getenv("PASS_LOCAL_STDERR")) {
|
||||||
|
char *env;
|
||||||
|
if (asprintf(&env, "SAVED_FD_%d=%d", i, dup(i)) < 0) {
|
||||||
|
perror("prepare SAVED_FD_");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
putenv(env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dup2(inpipe[0], 0);
|
||||||
|
dup2(outpipe[1], 1);
|
||||||
|
close(inpipe[0]);
|
||||||
|
close(outpipe[1]);
|
||||||
|
|
||||||
|
abs_exec_path = strdup(argv[3]);
|
||||||
|
argv[3] = get_program_name(argv[3]);
|
||||||
|
execv(abs_exec_path, argv + 3);
|
||||||
|
perror("execv");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
close(inpipe[0]);
|
||||||
|
close(outpipe[1]);
|
||||||
|
|
||||||
|
handle_data_client(MSG_SERVICE_CONNECT,
|
||||||
|
exec_params.connect_domain, exec_params.connect_port,
|
||||||
|
inpipe[1], outpipe[0], -1);
|
||||||
|
|
||||||
|
close(trigger_fd);
|
||||||
|
waitpid(child_pid, &i, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user