Esempio n. 1
0
File: titus.cpp Progetto: 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;
}
Esempio n. 2
0
int intercode_to_bcode(void)
{

 int i;

 for (i = 0; i < BCODE_MAX; i ++)
	{
		cstate.target_bcode->op [i] = OP_nop;
		cstate.target_bcode->src_line [i] = 0;
	}

// the end of the bcode is filled with stop instructions
	for (i = BCODE_POS_MAX; i < BCODE_MAX; i ++)
	{
		cstate.target_bcode->op [i] = OP_stop;
	}

	int intercode_length = cstate.ic_pos;
	cstate.bc_pos = 0;
	cstate.ic_pos = 0;
	cstate.resolve_pos = 0; // position in cstate.ic_address_resolve struct

 for (cstate.ic_pos = 0; cstate.ic_pos < intercode_length; cstate.ic_pos ++)
	{
		if (cstate.bc_pos >= BCODE_POS_MAX - 8)
		{
			return intercode_error_text("bcode too large");
		}
		switch(cstate.intercode[cstate.ic_pos].type)
		{
		 case IC_OP:
#ifdef SANITY_CHECK
    if (cstate.intercode[cstate.ic_pos].value [0]	< 0
					|| cstate.intercode[cstate.ic_pos].value [0]	>= INSTRUCTIONS)
				{
					fpr("\nError: c_generate.c: intercode_to_bcode(): invalid IC_OP instruction %i at intercode %i (source line %i)", cstate.intercode[cstate.ic_pos].value [0], cstate.ic_pos, cstate.intercode[cstate.ic_pos].src_line);
					error_call();
				}
#endif
    write_bcode(cstate.intercode[cstate.ic_pos].value [0]);
    if (instruction_set[cstate.intercode[cstate.ic_pos].value [0]].operands > 0)
				{
     write_bcode(cstate.intercode[cstate.ic_pos].value [1]);
				}
    if (instruction_set[cstate.intercode[cstate.ic_pos].value [0]].operands > 1)
				{
     write_bcode(cstate.intercode[cstate.ic_pos].value [2]);
				}
    break;
   case IC_OP_WITH_VARIABLE_OPERAND:
// This is like IC_OP but value [1] is an identifier index instead of a value
#ifdef SANITY_CHECK
    if (cstate.intercode[cstate.ic_pos].value [0]	< 0
					|| cstate.intercode[cstate.ic_pos].value [0]	>= INSTRUCTIONS)
				{
					fpr("\nError: c_generate.c: intercode_to_bcode(): invalid IC_OP_WITH_VARIABLE_OPERAND instruction %i at intercode %i (source line %i)", cstate.intercode[cstate.ic_pos].value [0], cstate.ic_pos, cstate.intercode[cstate.ic_pos].src_line);
					error_call();
				}
    if (identifier[cstate.intercode[cstate.ic_pos].value [1]].address < 0
					|| identifier[cstate.intercode[cstate.ic_pos].value [1]].address >= MEMORY_SIZE)
				{
					fpr("\nError: c_generate.c: intercode_to_bcode(): invalid IC_OP_WITH_VARIABLE_OPERAND operand (address %i) at intercode %i (source line %i)", identifier[cstate.intercode[cstate.ic_pos].value [1]].address, cstate.ic_pos, cstate.intercode[cstate.ic_pos].src_line);
					error_call();
				}	// unlikely to be possible as references to undeclared variables should have been caught during compilation stage.
#endif
    write_bcode(cstate.intercode[cstate.ic_pos].value [0]);
    write_bcode(identifier[cstate.intercode[cstate.ic_pos].value [1]].address);
    break;
   case IC_EXIT_POINT_TRUE:
				cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_bcode = cstate.bc_pos;
				break;
   case IC_EXIT_POINT_FALSE:
				cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].false_point_bcode = cstate.bc_pos;
				break;
			case IC_LABEL_DEFINITION:
			 identifier[cstate.intercode[cstate.ic_pos].value [0]].address = cstate.bc_pos;
			 break;
			case IC_GOTO_LABEL:
				if (identifier[cstate.intercode[cstate.ic_pos].value [0]].type != CTOKEN_TYPE_IDENTIFIER_LABEL)
   		return intercode_error_text("goto label not defined");
    write_bcode(OP_jump_num);
				if (identifier[cstate.intercode[cstate.ic_pos].value [0]].address != -1)
				{
     write_bcode(identifier[cstate.intercode[cstate.ic_pos].value [0]].address);
				}
				 else
					{
						if (!add_expoint_address_resolve(ADDRESS_RESOLVE_LABEL, cstate.intercode[cstate.ic_pos].value [0]))
							return 0;
					}
				break;
			case IC_IFFALSE_JUMP_TO_EXIT_POINT:
    write_bcode(OP_iffalse_jump);
				if (cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].false_point_bcode == -1)
				{
// exit point address not yet known, so must resolve it at the end of code generation:
					if (!add_expoint_address_resolve(ADDRESS_RESOLVE_EX_POINT_FALSE, cstate.intercode[cstate.ic_pos].value [0]))
						return 0;
				}
				 else
						write_bcode(cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].false_point_bcode); // address known
				cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].false_point_used = 1;
				break;
			case IC_IFTRUE_JUMP_TO_EXIT_POINT:
    write_bcode(OP_iftrue_jump);
				if (cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_bcode == -1)
				{
// exit point address not yet known, so must resolve it at the end of code generation:
					if (!add_expoint_address_resolve(ADDRESS_RESOLVE_EX_POINT_TRUE, cstate.intercode[cstate.ic_pos].value [0]))
						return 0;
				}
				 else
						write_bcode(cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_bcode); // address known
				cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_used = 1;
				break;
			case IC_JUMP_EXIT_POINT_TRUE:
    write_bcode(OP_jump_num);
				if (cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_bcode == -1)
				{
// exit point address not yet known, so must resolve it at the end of code generation:
					if (!add_expoint_address_resolve(ADDRESS_RESOLVE_EX_POINT_TRUE, cstate.intercode[cstate.ic_pos].value [0]))
						return 0;
				}
				 else
						write_bcode(cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_bcode); // address known
				cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_used = 1;
				break;
			case IC_JUMP_EXIT_POINT_FALSE:
    write_bcode(OP_jump_num);
				if (cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].false_point_bcode == -1)
				{
// exit point address not yet known, so must resolve it at the end of code generation:
					if (!add_expoint_address_resolve(ADDRESS_RESOLVE_EX_POINT_FALSE, cstate.intercode[cstate.ic_pos].value [0]))
						return 0;
				}
				 else
						write_bcode(cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].false_point_bcode); // address known
				cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].false_point_used = 1;
				break;
			case IC_NUMBER:
    write_bcode(cstate.intercode[cstate.ic_pos].value [0]);
    break;
   case IC_SWITCH:
    write_bcode(OP_switchA);
				if (!add_expoint_address_resolve(ADDRESS_RESOLVE_EX_POINT_TRUE, cstate.intercode[cstate.ic_pos].value [0]))
					return 0;
    write_bcode(cstate.intercode[cstate.ic_pos].value [1]);
    write_bcode(cstate.intercode[cstate.ic_pos].value [2]);
				cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_used = 1;
    break;
   case IC_JUMP_TABLE:
