示例#1
0
文件: titus.cpp 项目: AGWA/titus
int main (int argc, char** argv)
try {
	init_signals();

	// Initialize OpenSSL
	ERR_load_crypto_strings();
	SSL_library_init();
	SSL_load_error_strings();

	// This cipher list is the "Intermediate compatibility" list from https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29 as of 2014-12-09
	vhost_defaults.ciphers = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
	vhost_defaults.dhgroup = make_dh(dh_group14_prime, dh_group14_generator); // 2048 bit group
	vhost_defaults.ecdhcurve = get_ecdhcurve("prime256v1"); // a.k.a. secp256r1

	// Set default SSL options, which can be overridden by config file
	vhost_defaults.ssl_options[SSL_OP_NO_COMPRESSION] = true;
	vhost_defaults.ssl_options[SSL_OP_NO_SSLv3] = true;
	vhost_defaults.ssl_options[SSL_OP_NO_TLSv1] = false;
	vhost_defaults.ssl_options[SSL_OP_NO_TLSv1_1] = false;
	vhost_defaults.ssl_options[SSL_OP_NO_TLSv1_2] = false;
	vhost_defaults.ssl_options[SSL_OP_CIPHER_SERVER_PREFERENCE] = true;

	// These can't be overriden by config file:
	vhost_defaults.ssl_options[SSL_OP_SINGLE_DH_USE] = true;
	vhost_defaults.ssl_options[SSL_OP_SINGLE_ECDH_USE] = true;
	vhost_defaults.ssl_options[SSL_OP_NO_SSLv2] = true;

	// Command line arguments come in pairs of the form "--name value" and correspond
	// directly to the name/value option pairs in the config file (a la OpenVPN).
	for (int i = 1; i < argc; ) {
		if (std::strncmp(argv[i], "--", 2) == 0 && i + 1 < argc) {
			process_config_param(argv[i] + 2, argv[i+1]);
			i += 2;
		} else {
			std::clog << argv[0] << ": Bad arguments" << std::endl;
			return 2;
		}
	}

	if (vhost_configs.empty()) {
		// No vhosts specified, so add one implicitly that matches all local addresses / SNI names.
		// It will use the options from vhost_defaults.
		vhost_configs.emplace_back();
	}

	for (size_t i = 0; i < vhost_configs.size(); ++i) {
		vhosts.emplace_back();
		Vhost&		vhost(vhosts.back());
		Vhost_config&	config(vhost_configs[i]);

		vhost.id = i;
		vhost.servername_set = config.servername_set;
		vhost.servername = config.servername;
		init_ssl_ctx(vhost, config);
		resolve_addresses(vhost, config);
	}
	// Free up some memory that's no longer needed:
	vhost_configs.clear();
	vhost_defaults = Basic_vhost_config();

	// Listen
	listening_sock = socket(AF_INET6, SOCK_STREAM, 0);
	if (listening_sock == -1) {
		throw System_error("socket", "", errno);
	}
	set_reuseaddr(listening_sock);
	set_not_v6only(listening_sock);
	if (transparent == TRANSPARENT_ON) {
		set_transparent(listening_sock);
	}

	// TODO: support binding to specific IP addresses
	struct sockaddr_in6	listening_address;
	std::memset(&listening_address, '\0', sizeof(listening_address));
	listening_address.sin6_family = AF_INET6;
	listening_address.sin6_addr = in6addr_any;
	listening_address.sin6_port = htons(listening_port);
	if (bind(listening_sock, reinterpret_cast<const struct sockaddr*>(&listening_address), sizeof(listening_address)) == -1) {
		throw System_error("bind", "", errno);
	}

	if (listen(listening_sock, SOMAXCONN) == -1) {
		throw System_error("listen", "", errno);
	}

	// Set up UNIX domain socket for communicating with the key server.
	// Put it in a temporary directory with restrictive permissions so
	// other users can't traverse its path.  We have to use a named
	// socket as opposed to a socketpair because we need every child process
	// to communicate with the key server using its own socket.  (Duping one
	// end of a socketpair wouldn't work because then every child would
	// be referring to the same underlying socket, which provides
	// insufficient isolation.)
	temp_directory = make_temp_directory();
	filedesc keyserver_sock(make_unix_socket(temp_directory + "/server.sock", &keyserver_sockaddr, &keyserver_sockaddr_len));
	if (listen(keyserver_sock, SOMAXCONN) == -1) {
		throw System_error("listen", "", errno);
	}

	// Write PID file, daemonize, etc.
	std::ofstream		pid_file_out;
	if (!pid_file.empty()) {
		// Open PID file before forking so we can report errors
		pid_file_out.open(pid_file.c_str(), std::ofstream::out | std::ofstream::trunc);
		if (!pid_file_out) {
			throw Configuration_error("Unable to open PID file " + pid_file + " for writing.");
		}
		pid_file_created = true;
	}
	if (run_as_daemon) {
		daemonize();
	}
	if (pid_file_out) {
		pid_file_out << getpid() << '\n';
		pid_file_out.close();
	}

	// Spawn the master key server process
	keyserver_pid = spawn(keyserver_main, std::move(keyserver_sock));

	// Spawn spare children to accept() and service connections
	if (pipe(children_pipe) == -1) {
		throw System_error("pipe", "", errno);
	}
	set_nonblocking(children_pipe[0], true);

	spawn_children();

	// Wait for signals and readability on children_pipe
	sigset_t		empty_sigset;
	sigemptyset(&empty_sigset);
	fd_set			readfds;
	FD_ZERO(&readfds);
	FD_SET(children_pipe[0], &readfds);

	is_running = 1;
	struct timespec		timeout = { 2, 0 };
	int			select_res = 0;
	while (is_running && ((select_res = pselect(children_pipe[0] + 1, &readfds, NULL, NULL, failed_children ? &timeout : NULL, &empty_sigset)) >= 0 || errno == EINTR)) {
		if (failed_children && std::time(NULL) >= last_failed_child_time + 2) {
			failed_children = 0;
		}
		if (pending_sigchld) {
			on_sigchld();
			pending_sigchld = 0;
		}
		if (select_res > 0) {
			read_children_pipe();
		}
		FD_SET(children_pipe[0], &readfds);
	}

	if (is_running && select_res == -1) {
		throw System_error("pselect", "", errno);
	}


	cleanup();
	return 0;
} catch (const System_error& error) {
	std::clog << "titus: System error: " << error.syscall;
	if (!error.target.empty()) {
		std::clog << ": " << error.target;
	}
	std::clog << ": " << std::strerror(error.number) << std::endl;
	cleanup();
	return 3;
} catch (const Openssl_error& error) {
	std::clog << "titus: OpenSSL error: " << error.message() << std::endl;
	cleanup();
	return 4;
} catch (const Configuration_error& error) {
	std::clog << "titus: Configuration error: " << error.message << std::endl;
	cleanup();
	return 5;
} catch (const Too_many_failed_children& error) {
	// TODO: better error reporting when this happens
	std::clog << "titus: Too many child processes failed." << std::endl;
	cleanup();
	return 7;
} catch (const Keyserver_died& error) {
	// TODO: better error reporting when this happens
	std::clog << "titus: Key server died." << std::endl;
	cleanup();
	return 8;
}
示例#2
0
文件: daemon.c 项目: pzbitskiy/fssh
static int forward(pid_t pid, int *sigchld_fd, int stdin_pipe[2], int stdout_pipe[2], int stderr_pipe[2], void *socket)
{
	int rc = -1;

	if (close(stdin_pipe[0]) == -1)
		TRACE_ERRNO("close(%i) failed", stdin_pipe[0]);
	stdin_pipe[0] = -1;

	if (close(stdout_pipe[1]) == -1)
		TRACE_ERRNO("close(%i) failed", stdout_pipe[1]);
	stdout_pipe[1] = -1;

	if (close(stderr_pipe[1]) == -1)
		TRACE_ERRNO("close(%i) failed", stderr_pipe[1]);
	stderr_pipe[1] = -1;

	zmq_msg_t stdin_msg;
	size_t stdin_msg_pos = 0;
	zmq_msg_t stdout_msg;
	int stdout_msg_valid = 0;
	zmq_msg_t stderr_msg;
	int stderr_msg_valid = 0;

	if (make_nonblocking(stdin_pipe[1]) == -1)
		goto _out;
	if (make_nonblocking(stdout_pipe[0]) == -1)
		goto _out;
	if (make_nonblocking(stderr_pipe[0]) == -1)
		goto _out;
	TRACE("made nonblocking: %i, %i, %i", stdin_pipe[1], stdout_pipe[0], stderr_pipe[0]);

	while (1) {
		zmq_pollitem_t items[5];
		zmq_pollitem_t *item = items;

		zmq_pollitem_t *stdin_item = NULL;
		if (stdin_pipe[1] != -1 && stdin_msg_pos) {
			stdin_item = item++;
			stdin_item->socket = NULL;
			stdin_item->fd = stdin_pipe[1];
			stdin_item->events = ZMQ_POLLOUT | ZMQ_POLLERR;
		}

		zmq_pollitem_t *stdout_item = NULL;
		if (stdout_pipe[0] != -1 && !stdout_msg_valid) {
			stdout_item = item++;
			stdout_item->socket = NULL;
			stdout_item->fd = stdout_pipe[0];
			stdout_item->events = ZMQ_POLLIN | ZMQ_POLLERR;
		}

		zmq_pollitem_t *stderr_item = NULL;
		if (stderr_pipe[0] != -1 && !stderr_msg_valid) {
			stderr_item = item++;
			stderr_item->socket = NULL;
			stderr_item->fd = stderr_pipe[0];
			stderr_item->events = ZMQ_POLLIN | ZMQ_POLLERR;
		}

		zmq_pollitem_t *socket_item = NULL;
		short socket_events = ((stdout_msg_valid || stderr_msg_valid) ? ZMQ_POLLOUT : 0) |
		                      ((stdin_pipe[1] == -1 || stdin_msg_pos) ? 0 : ZMQ_POLLIN);
		if (socket_events) {
			socket_item = item++;
			socket_item->socket = socket;
			socket_item->fd = -1;
			socket_item->events = socket_events;
		}

		zmq_pollitem_t *sigchld_item = NULL;
		if (*sigchld_fd != -1) {
			sigchld_item = item++;
			sigchld_item->socket = NULL;
			sigchld_item->fd = *sigchld_fd;
			sigchld_item->events = ZMQ_POLLIN | ZMQ_POLLERR;
		}

		if (item == items) {
			TRACE("nothing to poll, exiting");
			break;
		}

		TRACE("polling:%s%s%s%s%s", stdin_item ? " stdin" : "",
		                            stdout_item ? " stdout" : "",
		                            stderr_item ? " stderr" : "",
		                            socket_item ? " socket" : "",
		                            sigchld_item ? " sigchld" : "");

		while (1) {
			if (zmq_poll(items, item - items, -1) == -1) {
				if (errno == EINTR)
					continue;
				TRACE_ERRNO("zmq_poll() failed");
				goto _out;
			}
			break;
		}

		if (stdin_item && (stdin_item->revents & (ZMQ_POLLOUT | ZMQ_POLLERR)))
			if (fd_write(&stdin_pipe[1], &stdin_msg, &stdin_msg_pos) == -1)
				goto _out;
		if (socket_item && (socket_item->revents & ZMQ_POLLOUT)) {
			if (socket_write(socket, &stdout_msg, &stdout_msg_valid) == -1)
				goto _out;
			if (socket_write(socket, &stderr_msg, &stderr_msg_valid) == -1)
				goto _out;
		}
		if (stdout_item && (stdout_item->revents & (ZMQ_POLLIN | ZMQ_POLLERR)))
			if (on_fd_readable(&stdout_pipe[0], socket, &stdout_msg, &stdout_msg_valid, msg_type_stdout) == -1)
				goto _out;
		if (stderr_item && (stderr_item->revents & (ZMQ_POLLIN | ZMQ_POLLERR)))
			if (on_fd_readable(&stderr_pipe[0], socket, &stderr_msg, &stderr_msg_valid, msg_type_stderr) == -1)
				goto _out;
		if (socket_item && (socket_item->revents & ZMQ_POLLIN))
			if (on_socket_readable(socket, &stdin_pipe[1], &stdin_msg, &stdin_msg_pos) == -1)
				goto _out;
		if (sigchld_item && (sigchld_item->revents & (ZMQ_POLLIN | ZMQ_POLLERR)))
			if (on_sigchld(sigchld_fd, pid, &stdin_pipe[1]) == -1)
				goto _out;
	}

	rc = 0;

_out:
	if (stdin_msg_pos && zmq_msg_close(&stdin_msg) == -1)
		TRACE_ERRNO("zmq_msg_close() failed");
	if (stdout_msg_valid && zmq_msg_close(&stdout_msg) == -1)
		TRACE_ERRNO("zmq_msg_close() failed");
	if (stderr_msg_valid && zmq_msg_close(&stderr_msg) == -1)
		TRACE_ERRNO("zmq_msg_close() failed");
	return rc;
}