qubes-core-agent-linux/qrexec/qrexec-fork-server.c
Marek Marczykowski-Górecki 5068d939f1
qrexec: use exec_qubes_rpc_if_requested() from qubes-utils
This avoids duplicating service call parsing in multiple places.
Further improvements to that code (like avoid using shell) can be
implemented in one place.

(cherry picked from commit 5512e4eada)
2018-02-19 02:41:47 +01:00

119 lines
3.1 KiB
C

/*
* The Qubes OS Project, http://www.qubes-os.org
*
* Copyright (C) 2015 Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
*
* 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.
*
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "qrexec.h"
#include <libvchan.h>
#include "libqrexec-utils.h"
#include "qrexec-agent.h"
extern char **environ;
void do_exec(char *cmd)
{
signal(SIGCHLD, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
/* call QUBESRPC if requested */
exec_qubes_rpc_if_requested(cmd, environ);
execl("/bin/sh", "sh", "-c", cmd, NULL);
perror("execl");
exit(1);
}
void handle_vchan_error(const char *op)
{
fprintf(stderr, "Error while vchan %s, exiting\n", op);
exit(1);
}
void handle_single_command(int fd, struct qrexec_cmd_info *info) {
char cmdline[info->cmdline_len+1];
if (!read_all(fd, cmdline, info->cmdline_len))
return;
cmdline[info->cmdline_len] = 0;
handle_new_process(info->type, info->connect_domain,
info->connect_port,
cmdline, info->cmdline_len);
}
int main(int argc, char **argv) {
int s, fd;
char *socket_path;
struct qrexec_cmd_info info;
struct sockaddr_un peer;
unsigned int addrlen;
if (argc == 2) {
socket_path = argv[1];
} else if (argc == 1) {
/* this will be leaked, but we don't care as the process will then terminate */
if (asprintf(&socket_path, QREXEC_FORK_SERVER_SOCKET, getenv("USER")) < 0) {
fprintf(stderr, "Memory allocation failed\n");
exit(1);
}
} else {
fprintf(stderr, "Usage: %s [socket path]\n", argv[0]);
exit(1);
}
s = get_server_socket(socket_path);
if (fcntl(s, F_SETFD, O_CLOEXEC) < 0) {
perror("fcntl");
exit(1);
}
/* fork into background */
switch (fork()) {
case -1:
perror("fork");
exit(1);
case 0:
break;
default:
exit(0);
}
signal(SIGCHLD, SIG_IGN);
register_exec_func(do_exec);
while ((fd = accept(s, (struct sockaddr *) &peer, &addrlen)) >= 0) {
if (read_all(fd, &info, sizeof(info))) {
handle_single_command(fd, &info);
}
close(fd);
addrlen = sizeof(peer);
}
close(s);
unlink(socket_path);
return 0;
}