/* 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; if (xid <= 0) { fprintf(stderr, "domain id=0?\n"); exit(1); } signal(SIGUSR1, sigusr1_handler); switch (fork()) { case -1: perror("fork"); exit(1); case 0: break; default: fprintf(stderr, "Waiting for VM's qrexec agent."); for (i=0;i<MAX_STARTUP_TIME;i++) { sleep(1); fprintf(stderr, "."); } fprintf(stderr, "Cannot connect to qrexec agent for %d seconds, giving up\n", MAX_STARTUP_TIME); exit(1); } close(0); snprintf(qrexec_error_log_name, sizeof(qrexec_error_log_name), "/var/log/qubes/qrexec.%d.log", xid); umask(0007); // make the log readable by the "qubes" group logfd = open(qrexec_error_log_name, O_WRONLY | O_CREAT | O_TRUNC, 0640); if (logfd < 0) { perror("open"); exit(1); } dup2(logfd, 1); dup2(logfd, 2); chdir("/var/run/qubes"); if (setsid() < 0) { perror("setsid()"); exit(1); } remote_domain_name = peer_client_init(xid, REXEC_PORT); setuid(getuid()); /* When running as root, make the socket accessible; perms on /var/run/qubes still apply */ umask(0); qrexec_daemon_unix_socket_fd = create_qrexec_socket(xid, remote_domain_name); umask(0077); signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, sigchld_handler); signal(SIGUSR1, SIG_DFL); kill(getppid(), SIGUSR1); // let the parent know we are ready }
/* 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; 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<startup_timeout;i++) { sleep(1); if (!opt_quiet) fprintf(stderr, "."); if (i==startup_timeout-1) { break; } } fprintf(stderr, "Cannot connect to '%s' qrexec agent for %d seconds, giving up\n", remote_domain_name, startup_timeout); exit(3); } close(0); snprintf(qrexec_error_log_name, sizeof(qrexec_error_log_name), "/var/log/qubes/qrexec.%s.log", remote_domain_name); umask(0007); // make the log readable by the "qubes" group logfd = open(qrexec_error_log_name, O_WRONLY | O_CREAT | O_TRUNC, 0660); if (logfd < 0) { perror("open"); exit(1); } dup2(logfd, 1); dup2(logfd, 2); chdir("/var/run/qubes"); if (setsid() < 0) { perror("setsid()"); exit(1); } vchan = libvchan_client_init(xid, VCHAN_BASE_PORT); if (!vchan) { perror("cannot connect to qrexec agent"); exit(1); } if (handle_agent_hello(vchan, remote_domain_name) < 0) { exit(1); } if (setgid(getgid()) < 0) { perror("setgid()"); exit(1); } if (setuid(getuid()) < 0) { perror("setuid()"); exit(1); } /* initialize clients state arrays */ for (i = 0; i < MAX_CLIENTS; i++) { clients[i].state = CLIENT_INVALID; policy_pending[i].pid = 0; used_vchan_ports[i] = VCHAN_PORT_UNUSED; vchan_port_notify_client[i] = VCHAN_PORT_UNUSED; } /* When running as root, make the socket accessible; perms on /var/run/qubes still apply */ umask(0); qrexec_daemon_unix_socket_fd = create_qrexec_socket(xid, remote_domain_name); umask(0077); signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, sigchld_handler); signal(SIGUSR1, SIG_DFL); kill(getppid(), SIGUSR1); // let the parent know we are ready }