From 0ba692c85a903e4d22b5f8e004336e571a26a175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Fri, 27 Dec 2013 05:31:11 +0100 Subject: [PATCH] code style: change tabs to spaces --- qrexec/qrexec-client.c | 432 ++++++++-------- qrexec/qrexec-daemon.c | 1059 ++++++++++++++++++++-------------------- 2 files changed, 744 insertions(+), 747 deletions(-) diff --git a/qrexec/qrexec-client.c b/qrexec/qrexec-client.c index b863a2d..e275080 100644 --- a/qrexec/qrexec-client.c +++ b/qrexec/qrexec-client.c @@ -36,107 +36,107 @@ int replace_esc_stderr = 0; int connect_unix_socket(const char *domname) { - int s, len; - struct sockaddr_un remote; + int s, len; + struct sockaddr_un remote; - if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - perror("socket"); - return -1; - } + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("socket"); + return -1; + } - remote.sun_family = AF_UNIX; - snprintf(remote.sun_path, sizeof remote.sun_path, - QREXEC_DAEMON_SOCKET_DIR "/qrexec.%s", domname); - len = strlen(remote.sun_path) + sizeof(remote.sun_family); - if (connect(s, (struct sockaddr *) &remote, len) == -1) { - perror("connect"); - exit(1); - } - return s; + remote.sun_family = AF_UNIX; + snprintf(remote.sun_path, sizeof remote.sun_path, + QREXEC_DAEMON_SOCKET_DIR "/qrexec.%s", domname); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + if (connect(s, (struct sockaddr *) &remote, len) == -1) { + perror("connect"); + exit(1); + } + return s; } void do_exec(const char *prog) { - execl("/bin/bash", "bash", "-c", prog, NULL); + execl("/bin/bash", "bash", "-c", prog, NULL); } static int local_stdin_fd, local_stdout_fd; void do_exit(int code) { - int status; -// sever communication lines; wait for child, if any -// so that qrexec-daemon can count (recursively) spawned processes correctly - close(local_stdin_fd); - close(local_stdout_fd); - waitpid(-1, &status, 0); - exit(code); + int status; + // sever communication lines; wait for child, if any + // so that qrexec-daemon can count (recursively) spawned processes correctly + close(local_stdin_fd); + close(local_stdout_fd); + waitpid(-1, &status, 0); + exit(code); } void prepare_local_fds(const char *cmdline) { - int pid; - if (!cmdline) { - local_stdin_fd = 1; - local_stdout_fd = 0; - return; - } - do_fork_exec(cmdline, &pid, &local_stdin_fd, &local_stdout_fd, - NULL); + int pid; + if (!cmdline) { + local_stdin_fd = 1; + local_stdout_fd = 0; + return; + } + do_fork_exec(cmdline, &pid, &local_stdin_fd, &local_stdout_fd, + NULL); } void send_cmdline(int s, int type, const char *cmdline) { - struct client_header hdr; - hdr.type = type; - hdr.len = strlen(cmdline) + 1; - if (!write_all(s, &hdr, sizeof(hdr)) - || !write_all(s, cmdline, hdr.len)) { - perror("write daemon"); - do_exit(1); - } + struct client_header hdr; + hdr.type = type; + hdr.len = strlen(cmdline) + 1; + if (!write_all(s, &hdr, sizeof(hdr)) + || !write_all(s, cmdline, hdr.len)) { + perror("write daemon"); + do_exit(1); + } } void handle_input(int s) { - char buf[MAX_DATA_CHUNK]; - int ret; - ret = read(local_stdout_fd, buf, sizeof(buf)); - if (ret < 0) { - perror("read"); - do_exit(1); - } - if (ret == 0) { - close(local_stdout_fd); - local_stdout_fd = -1; - shutdown(s, SHUT_WR); - if (local_stdin_fd == -1) { - // if pipe in opposite direction already closed, no need to stay alive - do_exit(0); - } - } - if (!write_all(s, buf, ret)) { - if (errno == EPIPE) { - // daemon disconnected its end of socket, so no future data will be - // send there; there is no sense to read from child stdout - // - // since AF_UNIX socket is buffered it doesn't mean all data was - // received from the agent - close(local_stdout_fd); - local_stdout_fd = -1; - if (local_stdin_fd == -1) { - // since child does no longer accept data on its stdin, doesn't - // make sense to process the data from the daemon - // - // we don't know real exit VM process code (exiting here, before - // MSG_SERVER_TO_CLIENT_EXIT_CODE message) - do_exit(1); - } - } else - perror("write daemon"); - } + char buf[MAX_DATA_CHUNK]; + int ret; + ret = read(local_stdout_fd, buf, sizeof(buf)); + if (ret < 0) { + perror("read"); + do_exit(1); + } + if (ret == 0) { + close(local_stdout_fd); + local_stdout_fd = -1; + shutdown(s, SHUT_WR); + if (local_stdin_fd == -1) { + // if pipe in opposite direction already closed, no need to stay alive + do_exit(0); + } + } + if (!write_all(s, buf, ret)) { + if (errno == EPIPE) { + // daemon disconnected its end of socket, so no future data will be + // send there; there is no sense to read from child stdout + // + // since AF_UNIX socket is buffered it doesn't mean all data was + // received from the agent + close(local_stdout_fd); + local_stdout_fd = -1; + if (local_stdin_fd == -1) { + // since child does no longer accept data on its stdin, doesn't + // make sense to process the data from the daemon + // + // we don't know real exit VM process code (exiting here, before + // MSG_SERVER_TO_CLIENT_EXIT_CODE message) + do_exit(1); + } + } else + perror("write daemon"); + } } void do_replace_esc(char *buf, int len) { @@ -149,170 +149,170 @@ void do_replace_esc(char *buf, int len) { void handle_daemon_data(int s) { - int status; - struct client_header hdr; - char buf[MAX_DATA_CHUNK], *bufptr=buf; + int status; + struct client_header hdr; + char buf[MAX_DATA_CHUNK], *bufptr=buf; - if (!read_all(s, &hdr, sizeof hdr)) { - perror("read daemon"); - do_exit(1); - } - if (hdr.len > MAX_DATA_CHUNK) { - fprintf(stderr, "client_header.len=%d\n", hdr.len); - do_exit(1); - } - if (!read_all(s, buf, hdr.len)) { - perror("read daemon"); - do_exit(1); - } + if (!read_all(s, &hdr, sizeof hdr)) { + perror("read daemon"); + do_exit(1); + } + if (hdr.len > MAX_DATA_CHUNK) { + fprintf(stderr, "client_header.len=%d\n", hdr.len); + do_exit(1); + } + if (!read_all(s, buf, hdr.len)) { + perror("read daemon"); + do_exit(1); + } - switch (hdr.type) { - case MSG_SERVER_TO_CLIENT_STDOUT: - if (replace_esc_stdout) - do_replace_esc(buf, hdr.len); - if (local_stdin_fd == -1) - break; - if (hdr.len == 0) { - close(local_stdin_fd); - local_stdin_fd = -1; - } else if (!write_all(local_stdin_fd, buf, hdr.len)) { - if (errno == EPIPE) { - // remote side have closed its stdin, handle data in oposite - // direction (if any) before exit - local_stdin_fd = -1; - } else { - perror("write local stdout"); - do_exit(1); - } - } - break; - case MSG_SERVER_TO_CLIENT_STDERR: - if (replace_esc_stderr) - do_replace_esc(buf, hdr.len); - write_all(2, buf, hdr.len); - break; - case MSG_SERVER_TO_CLIENT_EXIT_CODE: - status = *(unsigned int *) bufptr; - if (WIFEXITED(status)) - do_exit(WEXITSTATUS(status)); - else - do_exit(255); - break; - default: - fprintf(stderr, "unknown msg %d\n", hdr.type); - do_exit(1); - } + switch (hdr.type) { + case MSG_SERVER_TO_CLIENT_STDOUT: + if (replace_esc_stdout) + do_replace_esc(buf, hdr.len); + if (local_stdin_fd == -1) + break; + if (hdr.len == 0) { + close(local_stdin_fd); + local_stdin_fd = -1; + } else if (!write_all(local_stdin_fd, buf, hdr.len)) { + if (errno == EPIPE) { + // remote side have closed its stdin, handle data in oposite + // direction (if any) before exit + local_stdin_fd = -1; + } else { + perror("write local stdout"); + do_exit(1); + } + } + break; + case MSG_SERVER_TO_CLIENT_STDERR: + if (replace_esc_stderr) + do_replace_esc(buf, hdr.len); + write_all(2, buf, hdr.len); + break; + case MSG_SERVER_TO_CLIENT_EXIT_CODE: + status = *(unsigned int *) bufptr; + if (WIFEXITED(status)) + do_exit(WEXITSTATUS(status)); + else + do_exit(255); + break; + default: + fprintf(stderr, "unknown msg %d\n", hdr.type); + do_exit(1); + } } // perhaps we could save a syscall if we include both sides in both // rdset and wrset; to be investigated void handle_daemon_only_until_writable(int s) { - fd_set rdset, wrset; + fd_set rdset, wrset; - do { - FD_ZERO(&rdset); - FD_ZERO(&wrset); - FD_SET(s, &rdset); - FD_SET(s, &wrset); + do { + FD_ZERO(&rdset); + FD_ZERO(&wrset); + FD_SET(s, &rdset); + FD_SET(s, &wrset); - if (select(s + 1, &rdset, &wrset, NULL, NULL) < 0) { - perror("select"); - do_exit(1); - } - if (FD_ISSET(s, &rdset)) - handle_daemon_data(s); - } while (!FD_ISSET(s, &wrset)); + if (select(s + 1, &rdset, &wrset, NULL, NULL) < 0) { + perror("select"); + do_exit(1); + } + if (FD_ISSET(s, &rdset)) + handle_daemon_data(s); + } while (!FD_ISSET(s, &wrset)); } void select_loop(int s) { - fd_set select_set; - int max; - for (;;) { - handle_daemon_only_until_writable(s); - FD_ZERO(&select_set); - FD_SET(s, &select_set); - max = s; - if (local_stdout_fd != -1) { - FD_SET(local_stdout_fd, &select_set); - if (s < local_stdout_fd) - max = local_stdout_fd; - } - if (select(max + 1, &select_set, NULL, NULL, NULL) < 0) { - perror("select"); - do_exit(1); - } - if (FD_ISSET(s, &select_set)) - handle_daemon_data(s); - if (local_stdout_fd != -1 - && FD_ISSET(local_stdout_fd, &select_set)) - handle_input(s); - } + fd_set select_set; + int max; + for (;;) { + handle_daemon_only_until_writable(s); + FD_ZERO(&select_set); + FD_SET(s, &select_set); + max = s; + if (local_stdout_fd != -1) { + FD_SET(local_stdout_fd, &select_set); + if (s < local_stdout_fd) + max = local_stdout_fd; + } + if (select(max + 1, &select_set, NULL, NULL, NULL) < 0) { + perror("select"); + do_exit(1); + } + if (FD_ISSET(s, &select_set)) + handle_daemon_data(s); + if (local_stdout_fd != -1 + && FD_ISSET(local_stdout_fd, &select_set)) + handle_input(s); + } } void usage(const char *name) { - fprintf(stderr, - "usage: %s -d domain_num [-l local_prog] -e -t -T -c remote_cmdline\n" - "-e means exit after sending cmd, -c: connect to existing process\n" - "-t enables replacing ESC character with '_' in command output, -T is the same for stderr\n", - name); - exit(1); + fprintf(stderr, + "usage: %s -d domain_num [-l local_prog] -e -t -T -c remote_cmdline\n" + "-e means exit after sending cmd, -c: connect to existing process\n" + "-t enables replacing ESC character with '_' in command output, -T is the same for stderr\n", + name); + exit(1); } int main(int argc, char **argv) { - int opt; - char *domname = NULL; - int s; - int just_exec = 0; - int connect_existing = 0; - char *local_cmdline = NULL; - while ((opt = getopt(argc, argv, "d:l:ectT")) != -1) { - switch (opt) { - case 'd': - domname = strdup(optarg); - break; - case 'l': - local_cmdline = strdup(optarg); - break; - case 'e': - just_exec = 1; - break; - case 'c': - connect_existing = 1; - break; - case 't': - replace_esc_stdout = 1; - break; - case 'T': - replace_esc_stderr = 1; - break; - default: - usage(argv[0]); - } - } - if (optind >= argc || !domname) - usage(argv[0]); + int opt; + char *domname = NULL; + int s; + int just_exec = 0; + int connect_existing = 0; + char *local_cmdline = NULL; + while ((opt = getopt(argc, argv, "d:l:ectT")) != -1) { + switch (opt) { + case 'd': + domname = strdup(optarg); + break; + case 'l': + local_cmdline = strdup(optarg); + break; + case 'e': + just_exec = 1; + break; + case 'c': + connect_existing = 1; + break; + case 't': + replace_esc_stdout = 1; + break; + case 'T': + replace_esc_stderr = 1; + break; + default: + usage(argv[0]); + } + } + if (optind >= argc || !domname) + usage(argv[0]); - register_exec_func(&do_exec); + register_exec_func(&do_exec); - s = connect_unix_socket(domname); - setenv("QREXEC_REMOTE_DOMAIN", domname, 1); - prepare_local_fds(local_cmdline); + s = connect_unix_socket(domname); + setenv("QREXEC_REMOTE_DOMAIN", domname, 1); + prepare_local_fds(local_cmdline); - if (just_exec) - send_cmdline(s, MSG_CLIENT_TO_SERVER_JUST_EXEC, - argv[optind]); - else { - int cmd; - if (connect_existing) - cmd = MSG_CLIENT_TO_SERVER_CONNECT_EXISTING; - else - cmd = MSG_CLIENT_TO_SERVER_EXEC_CMDLINE; - send_cmdline(s, cmd, argv[optind]); - select_loop(s); - } - return 0; + if (just_exec) + send_cmdline(s, MSG_CLIENT_TO_SERVER_JUST_EXEC, + argv[optind]); + else { + int cmd; + if (connect_existing) + cmd = MSG_CLIENT_TO_SERVER_CONNECT_EXISTING; + else + cmd = MSG_CLIENT_TO_SERVER_EXEC_CMDLINE; + send_cmdline(s, cmd, argv[optind]); + select_loop(s); + } + return 0; } diff --git a/qrexec/qrexec-daemon.c b/qrexec/qrexec-daemon.c index 95d5aa6..dd2acd7 100644 --- a/qrexec/qrexec-daemon.c +++ b/qrexec/qrexec-daemon.c @@ -33,24 +33,24 @@ #include "libqrexec-utils.h" enum client_flags { - CLIENT_INVALID = 0, // table slot not used - CLIENT_CMDLINE = 1, // waiting for cmdline from client - CLIENT_DATA = 2, // waiting for data from client - CLIENT_DONT_READ = 4, // don't read from the client, the other side pipe is full, or EOF (additionally marked with CLIENT_EOF) - CLIENT_OUTQ_FULL = 8, // don't write to client, its stdin pipe is full - CLIENT_EOF = 16, // got EOF - CLIENT_EXITED = 32 // only send remaining data from client and remove from list + CLIENT_INVALID = 0, // table slot not used + CLIENT_CMDLINE = 1, // waiting for cmdline from client + CLIENT_DATA = 2, // waiting for data from client + CLIENT_DONT_READ = 4, // don't read from the client, the other side pipe is full, or EOF (additionally marked with CLIENT_EOF) + CLIENT_OUTQ_FULL = 8, // don't write to client, its stdin pipe is full + CLIENT_EOF = 16, // got EOF + CLIENT_EXITED = 32 // only send remaining data from client and remove from list }; struct _client { - int state; // combination of above enum client_flags - struct buffer buffer; // buffered data to client, if any + int state; // combination of above enum client_flags + struct buffer buffer; // buffered data to client, if any }; /* -The "clients" array is indexed by client's fd. -Thus its size must be equal MAX_FDS; defining MAX_CLIENTS for clarity. -*/ + The "clients" array is indexed by client's fd. + Thus its size must be equal MAX_FDS; defining MAX_CLIENTS for clarity. + */ #define MAX_CLIENTS MAX_FDS struct _client clients[MAX_CLIENTS]; // data on all qrexec_client connections @@ -75,22 +75,22 @@ libvchan_t *vchan; void sigusr1_handler(int UNUSED(x)) { - if (!opt_quiet) - fprintf(stderr, "connected\n"); - exit(0); + if (!opt_quiet) + fprintf(stderr, "connected\n"); + exit(0); } void sigchld_parent_handler(int UNUSED(x)) { - children_count--; - /* starting value is 0 so we see dead real qrexec-daemon as -1 */ - if (children_count < 0) { - if (!opt_quiet) - fprintf(stderr, "failed\n"); - else - fprintf(stderr, "Connection to the VM failed\n"); - exit(1); - } + children_count--; + /* starting value is 0 so we see dead real qrexec-daemon as -1 */ + if (children_count < 0) { + if (!opt_quiet) + fprintf(stderr, "failed\n"); + else + fprintf(stderr, "Connection to the VM failed\n"); + exit(1); + } } void sigchld_handler(int x); @@ -100,39 +100,39 @@ int remote_domain_xid; // guess what void unlink_qrexec_socket() { - char socket_address[40]; - char link_to_socket_name[strlen(remote_domain_name) + sizeof(socket_address)]; + char socket_address[40]; + char link_to_socket_name[strlen(remote_domain_name) + sizeof(socket_address)]; - snprintf(socket_address, sizeof(socket_address), - QREXEC_DAEMON_SOCKET_DIR "/qrexec.%d", remote_domain_xid); - snprintf(link_to_socket_name, sizeof link_to_socket_name, - QREXEC_DAEMON_SOCKET_DIR "/qrexec.%s", remote_domain_name); - unlink(socket_address); - unlink(link_to_socket_name); + snprintf(socket_address, sizeof(socket_address), + QREXEC_DAEMON_SOCKET_DIR "/qrexec.%d", remote_domain_xid); + snprintf(link_to_socket_name, sizeof link_to_socket_name, + QREXEC_DAEMON_SOCKET_DIR "/qrexec.%s", remote_domain_name); + unlink(socket_address); + unlink(link_to_socket_name); } void handle_vchan_error(const char *op) { - fprintf(stderr, "Error while vchan %s, exiting\n", op); - exit(1); + fprintf(stderr, "Error while vchan %s, exiting\n", op); + exit(1); } int create_qrexec_socket(int domid, const char *domname) { - char socket_address[40]; - char link_to_socket_name[strlen(domname) + sizeof(socket_address)]; + char socket_address[40]; + char link_to_socket_name[strlen(domname) + sizeof(socket_address)]; - snprintf(socket_address, sizeof(socket_address), - QREXEC_DAEMON_SOCKET_DIR "/qrexec.%d", domid); - snprintf(link_to_socket_name, sizeof link_to_socket_name, - QREXEC_DAEMON_SOCKET_DIR "/qrexec.%s", domname); - unlink(link_to_socket_name); - if (symlink(socket_address, link_to_socket_name)) { - fprintf(stderr, "symlink(%s,%s) failed: %s\n", socket_address, - link_to_socket_name, strerror (errno)); - } - atexit(unlink_qrexec_socket); - return get_server_socket(socket_address); + snprintf(socket_address, sizeof(socket_address), + QREXEC_DAEMON_SOCKET_DIR "/qrexec.%d", domid); + snprintf(link_to_socket_name, sizeof link_to_socket_name, + QREXEC_DAEMON_SOCKET_DIR "/qrexec.%s", domname); + unlink(link_to_socket_name); + if (symlink(socket_address, link_to_socket_name)) { + fprintf(stderr, "symlink(%s,%s) failed: %s\n", socket_address, + link_to_socket_name, strerror (errno)); + } + atexit(unlink_qrexec_socket); + return get_server_socket(socket_address); } #define MAX_STARTUP_TIME_DEFAULT 60 @@ -140,600 +140,597 @@ int create_qrexec_socket(int domid, const char *domname) /* do the preparatory tasks, needed before entering the main event loop */ void init(int xid) { - char qrexec_error_log_name[256]; - int logfd; - int i; - pid_t pid; - int startup_timeout = MAX_STARTUP_TIME_DEFAULT; - const char *startup_timeout_str = NULL; + char qrexec_error_log_name[256]; + int logfd; + int i; + pid_t pid; + int startup_timeout = MAX_STARTUP_TIME_DEFAULT; + const char *startup_timeout_str = NULL; - if (xid <= 0) { - fprintf(stderr, "domain id=0?\n"); - exit(1); - } - startup_timeout_str = getenv("QREXEC_STARTUP_TIMEOUT"); - if (startup_timeout_str) { - startup_timeout = atoi(startup_timeout_str); - if (startup_timeout <= 0) - // invalid or negative number - startup_timeout = MAX_STARTUP_TIME_DEFAULT; - } - signal(SIGUSR1, sigusr1_handler); - signal(SIGCHLD, sigchld_parent_handler); - switch (pid=fork()) { - case -1: - perror("fork"); - exit(1); - case 0: - break; - default: - if (getenv("QREXEC_STARTUP_NOWAIT")) - exit(0); - if (!opt_quiet) - fprintf(stderr, "Waiting for VM's qrexec agent."); - for (i=0;i= MAX_CLIENTS) { - fprintf(stderr, "too many clients ?\n"); - exit(1); - } - clients[fd].state = CLIENT_CMDLINE; - buffer_init(&clients[fd].buffer); - if (fd > max_client_fd) - max_client_fd = fd; + int fd = do_accept(qrexec_daemon_unix_socket_fd); + if (fd >= MAX_CLIENTS) { + fprintf(stderr, "too many clients ?\n"); + exit(1); + } + clients[fd].state = CLIENT_CMDLINE; + buffer_init(&clients[fd].buffer); + if (fd > max_client_fd) + max_client_fd = fd; } void terminate_client_and_flush_data(int fd) { - int i; - struct server_header s_hdr; + int i; + struct server_header s_hdr; - if (!(clients[fd].state & CLIENT_EXITED) && fork_and_flush_stdin(fd, &clients[fd].buffer)) - children_count++; - close(fd); - clients[fd].state = CLIENT_INVALID; - buffer_free(&clients[fd].buffer); - if (max_client_fd == fd) { - for (i = fd; i >= 0 && clients[i].state == CLIENT_INVALID; - i--); - max_client_fd = i; - } - s_hdr.type = MSG_SERVER_TO_AGENT_CLIENT_END; - s_hdr.client_id = fd; - s_hdr.len = 0; - if (libvchan_send(vchan, &s_hdr, sizeof(s_hdr)) < 0) - handle_vchan_error("send"); + if (!(clients[fd].state & CLIENT_EXITED) && fork_and_flush_stdin(fd, &clients[fd].buffer)) + children_count++; + close(fd); + clients[fd].state = CLIENT_INVALID; + buffer_free(&clients[fd].buffer); + if (max_client_fd == fd) { + for (i = fd; i >= 0 && clients[i].state == CLIENT_INVALID; + i--); + max_client_fd = i; + } + s_hdr.type = MSG_SERVER_TO_AGENT_CLIENT_END; + s_hdr.client_id = fd; + s_hdr.len = 0; + if (libvchan_send(vchan, &s_hdr, sizeof(s_hdr)) < 0) + handle_vchan_error("send"); } int get_cmdline_body_from_client_and_pass_to_agent(int fd, struct server_header - *s_hdr) + *s_hdr) { - int len = s_hdr->len; - char buf[len]; - int use_default_user = 0; - if (!read_all(fd, buf, len)) { - terminate_client_and_flush_data(fd); - return 0; - } - if (!strncmp(buf, default_user_keyword, default_user_keyword_len_without_colon+1)) { - use_default_user = 1; - s_hdr->len -= default_user_keyword_len_without_colon; // -1 because of colon - s_hdr->len += strlen(default_user); - } - if (libvchan_send(vchan, s_hdr, sizeof(*s_hdr)) < 0) - handle_vchan_error("send"); - if (use_default_user) { - if (libvchan_send(vchan, default_user, strlen(default_user)) < 0) - handle_vchan_error("send default_user"); - if (libvchan_send(vchan, buf+default_user_keyword_len_without_colon, - len-default_user_keyword_len_without_colon) < 0) - handle_vchan_error("send buf"); - } else - if (libvchan_send(vchan, buf, len) < 0) - handle_vchan_error("send buf"); - return 1; + int len = s_hdr->len; + char buf[len]; + int use_default_user = 0; + if (!read_all(fd, buf, len)) { + terminate_client_and_flush_data(fd); + return 0; + } + if (!strncmp(buf, default_user_keyword, default_user_keyword_len_without_colon+1)) { + use_default_user = 1; + s_hdr->len -= default_user_keyword_len_without_colon; // -1 because of colon + s_hdr->len += strlen(default_user); + } + if (libvchan_send(vchan, s_hdr, sizeof(*s_hdr)) < 0) + handle_vchan_error("send"); + if (use_default_user) { + if (libvchan_send(vchan, default_user, strlen(default_user)) < 0) + handle_vchan_error("send default_user"); + if (libvchan_send(vchan, buf+default_user_keyword_len_without_colon, + len-default_user_keyword_len_without_colon) < 0) + handle_vchan_error("send buf"); + } else + if (libvchan_send(vchan, buf, len) < 0) + handle_vchan_error("send buf"); + return 1; } void handle_cmdline_message_from_client(int fd) { - struct client_header hdr; - struct server_header s_hdr; - if (!read_all(fd, &hdr, sizeof hdr)) { - terminate_client_and_flush_data(fd); - return; - } - switch (hdr.type) { - case MSG_CLIENT_TO_SERVER_EXEC_CMDLINE: - s_hdr.type = MSG_SERVER_TO_AGENT_EXEC_CMDLINE; - break; - case MSG_CLIENT_TO_SERVER_JUST_EXEC: - s_hdr.type = MSG_SERVER_TO_AGENT_JUST_EXEC; - break; - case MSG_CLIENT_TO_SERVER_CONNECT_EXISTING: - s_hdr.type = MSG_SERVER_TO_AGENT_CONNECT_EXISTING; - break; - default: - terminate_client_and_flush_data(fd); - return; - } + struct client_header hdr; + struct server_header s_hdr; + if (!read_all(fd, &hdr, sizeof hdr)) { + terminate_client_and_flush_data(fd); + return; + } + switch (hdr.type) { + case MSG_CLIENT_TO_SERVER_EXEC_CMDLINE: + s_hdr.type = MSG_SERVER_TO_AGENT_EXEC_CMDLINE; + break; + case MSG_CLIENT_TO_SERVER_JUST_EXEC: + s_hdr.type = MSG_SERVER_TO_AGENT_JUST_EXEC; + break; + case MSG_CLIENT_TO_SERVER_CONNECT_EXISTING: + s_hdr.type = MSG_SERVER_TO_AGENT_CONNECT_EXISTING; + break; + default: + terminate_client_and_flush_data(fd); + return; + } - s_hdr.client_id = fd; - s_hdr.len = hdr.len; - if (!get_cmdline_body_from_client_and_pass_to_agent(fd, &s_hdr)) - // client disconnected while sending cmdline, above call already - // cleaned up client info - return; - clients[fd].state = CLIENT_DATA; - set_nonblock(fd); // so that we can detect full queue without blocking - if (hdr.type == MSG_CLIENT_TO_SERVER_JUST_EXEC) - terminate_client_and_flush_data(fd); + s_hdr.client_id = fd; + s_hdr.len = hdr.len; + if (!get_cmdline_body_from_client_and_pass_to_agent(fd, &s_hdr)) + // client disconnected while sending cmdline, above call already + // cleaned up client info + return; + clients[fd].state = CLIENT_DATA; + set_nonblock(fd); // so that we can detect full queue without blocking + if (hdr.type == MSG_CLIENT_TO_SERVER_JUST_EXEC) + terminate_client_and_flush_data(fd); } /* handle data received from one of qrexec_client processes */ void handle_message_from_client(int fd) { - struct server_header s_hdr; - char buf[MAX_DATA_CHUNK]; - unsigned int len; - int ret; + struct server_header s_hdr; + char buf[MAX_DATA_CHUNK]; + unsigned int len; + int ret; - if (clients[fd].state == CLIENT_CMDLINE) { - handle_cmdline_message_from_client(fd); - return; - } - // We have already passed cmdline from client. - // Now the client passes us raw data from its stdin. - len = libvchan_buffer_space(vchan); - if (len <= sizeof s_hdr) - return; - /* Read at most the amount of data that we have room for in vchan */ - ret = read(fd, buf, len - sizeof(s_hdr)); - if (ret < 0) { - perror("read client"); - terminate_client_and_flush_data(fd); - return; - } - s_hdr.client_id = fd; - s_hdr.len = ret; - s_hdr.type = MSG_SERVER_TO_AGENT_INPUT; + if (clients[fd].state == CLIENT_CMDLINE) { + handle_cmdline_message_from_client(fd); + return; + } + // We have already passed cmdline from client. + // Now the client passes us raw data from its stdin. + len = libvchan_buffer_space(vchan); + if (len <= sizeof s_hdr) + return; + /* Read at most the amount of data that we have room for in vchan */ + ret = read(fd, buf, len - sizeof(s_hdr)); + if (ret < 0) { + perror("read client"); + terminate_client_and_flush_data(fd); + return; + } + s_hdr.client_id = fd; + s_hdr.len = ret; + s_hdr.type = MSG_SERVER_TO_AGENT_INPUT; - if (libvchan_send(vchan, &s_hdr, sizeof(s_hdr)) < 0) - handle_vchan_error("send hdr"); - if (libvchan_send(vchan, buf, ret) < 0) - handle_vchan_error("send buf"); - if (ret == 0) // EOF - so don't select() on this client - clients[fd].state |= CLIENT_DONT_READ | CLIENT_EOF; - if (clients[fd].state & CLIENT_EXITED) - //client already exited and all data sent - cleanup now - terminate_client_and_flush_data(fd); + if (libvchan_send(vchan, &s_hdr, sizeof(s_hdr)) < 0) + handle_vchan_error("send hdr"); + if (libvchan_send(vchan, buf, ret) < 0) + handle_vchan_error("send buf"); + if (ret == 0) // EOF - so don't select() on this client + clients[fd].state |= CLIENT_DONT_READ | CLIENT_EOF; + if (clients[fd].state & CLIENT_EXITED) + //client already exited and all data sent - cleanup now + terminate_client_and_flush_data(fd); } -/* -Called when there is buffered data for this client, and select() reports -that client's pipe is writable; so we should be able to flush some -buffered data. -*/ +/* + * Called when there is buffered data for this client, and select() reports + * that client's pipe is writable; so we should be able to flush some + * buffered data. + */ void write_buffered_data_to_client(int client_id) { - switch (flush_client_data - (vchan, client_id, client_id, &clients[client_id].buffer)) { - case WRITE_STDIN_OK: // no more buffered data - clients[client_id].state &= ~CLIENT_OUTQ_FULL; - break; - case WRITE_STDIN_ERROR: - // do not write to this fd anymore - clients[client_id].state |= CLIENT_EXITED; - if (clients[client_id].state & CLIENT_EOF) - terminate_client_and_flush_data(client_id); - else - // client will be removed when read returns 0 (EOF) - // clear CLIENT_OUTQ_FULL flag to no select on this fd anymore - clients[client_id].state &= ~CLIENT_OUTQ_FULL; - break; - case WRITE_STDIN_BUFFERED: // no room for all data, don't clear CLIENT_OUTQ_FULL flag - break; - default: - fprintf(stderr, "unknown flush_client_data?\n"); - exit(1); - } + switch (flush_client_data + (vchan, client_id, client_id, &clients[client_id].buffer)) { + case WRITE_STDIN_OK: // no more buffered data + clients[client_id].state &= ~CLIENT_OUTQ_FULL; + break; + case WRITE_STDIN_ERROR: + // do not write to this fd anymore + clients[client_id].state |= CLIENT_EXITED; + if (clients[client_id].state & CLIENT_EOF) + terminate_client_and_flush_data(client_id); + else + // client will be removed when read returns 0 (EOF) + // clear CLIENT_OUTQ_FULL flag to no select on this fd anymore + clients[client_id].state &= ~CLIENT_OUTQ_FULL; + break; + case WRITE_STDIN_BUFFERED: // no room for all data, don't clear CLIENT_OUTQ_FULL flag + break; + default: + fprintf(stderr, "unknown flush_client_data?\n"); + exit(1); + } } -/* -The header (hdr argument) is already built. Just read the raw data from -the packet, and pass it along with the header to the client. -*/ +/* + * The header (hdr argument) is already built. Just read the raw data from + * the packet, and pass it along with the header to the client. + */ void get_packet_data_from_agent_and_pass_to_client(int client_id, struct client_header - *hdr) + *hdr) { - int len = hdr->len; - char buf[sizeof(*hdr) + len]; + int len = hdr->len; + char buf[sizeof(*hdr) + len]; - /* make both the header and data be consecutive in the buffer */ - memcpy(buf, hdr, sizeof(*hdr)); - if (libvchan_recv(vchan, buf + sizeof(*hdr), len) < 0) - handle_vchan_error("recv buf"); - if (clients[client_id].state & CLIENT_EXITED) - // ignore data for no longer running client - return; + /* make both the header and data be consecutive in the buffer */ + memcpy(buf, hdr, sizeof(*hdr)); + if (libvchan_recv(vchan, buf + sizeof(*hdr), len) < 0) + handle_vchan_error("recv buf"); + if (clients[client_id].state & CLIENT_EXITED) + // ignore data for no longer running client + return; - switch (write_stdin - (vchan, client_id, client_id, buf, len + sizeof(*hdr), - &clients[client_id].buffer)) { - case WRITE_STDIN_OK: - break; - case WRITE_STDIN_BUFFERED: // some data have been buffered - clients[client_id].state |= CLIENT_OUTQ_FULL; - break; - case WRITE_STDIN_ERROR: - // do not write to this fd anymore - clients[client_id].state |= CLIENT_EXITED; - // if already got EOF, remove client - if (clients[client_id].state & CLIENT_EOF) - terminate_client_and_flush_data(client_id); - break; - default: - fprintf(stderr, "unknown write_stdin?\n"); - exit(1); - } + switch (write_stdin + (vchan, client_id, client_id, buf, len + sizeof(*hdr), + &clients[client_id].buffer)) { + case WRITE_STDIN_OK: + break; + case WRITE_STDIN_BUFFERED: // some data have been buffered + clients[client_id].state |= CLIENT_OUTQ_FULL; + break; + case WRITE_STDIN_ERROR: + // do not write to this fd anymore + clients[client_id].state |= CLIENT_EXITED; + // if already got EOF, remove client + if (clients[client_id].state & CLIENT_EOF) + terminate_client_and_flush_data(client_id); + break; + default: + fprintf(stderr, "unknown write_stdin?\n"); + exit(1); + } } -/* -The signal handler executes asynchronously; therefore all it should do is -to set a flag "signal has arrived", and let the main even loop react to this -flag in appropriate moment. -*/ +/* + * The signal handler executes asynchronously; therefore all it should do is + * to set a flag "signal has arrived", and let the main even loop react to this + * flag in appropriate moment. + */ int child_exited; void sigchld_handler(int UNUSED(x)) { - child_exited = 1; - signal(SIGCHLD, sigchld_handler); + child_exited = 1; + signal(SIGCHLD, sigchld_handler); } /* clean zombies, update children_count */ void reap_children(void) { - int status; - while (waitpid(-1, &status, WNOHANG) > 0) - children_count--; - child_exited = 0; + int status; + while (waitpid(-1, &status, WNOHANG) > 0) + children_count--; + child_exited = 0; } /* too many children - wait for one of them to terminate */ void wait_for_child(void) { - int status; - waitpid(-1, &status, 0); - children_count--; + int status; + waitpid(-1, &status, 0); + children_count--; } #define MAX_CHILDREN 10 void check_children_count_and_wait_if_too_many(void) { - if (children_count > MAX_CHILDREN) { - fprintf(stderr, - "max number of children reached, waiting for child exit...\n"); - wait_for_child(); - fprintf(stderr, "now children_count=%d, continuing.\n", - children_count); - } + if (children_count > MAX_CHILDREN) { + fprintf(stderr, + "max number of children reached, waiting for child exit...\n"); + wait_for_child(); + fprintf(stderr, "now children_count=%d, continuing.\n", + children_count); + } } void sanitize_name(char * untrusted_s_signed) { - unsigned char * untrusted_s; - for (untrusted_s=(unsigned char*)untrusted_s_signed; *untrusted_s; untrusted_s++) { - if (*untrusted_s >= 'a' && *untrusted_s <= 'z') - continue; - if (*untrusted_s >= 'A' && *untrusted_s <= 'Z') - continue; - if (*untrusted_s >= '0' && *untrusted_s <= '9') - continue; - if (*untrusted_s == '$' || *untrusted_s == '_' || *untrusted_s == '-' || *untrusted_s == '.' || *untrusted_s == ' ') - continue; - *untrusted_s = '_'; - } + unsigned char * untrusted_s; + for (untrusted_s=(unsigned char*)untrusted_s_signed; *untrusted_s; untrusted_s++) { + if (*untrusted_s >= 'a' && *untrusted_s <= 'z') + continue; + if (*untrusted_s >= 'A' && *untrusted_s <= 'Z') + continue; + if (*untrusted_s >= '0' && *untrusted_s <= '9') + continue; + if (*untrusted_s == '$' || *untrusted_s == '_' || *untrusted_s == '-' || *untrusted_s == '.' || *untrusted_s == ' ') + continue; + *untrusted_s = '_'; + } } - + #define ENSURE_NULL_TERMINATED(x) x[sizeof(x)-1] = 0 -/* -Called when agent sends a message asking to execute a predefined command. -*/ +/* + * Called when agent sends a message asking to execute a predefined command. + */ void handle_execute_predefined_command(void) { - int i; - struct trigger_connect_params untrusted_params, params; + int i; + struct trigger_connect_params untrusted_params, params; - check_children_count_and_wait_if_too_many(); - if (libvchan_recv(vchan, &untrusted_params, sizeof(params)) < 0) - handle_vchan_error("recv params"); + check_children_count_and_wait_if_too_many(); + if (libvchan_recv(vchan, &untrusted_params, sizeof(params)) < 0) + handle_vchan_error("recv params"); - /* sanitize start */ - ENSURE_NULL_TERMINATED(untrusted_params.exec_index); - ENSURE_NULL_TERMINATED(untrusted_params.target_vmname); - ENSURE_NULL_TERMINATED(untrusted_params.process_fds.ident); - sanitize_name(untrusted_params.exec_index); - sanitize_name(untrusted_params.target_vmname); - sanitize_name(untrusted_params.process_fds.ident); - params = untrusted_params; - /* sanitize end */ + /* sanitize start */ + ENSURE_NULL_TERMINATED(untrusted_params.exec_index); + ENSURE_NULL_TERMINATED(untrusted_params.target_vmname); + ENSURE_NULL_TERMINATED(untrusted_params.process_fds.ident); + sanitize_name(untrusted_params.exec_index); + sanitize_name(untrusted_params.target_vmname); + sanitize_name(untrusted_params.process_fds.ident); + params = untrusted_params; + /* sanitize end */ - switch (fork()) { - case -1: - perror("fork"); - exit(1); - case 0: - break; - default: - children_count++; - return; - } - for (i = 3; i < MAX_FDS; i++) - close(i); - signal(SIGCHLD, SIG_DFL); - signal(SIGPIPE, SIG_DFL); - execl("/usr/lib/qubes/qrexec-policy", "qrexec-policy", - remote_domain_name, params.target_vmname, - params.exec_index, params.process_fds.ident, NULL); - perror("execl"); - _exit(1); + switch (fork()) { + case -1: + perror("fork"); + exit(1); + case 0: + break; + default: + children_count++; + return; + } + for (i = 3; i < MAX_FDS; i++) + close(i); + signal(SIGCHLD, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + execl("/usr/lib/qubes/qrexec-policy", "qrexec-policy", + remote_domain_name, params.target_vmname, + params.exec_index, params.process_fds.ident, NULL); + perror("execl"); + _exit(1); } void check_client_id_in_range(unsigned int untrusted_client_id) { - if (untrusted_client_id >= MAX_CLIENTS) { - fprintf(stderr, "from agent: client_id=%d\n", - untrusted_client_id); - exit(1); - } + if (untrusted_client_id >= MAX_CLIENTS) { + fprintf(stderr, "from agent: client_id=%d\n", + untrusted_client_id); + exit(1); + } } void sanitize_message_from_agent(struct server_header *untrusted_header) { - switch (untrusted_header->type) { - case MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING: - break; - case MSG_AGENT_TO_SERVER_STDOUT: - case MSG_AGENT_TO_SERVER_STDERR: - case MSG_AGENT_TO_SERVER_EXIT_CODE: - check_client_id_in_range(untrusted_header->client_id); - if (untrusted_header->len > MAX_DATA_CHUNK) { - fprintf(stderr, "agent feeded %d of data bytes?\n", - untrusted_header->len); - exit(1); - } - break; + switch (untrusted_header->type) { + case MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING: + break; + case MSG_AGENT_TO_SERVER_STDOUT: + case MSG_AGENT_TO_SERVER_STDERR: + case MSG_AGENT_TO_SERVER_EXIT_CODE: + check_client_id_in_range(untrusted_header->client_id); + if (untrusted_header->len > MAX_DATA_CHUNK) { + fprintf(stderr, "agent feeded %d of data bytes?\n", + untrusted_header->len); + exit(1); + } + break; - case MSG_XOFF: - case MSG_XON: - check_client_id_in_range(untrusted_header->client_id); - break; - default: - fprintf(stderr, "unknown mesage type %d from agent\n", - untrusted_header->type); - exit(1); - } + case MSG_XOFF: + case MSG_XON: + check_client_id_in_range(untrusted_header->client_id); + break; + default: + fprintf(stderr, "unknown mesage type %d from agent\n", + untrusted_header->type); + exit(1); + } } void handle_message_from_agent(void) { - struct client_header hdr; - struct server_header s_hdr, untrusted_s_hdr; + struct client_header hdr; + struct server_header s_hdr, untrusted_s_hdr; - if (libvchan_recv(vchan, &untrusted_s_hdr, sizeof(untrusted_s_hdr)) < 0) - handle_vchan_error("recv hdr"); - /* sanitize start */ - sanitize_message_from_agent(&untrusted_s_hdr); - s_hdr = untrusted_s_hdr; - /* sanitize end */ + if (libvchan_recv(vchan, &untrusted_s_hdr, sizeof(untrusted_s_hdr)) < 0) + handle_vchan_error("recv hdr"); + /* sanitize start */ + sanitize_message_from_agent(&untrusted_s_hdr); + s_hdr = untrusted_s_hdr; + /* sanitize end */ -// fprintf(stderr, "got %x %x %x\n", s_hdr.type, s_hdr.client_id, -// s_hdr.len); + if (s_hdr.type == MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING) { + handle_execute_predefined_command(); + return; + } - if (s_hdr.type == MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING) { - handle_execute_predefined_command(); - return; - } + if (s_hdr.type == MSG_XOFF) { + clients[s_hdr.client_id].state |= CLIENT_DONT_READ; + return; + } - if (s_hdr.type == MSG_XOFF) { - clients[s_hdr.client_id].state |= CLIENT_DONT_READ; - return; - } + if (s_hdr.type == MSG_XON) { + clients[s_hdr.client_id].state &= ~CLIENT_DONT_READ; + return; + } - if (s_hdr.type == MSG_XON) { - clients[s_hdr.client_id].state &= ~CLIENT_DONT_READ; - return; - } - - switch (s_hdr.type) { - case MSG_AGENT_TO_SERVER_STDOUT: - hdr.type = MSG_SERVER_TO_CLIENT_STDOUT; - break; - case MSG_AGENT_TO_SERVER_STDERR: - hdr.type = MSG_SERVER_TO_CLIENT_STDERR; - break; - case MSG_AGENT_TO_SERVER_EXIT_CODE: - hdr.type = MSG_SERVER_TO_CLIENT_EXIT_CODE; - break; - default: /* cannot happen, already sanitized */ - fprintf(stderr, "from agent: type=%d\n", s_hdr.type); - exit(1); - } - hdr.len = s_hdr.len; - if (clients[s_hdr.client_id].state == CLIENT_INVALID) { - // benefit of doubt - maybe client exited earlier - // just eat the packet data and continue - char buf[MAX_DATA_CHUNK]; - if (libvchan_recv(vchan, buf, s_hdr.len) < 0) - handle_vchan_error("recv buf"); - return; - } - get_packet_data_from_agent_and_pass_to_client(s_hdr.client_id, - &hdr); - if (s_hdr.type == MSG_AGENT_TO_SERVER_EXIT_CODE) - terminate_client_and_flush_data(s_hdr.client_id); + switch (s_hdr.type) { + case MSG_AGENT_TO_SERVER_STDOUT: + hdr.type = MSG_SERVER_TO_CLIENT_STDOUT; + break; + case MSG_AGENT_TO_SERVER_STDERR: + hdr.type = MSG_SERVER_TO_CLIENT_STDERR; + break; + case MSG_AGENT_TO_SERVER_EXIT_CODE: + hdr.type = MSG_SERVER_TO_CLIENT_EXIT_CODE; + break; + default: /* cannot happen, already sanitized */ + fprintf(stderr, "from agent: type=%d\n", s_hdr.type); + exit(1); + } + hdr.len = s_hdr.len; + if (clients[s_hdr.client_id].state == CLIENT_INVALID) { + // benefit of doubt - maybe client exited earlier + // just eat the packet data and continue + char buf[MAX_DATA_CHUNK]; + if (libvchan_recv(vchan, buf, s_hdr.len) < 0) + handle_vchan_error("recv buf"); + return; + } + get_packet_data_from_agent_and_pass_to_client(s_hdr.client_id, + &hdr); + if (s_hdr.type == MSG_AGENT_TO_SERVER_EXIT_CODE) + terminate_client_and_flush_data(s_hdr.client_id); } -/* -Scan the "clients" table, add ones we want to read from (because the other -end has not send MSG_XOFF on them) to read_fdset, add ones we want to write -to (because its pipe is full) to write_fdset. Return the highest used file -descriptor number, needed for the first select() parameter. -*/ +/* + * Scan the "clients" table, add ones we want to read from (because the other + * end has not send MSG_XOFF on them) to read_fdset, add ones we want to write + * to (because its pipe is full) to write_fdset. Return the highest used file + * descriptor number, needed for the first select() parameter. + */ int fill_fdsets_for_select(fd_set * read_fdset, fd_set * write_fdset) { - int i; - int max = -1; - FD_ZERO(read_fdset); - FD_ZERO(write_fdset); - for (i = 0; i <= max_client_fd; i++) { - if (clients[i].state != CLIENT_INVALID - && !(clients[i].state & CLIENT_DONT_READ)) { - FD_SET(i, read_fdset); - max = i; - } - if (clients[i].state != CLIENT_INVALID - && clients[i].state & CLIENT_OUTQ_FULL) { - FD_SET(i, write_fdset); - max = i; - } - } - FD_SET(qrexec_daemon_unix_socket_fd, read_fdset); - if (qrexec_daemon_unix_socket_fd > max) - max = qrexec_daemon_unix_socket_fd; - return max; + int i; + int max = -1; + FD_ZERO(read_fdset); + FD_ZERO(write_fdset); + for (i = 0; i <= max_client_fd; i++) { + if (clients[i].state != CLIENT_INVALID + && !(clients[i].state & CLIENT_DONT_READ)) { + FD_SET(i, read_fdset); + max = i; + } + if (clients[i].state != CLIENT_INVALID + && clients[i].state & CLIENT_OUTQ_FULL) { + FD_SET(i, write_fdset); + max = i; + } + } + FD_SET(qrexec_daemon_unix_socket_fd, read_fdset); + if (qrexec_daemon_unix_socket_fd > max) + max = qrexec_daemon_unix_socket_fd; + return max; } int main(int argc, char **argv) { - fd_set read_fdset, write_fdset; - int i, opt; - int max; - sigset_t chld_set; + fd_set read_fdset, write_fdset; + int i, opt; + int max; + sigset_t chld_set; - while ((opt=getopt(argc, argv, "q")) != -1) { - switch (opt) { - case 'q': - opt_quiet = 1; - break; - default: /* '?' */ - fprintf(stderr, "usage: %s [-q] domainid domain-name [default user]\n", argv[0]); - exit(1); - } - } - if (argc - optind < 2 || argc - optind > 3) { - fprintf(stderr, "usage: %s [-q] domainid domain-name [default user]\n", argv[0]); - exit(1); - } - remote_domain_name = argv[optind+1]; - if (argc - optind >= 3) - default_user = argv[optind+2]; - remote_domain_xid = atoi(argv[optind]); - init(remote_domain_xid); - sigemptyset(&chld_set); - sigaddset(&chld_set, SIGCHLD); - /* - The main event loop. Waits for one of the following events: - - message from client - - message from agent - - new client - - child exited - */ - for (;;) { - max = fill_fdsets_for_select(&read_fdset, &write_fdset); - if (libvchan_buffer_space(vchan) <= - sizeof(struct server_header)) - FD_ZERO(&read_fdset); // vchan full - don't read from clients + while ((opt=getopt(argc, argv, "q")) != -1) { + switch (opt) { + case 'q': + opt_quiet = 1; + break; + default: /* '?' */ + fprintf(stderr, "usage: %s [-q] domainid domain-name [default user]\n", argv[0]); + exit(1); + } + } + if (argc - optind < 2 || argc - optind > 3) { + fprintf(stderr, "usage: %s [-q] domainid domain-name [default user]\n", argv[0]); + exit(1); + } + remote_domain_name = argv[optind+1]; + if (argc - optind >= 3) + default_user = argv[optind+2]; + remote_domain_xid = atoi(argv[optind]); + init(remote_domain_xid); + sigemptyset(&chld_set); + sigaddset(&chld_set, SIGCHLD); + /* + The main event loop. Waits for one of the following events: + - message from client + - message from agent + - new client + - child exited + */ + for (;;) { + max = fill_fdsets_for_select(&read_fdset, &write_fdset); + if (libvchan_buffer_space(vchan) <= + sizeof(struct server_header)) + FD_ZERO(&read_fdset); // vchan full - don't read from clients - sigprocmask(SIG_BLOCK, &chld_set, NULL); - if (child_exited) - reap_children(); - wait_for_vchan_or_argfd(vchan, max, &read_fdset, &write_fdset); - sigprocmask(SIG_UNBLOCK, &chld_set, NULL); + sigprocmask(SIG_BLOCK, &chld_set, NULL); + if (child_exited) + reap_children(); + wait_for_vchan_or_argfd(vchan, max, &read_fdset, &write_fdset); + sigprocmask(SIG_UNBLOCK, &chld_set, NULL); - if (FD_ISSET(qrexec_daemon_unix_socket_fd, &read_fdset)) - handle_new_client(); + if (FD_ISSET(qrexec_daemon_unix_socket_fd, &read_fdset)) + handle_new_client(); - while (libvchan_data_ready(vchan)) - handle_message_from_agent(); + while (libvchan_data_ready(vchan)) + handle_message_from_agent(); - for (i = 0; i <= max_client_fd; i++) - if (clients[i].state != CLIENT_INVALID - && FD_ISSET(i, &read_fdset)) - handle_message_from_client(i); + for (i = 0; i <= max_client_fd; i++) + if (clients[i].state != CLIENT_INVALID + && FD_ISSET(i, &read_fdset)) + handle_message_from_client(i); - for (i = 0; i <= max_client_fd; i++) - if (clients[i].state != CLIENT_INVALID - && FD_ISSET(i, &write_fdset)) - write_buffered_data_to_client(i); + for (i = 0; i <= max_client_fd; i++) + if (clients[i].state != CLIENT_INVALID + && FD_ISSET(i, &write_fdset)) + write_buffered_data_to_client(i); - } + } }