Esempio n. 1
0
static void
tls_call_exec_client(struct proto_conn *sock, const char *srcaddr,
    const char *dstaddr, int timeout)
{
	char *timeoutstr, *startfdstr, *debugstr;
	int startfd;

	/* Declare that we are receiver. */
	proto_recv(sock, NULL, 0);

	if (pjdlog_mode_get() == PJDLOG_MODE_STD)
		startfd = 3;
	else /* if (pjdlog_mode_get() == PJDLOG_MODE_SYSLOG) */
		startfd = 0;

	if (proto_descriptor(sock) != startfd) {
		/* Move socketpair descriptor to descriptor number startfd. */
		if (dup2(proto_descriptor(sock), startfd) == -1)
			pjdlog_exit(EX_OSERR, "dup2() failed");
		proto_close(sock);
	} else {
		/*
		 * The FD_CLOEXEC is cleared by dup2(2), so when we not
		 * call it, we have to clear it by hand in case it is set.
		 */
		if (fcntl(startfd, F_SETFD, 0) == -1)
			pjdlog_exit(EX_OSERR, "fcntl() failed");
	}

	closefrom(startfd + 1);

	if (asprintf(&startfdstr, "%d", startfd) == -1)
		pjdlog_exit(EX_TEMPFAIL, "asprintf() failed");
	if (timeout == -1)
		timeout = TLS_DEFAULT_TIMEOUT;
	if (asprintf(&timeoutstr, "%d", timeout) == -1)
		pjdlog_exit(EX_TEMPFAIL, "asprintf() failed");
	if (asprintf(&debugstr, "%d", pjdlog_debug_get()) == -1)
		pjdlog_exit(EX_TEMPFAIL, "asprintf() failed");

	execl(proto_get("execpath"), proto_get("execpath"), "proto", "tls",
	    proto_get("user"), "client", startfdstr,
	    srcaddr == NULL ? "" : srcaddr, dstaddr,
	    proto_get("tls:fingerprint"), proto_get("tcp:port"), timeoutstr,
	    debugstr, NULL);
	pjdlog_exit(EX_SOFTWARE, "execl() failed");
}
Esempio n. 2
0
void
hastd_secondary(struct hast_resource *res, struct nv *nvin)
{
	sigset_t mask;
	pthread_t td;
	pid_t pid;
	int error, mode, debuglevel;

	/*
	 * Create communication channel between parent and child.
	 */
	if (proto_client(NULL, "socketpair://", &res->hr_ctrl) < 0) {
		KEEP_ERRNO((void)pidfile_remove(pfh));
		pjdlog_exit(EX_OSERR,
		    "Unable to create control sockets between parent and child");
	}
	/*
	 * Create communication channel between child and parent.
	 */
	if (proto_client(NULL, "socketpair://", &res->hr_event) < 0) {
		KEEP_ERRNO((void)pidfile_remove(pfh));
		pjdlog_exit(EX_OSERR,
		    "Unable to create event sockets between child and parent");
	}

	pid = fork();
	if (pid < 0) {
		KEEP_ERRNO((void)pidfile_remove(pfh));
		pjdlog_exit(EX_OSERR, "Unable to fork");
	}

	if (pid > 0) {
		/* This is parent. */
		proto_close(res->hr_remotein);
		res->hr_remotein = NULL;
		proto_close(res->hr_remoteout);
		res->hr_remoteout = NULL;
		/* Declare that we are receiver. */
		proto_recv(res->hr_event, NULL, 0);
		/* Declare that we are sender. */
		proto_send(res->hr_ctrl, NULL, 0);
		res->hr_workerpid = pid;
		return;
	}

	gres = res;
	mode = pjdlog_mode_get();
	debuglevel = pjdlog_debug_get();

	/* Declare that we are sender. */
	proto_send(res->hr_event, NULL, 0);
	/* Declare that we are receiver. */
	proto_recv(res->hr_ctrl, NULL, 0);
	descriptors_cleanup(res);

	descriptors_assert(res, mode);

	pjdlog_init(mode);
	pjdlog_debug_set(debuglevel);
	pjdlog_prefix_set("[%s] (%s) ", res->hr_name, role2str(res->hr_role));
	setproctitle("%s (%s)", res->hr_name, role2str(res->hr_role));

	PJDLOG_VERIFY(sigemptyset(&mask) == 0);
	PJDLOG_VERIFY(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);

	/* Error in setting timeout is not critical, but why should it fail? */
	if (proto_timeout(res->hr_remotein, 2 * HAST_KEEPALIVE) < 0)
		pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");
	if (proto_timeout(res->hr_remoteout, res->hr_timeout) < 0)
		pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");

	init_local(res);
	init_environment();

	if (drop_privs(res) != 0)
		exit(EX_CONFIG);
	pjdlog_info("Privileges successfully dropped.");

	/*
	 * Create the control thread before sending any event to the parent,
	 * as we can deadlock when parent sends control request to worker,
	 * but worker has no control thread started yet, so parent waits.
	 * In the meantime worker sends an event to the parent, but parent
	 * is unable to handle the event, because it waits for control
	 * request response.
	 */
	error = pthread_create(&td, NULL, ctrl_thread, res);
	PJDLOG_ASSERT(error == 0);

	init_remote(res, nvin);
	event_send(res, EVENT_CONNECT);

	error = pthread_create(&td, NULL, recv_thread, res);
	PJDLOG_ASSERT(error == 0);
	error = pthread_create(&td, NULL, disk_thread, res);
	PJDLOG_ASSERT(error == 0);
	(void)send_thread(res);
}
Esempio n. 3
0
static void
tls_call_exec_server(struct proto_conn *sock, struct proto_conn *tcp)
{
	int startfd, sockfd, tcpfd, safefd;
	char *startfdstr, *debugstr;

	if (pjdlog_mode_get() == PJDLOG_MODE_STD)
		startfd = 3;
	else /* if (pjdlog_mode_get() == PJDLOG_MODE_SYSLOG) */
		startfd = 0;

	/* Declare that we are receiver. */
	proto_send(sock, NULL, 0);

	sockfd = proto_descriptor(sock);
	tcpfd = proto_descriptor(tcp);

	safefd = MAX(sockfd, tcpfd);
	safefd = MAX(safefd, startfd);
	safefd++;

	/* Move sockfd and tcpfd to safe numbers first. */
	if (dup2(sockfd, safefd) == -1)
		pjdlog_exit(EX_OSERR, "dup2() failed");
	proto_close(sock);
	sockfd = safefd;
	if (dup2(tcpfd, safefd + 1) == -1)
		pjdlog_exit(EX_OSERR, "dup2() failed");
	proto_close(tcp);
	tcpfd = safefd + 1;

	/* Move socketpair descriptor to descriptor number startfd. */
	if (dup2(sockfd, startfd) == -1)
		pjdlog_exit(EX_OSERR, "dup2() failed");
	(void)close(sockfd);
	/* Move tcp descriptor to descriptor number startfd + 1. */
	if (dup2(tcpfd, startfd + 1) == -1)
		pjdlog_exit(EX_OSERR, "dup2() failed");
	(void)close(tcpfd);

	closefrom(startfd + 2);

	/*
	 * Even if FD_CLOEXEC was set on descriptors before dup2(), it should
	 * have been cleared on dup2(), but better be safe than sorry.
	 */
	if (fcntl(startfd, F_SETFD, 0) == -1)
		pjdlog_exit(EX_OSERR, "fcntl() failed");
	if (fcntl(startfd + 1, F_SETFD, 0) == -1)
		pjdlog_exit(EX_OSERR, "fcntl() failed");

	if (asprintf(&startfdstr, "%d", startfd) == -1)
		pjdlog_exit(EX_TEMPFAIL, "asprintf() failed");
	if (asprintf(&debugstr, "%d", pjdlog_debug_get()) == -1)
		pjdlog_exit(EX_TEMPFAIL, "asprintf() failed");

	execl(proto_get("execpath"), proto_get("execpath"), "proto", "tls",
	    proto_get("user"), "server", startfdstr, proto_get("tls:keyfile"),
	    proto_get("tls:certfile"), debugstr, NULL);
	pjdlog_exit(EX_SOFTWARE, "execl() failed");
}
Esempio n. 4
0
/*
 * This function creates sandboxes on-demand whoever has access to it via
 * 'sock' socket. Function sends two descriptors to the caller: process
 * descriptor of the sandbox and socket pair descriptor for communication
 * between sandbox and its owner.
 */
