/* * The Qubes OS Project, http://www.qubes-os.org * * Copyright (C) 2010 Rafal Wojtczuk * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include "qrexec.h" #include "libqrexec-utils.h" static do_exec_t *exec_func = NULL; void register_exec_func(do_exec_t *func) { exec_func = func; } void exec_qubes_rpc_if_requested(char *prog, char *const envp[]) { /* avoid calling qubes-rpc-multiplexer through shell */ if (strncmp(prog, RPC_REQUEST_COMMAND, RPC_REQUEST_COMMAND_LEN) == 0) { char *tok; char *argv[16]; // right now 6 are used, but allow future extensions size_t i = 0; tok=strtok(prog, " "); do { if (i >= sizeof(argv)/sizeof(argv[0])-1) { fprintf(stderr, "To many arguments to %s\n", RPC_REQUEST_COMMAND); exit(1); } argv[i++] = tok; } while ((tok=strtok(NULL, " "))); argv[i] = NULL; argv[0] = QUBES_RPC_MULTIPLEXER_PATH; execve(QUBES_RPC_MULTIPLEXER_PATH, argv, envp); perror("exec qubes-rpc-multiplexer"); exit(1); } } void fix_fds(int fdin, int fdout, int fderr) { int i; for (i = 0; i < 256; i++) if (i != fdin && i != fdout && i != fderr) close(i); dup2(fdin, 0); dup2(fdout, 1); dup2(fderr, 2); close(fdin); close(fdout); if (fderr != 2) close(fderr); } void do_fork_exec(const char *cmdline, int *pid, int *stdin_fd, int *stdout_fd, int *stderr_fd) { int inpipe[2], outpipe[2], errpipe[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, inpipe) || socketpair(AF_UNIX, SOCK_STREAM, 0, outpipe) || (stderr_fd && socketpair(AF_UNIX, SOCK_STREAM, 0, errpipe))) { perror("socketpair"); exit(1); } switch (*pid = fork()) { case -1: perror("fork"); exit(-1); case 0: if (stderr_fd) { fix_fds(inpipe[0], outpipe[1], errpipe[1]); } else fix_fds(inpipe[0], outpipe[1], 2); if (exec_func != NULL) exec_func((char*)cmdline); exit(-1); default:; } close(inpipe[0]); close(outpipe[1]); *stdin_fd = inpipe[1]; *stdout_fd = outpipe[0]; if (stderr_fd) { close(errpipe[1]); *stderr_fd = errpipe[0]; } }