// this just writes a number (to be used by switch code), no instruction.
//   	cstate.target_bcode->op[cstate.bc_pos] = cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_bcode;
//    cstate.bc_pos ++;
				if (cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_bcode == -1)
				{
// exit point address not yet known, so must resolve it at the end of code generation:
					if (!add_expoint_address_resolve(ADDRESS_RESOLVE_EX_POINT_TRUE, cstate.intercode[cstate.ic_pos].value [0]))
						return 0;
				}
				 else
						write_bcode(cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_bcode); // address known
				cstate.expoint[cstate.intercode[cstate.ic_pos].value [0]].true_point_used = 1;
    break;

			default:
				fpr("\nError: c_generate.c: intercode_to_bcode(): invalid instruction %i at intercode %i (source line %i)", cstate.intercode[cstate.ic_pos].type, cstate.ic_pos, cstate.intercode[cstate.ic_pos].src_line);
				error_call();
				break; // should never happen

		}
	}

 if (!resolve_addresses())
		return 0;

	start_log_line(MLOG_COL_COMPILER);
	write_to_log("Bcode length ");
	write_number_to_log(cstate.bc_pos);
	write_to_log(" (");
	write_number_to_log(BCODE_MAX);
	write_to_log("). Memory used ");
	write_number_to_log(cstate.mem_pos);
	write_to_log(" (");
	write_number_to_log(MEMORY_SIZE);
	write_to_log(").");
	finish_log_line();

//	fpr("\n generation success! bc_pos %i ic_pos %i", cstate.bc_pos, cstate.ic_pos);

 return 1; // success!

}