static void
zygote_main(int sock)
{
	int error, fd, flags, procfd;
	int chanfd[2];
	nvlist_t *nvlin, *nvlout;
	zygote_func_t *func;
	pid_t pid;

	assert(sock > STDERR_FILENO);

	setproctitle("zygote");

	if (pjdlog_mode_get() != PJDLOG_MODE_STD)
		stdnull();
	for (fd = STDERR_FILENO + 1; fd < sock; fd++)
		close(fd);
	closefrom(sock + 1);

	for (;;) {
		nvlin = nvlist_recv(sock);
		if (nvlin == NULL) {
			if (errno == ENOTCONN) {
				/* Casperd exited. */
				exit(0);
			}
			continue;
		}
		func = (zygote_func_t *)(uintptr_t)nvlist_get_number(nvlin,
		    "func");
		flags = (int)nvlist_get_number(nvlin, "flags");
		nvlist_destroy(nvlin);

		/*
		 * Someone is requesting a new process, create one.
		 */
		procfd = -1;
		chanfd[0] = -1;
		chanfd[1] = -1;
		error = 0;
		if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
		    chanfd) == -1) {
			error = errno;
			goto send;
		}
		pid = pdfork(&procfd, 0);
		switch (pid) {
		case -1:
			/* Failure. */
			error = errno;
			break;
		case 0:
			/* Child. */
			close(sock);
			close(chanfd[0]);
			func(chanfd[1]);
			/* NOTREACHED */
			exit(1);
		default:
			/* Parent. */
			close(chanfd[1]);
			break;
		}
send:
		nvlout = nvlist_create(0);
		if (error != 0) {
			nvlist_add_number(nvlout, "error", (uint64_t)error);
			if (chanfd[0] >= 0)
				close(chanfd[0]);
			if (procfd >= 0)
				close(procfd);
		} else {
			nvlist_move_descriptor(nvlout, "chanfd", chanfd[0]);
			nvlist_move_descriptor(nvlout, "procfd", procfd);
		}
		(void)nvlist_send(sock, nvlout);
		nvlist_destroy(nvlout);
	}
	/* NOTREACHED */
}