diff --git a/qrexec/qrexec.h b/qrexec/qrexec.h index 729ff932..ec29ed51 100644 --- a/qrexec/qrexec.h +++ b/qrexec/qrexec.h @@ -25,6 +25,8 @@ #define REXEC_PORT 512 +#define QREXEC_AGENT_TRIGGER_PATH "/var/run/qubes/qrexec_agent" + enum { MSG_CLIENT_TO_SERVER_EXEC_CMDLINE = 0x100, MSG_CLIENT_TO_SERVER_JUST_EXEC, @@ -40,12 +42,18 @@ enum { MSG_AGENT_TO_SERVER_STDOUT, MSG_AGENT_TO_SERVER_STDERR, MSG_AGENT_TO_SERVER_EXIT_CODE, + MSG_AGENT_TO_SERVER_TRIGGER_EXEC, MSG_SERVER_TO_CLIENT_STDOUT, MSG_SERVER_TO_CLIENT_STDERR, MSG_SERVER_TO_CLIENT_EXIT_CODE }; +enum { + QREXEC_EXECUTE_FILE_COPY=0x700, + QREXEC_EXECUTE_FILE_COPY_FOR_DISPVM +}; + struct server_header { unsigned int type; unsigned int clid; diff --git a/qrexec/qrexec_agent.c b/qrexec/qrexec_agent.c index 8b1309c2..ef02ddb1 100644 --- a/qrexec/qrexec_agent.c +++ b/qrexec/qrexec_agent.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "qrexec.h" #include "buffer.h" #include "glue.h" @@ -63,9 +64,16 @@ struct _process_fd process_fd[MAX_FDS]; /* indexed by client id, which is descriptor number of a client in daemon */ struct _client_info client_info[MAX_FDS]; +int trigger_fd; + void init() { peer_server_init(REXEC_PORT); + umask(0); + mkfifo(QREXEC_AGENT_TRIGGER_PATH, 0666); + umask(077); + trigger_fd = + open(QREXEC_AGENT_TRIGGER_PATH, O_RDONLY | O_NONBLOCK); } void no_colon_in_cmd() @@ -418,6 +426,11 @@ int fill_fds_for_select(fd_set * rdset, fd_set * wrset) FD_SET(i, rdset); max = i; } + + FD_SET(trigger_fd, rdset); + if (trigger_fd > max) + max = trigger_fd; + for (i = 0; i < MAX_FDS; i++) if (client_info[i].pid > 0 && client_info[i].is_blocked) { fd = client_info[i].stdin_fd; @@ -446,6 +459,28 @@ void flush_client_data_agent(int clid) } } +void handle_trigger_io() +{ + struct server_header s_hdr; + char buf[5]; + + s_hdr.clid = 0; + s_hdr.len = 0; + if (read(trigger_fd, buf, 4) == 4) { + buf[4] = 0; + if (!strcmp(buf, "FCPR")) + s_hdr.clid = QREXEC_EXECUTE_FILE_COPY; + else if (!strcmp(buf, "DVMR")) + s_hdr.clid = QREXEC_EXECUTE_FILE_COPY_FOR_DISPVM; + if (s_hdr.clid) { + s_hdr.type = MSG_AGENT_TO_SERVER_TRIGGER_EXEC; + write_all_vchan_ext(&s_hdr, sizeof s_hdr); + } + } + close(trigger_fd); + trigger_fd = + open(QREXEC_AGENT_TRIGGER_PATH, O_RDONLY | O_NONBLOCK); +} int main() { @@ -469,6 +504,9 @@ int main() while (read_ready_vchan_ext()) handle_server_data(); + if (FD_ISSET(trigger_fd, &rdset)) + handle_trigger_io(); + handle_process_data_all(&rdset); for (i = 0; i <= MAX_FDS; i++) if (client_info[i].pid > 0 diff --git a/qrexec/qrexec_daemon.c b/qrexec/qrexec_daemon.c index 5ceb4ab9..9f801983 100644 --- a/qrexec/qrexec_daemon.c +++ b/qrexec/qrexec_daemon.c @@ -51,9 +51,11 @@ int server_fd; void handle_usr1(int x) { - exit(0); + exit(0); } +char domain_id[64]; + void init(int xid) { char dbg_log[256]; @@ -63,6 +65,7 @@ void init(int xid) fprintf(stderr, "domain id=0?\n"); exit(1); } + snprintf(domain_id, sizeof(domain_id), "%d", xid); signal(SIGUSR1, handle_usr1); switch (fork()) { case -1: @@ -71,7 +74,7 @@ void init(int xid) case 0: break; default: - pause(); + pause(); exit(0); } close(0); @@ -94,6 +97,7 @@ void init(int xid) peer_client_init(xid, REXEC_PORT); setuid(getuid()); signal(SIGPIPE, SIG_IGN); + signal(SIGCHLD, SIG_IGN); signal(SIGUSR1, SIG_DFL); kill(getppid(), SIGUSR1); } @@ -242,6 +246,41 @@ void pass_to_client(int clid, struct client_header *hdr) } } +void handle_trigger_exec(int req) +{ + char *rcmd = NULL, *lcmd = NULL; + int i; + switch (req) { + case QREXEC_EXECUTE_FILE_COPY: + rcmd = "directly:user:/usr/lib/qubes/qfile-agent"; + lcmd = "/usr/lib/qubes/qfile-daemon"; + break; + case QREXEC_EXECUTE_FILE_COPY_FOR_DISPVM: + rcmd = "directly:user:/usr/lib/qubes/qfile-agent-dvm"; + lcmd = "/usr/lib/qubes/qfile-daemon-dvm"; + break; + default: + fprintf(stderr, "got trigger exec no %d\n", req); + exit(1); + } + switch (fork()) { + case -1: + perror("fork"); + exit(1); + case 0: + break; + default: + return; + } + for (i = 3; i < 256; i++) + close(i); + signal(SIGCHLD, SIG_DFL); + execl("/usr/lib/qubes/qrexec_client", "qrexec_client", "-d", + domain_id, "-l", lcmd, rcmd, NULL); + perror("execl"); + exit(1); +} + void handle_agent_data() { struct client_header hdr; @@ -251,6 +290,11 @@ void handle_agent_data() // fprintf(stderr, "got %x %x %x\n", s_hdr.type, s_hdr.clid, // s_hdr.len); + if (s_hdr.type == MSG_AGENT_TO_SERVER_TRIGGER_EXEC) { + handle_trigger_exec(s_hdr.clid); + return; + } + if (s_hdr.clid >= MAX_FDS || s_hdr.clid < 0) { fprintf(stderr, "from agent: clid=%d\n", s_hdr.clid); exit(1); diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index 8ca5daee..5d3038f3 100644 --- a/rpm_spec/core-appvm.spec +++ b/rpm_spec/core-appvm.spec @@ -107,6 +107,7 @@ install -D ../u2mfn/u2mfn-kernel.h $RPM_BUILD_ROOT/usr/include/u2mfn-kernel.h install -D ../vchan/libvchan.so $RPM_BUILD_ROOT/%{_libdir}/libvchan.so install -D ../u2mfn/libu2mfn.so $RPM_BUILD_ROOT/%{_libdir}/libu2mfn.so +mkdir -p $RPM_BUILD_ROOT/var/run/qubes %triggerin -- initscripts cp /var/lib/qubes/serial.conf /etc/init/serial.conf @@ -227,6 +228,7 @@ rm -rf $RPM_BUILD_ROOT /usr/include/libvchan.h %{_libdir}/libvchan.so %{_libdir}/libu2mfn.so +%dir /var/run/qubes %package devel diff --git a/rpm_spec/core-netvm.spec b/rpm_spec/core-netvm.spec index 6c88fcac..84df5cbe 100644 --- a/rpm_spec/core-netvm.spec +++ b/rpm_spec/core-netvm.spec @@ -83,6 +83,7 @@ cp ../common/vif-route-qubes $RPM_BUILD_ROOT/etc/xen/scripts install -D ../vchan/libvchan.so $RPM_BUILD_ROOT/%{_libdir}/libvchan.so install -D ../u2mfn/libu2mfn.so $RPM_BUILD_ROOT/%{_libdir}/libu2mfn.so +mkdir -p $RPM_BUILD_ROOT/var/run/qubes %triggerin -- initscripts cp /var/lib/qubes/serial.conf /etc/init/serial.conf @@ -193,3 +194,4 @@ rm -rf $RPM_BUILD_ROOT %dir /var/run/qubes %{_libdir}/libvchan.so %{_libdir}/libu2mfn.so +%dir /var/run/qubes