Пример #1
0
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
void
screenshot_save_start (GdkPixbuf    *pixbuf,
		       SaveFunction  callback,
		       gpointer      user_data)
{
  GPid pid;
  gboolean ret;
  int parent_exit_notification[2];
  int pipe_from_child[2];

  pipe (parent_exit_notification);
  pipe (pipe_from_child);

  parent_dir = make_temp_directory ();
  if (parent_dir == NULL)
    return;

  tmp_filename = g_build_filename (parent_dir,
		  		   _("Screenshot.png"),
				   NULL);
  save_callback = callback;
  save_user_data = user_data;

  pid = fork ();
  if (pid == 0)
    {
      GError *error = NULL;
      char c;

      signal (SIGINT, signal_handler);
      signal (SIGTERM, signal_handler);

      close (parent_exit_notification [1]);
      close (pipe_from_child [0]);

      if (icc_profile_base64 != NULL)
        {
          ret = gdk_pixbuf_save (pixbuf, tmp_filename,
                                 "png", &error,
                                 "icc-profile", icc_profile_base64,
                                 "tEXt::Software", "gnome-screenshot",
                                 NULL);
        }
      else
        {
          ret = gdk_pixbuf_save (pixbuf, tmp_filename,
                                 "png", &error,
                                 "tEXt::Software", "gnome-screenshot",
                                 NULL);
        }

      if (!ret)
	{
	  if (error && error->message)
	    write (pipe_from_child[1],
		   error->message,
		   strlen (error->message));
	  else
#define ERROR_MESSAGE _("Unknown error saving screenshot to disk")
	    write (pipe_from_child[1],
		   ERROR_MESSAGE,
		   strlen (ERROR_MESSAGE));
	}
      /* By closing the pipe, we let the main process know that we're
       * done saving it. */
      close (pipe_from_child[1]);
      read (parent_exit_notification[0], &c, 1);

      clean_up_temporary_dir (FALSE);
      _exit (0);
    }
  else if (pid > 0)
    {
      GIOChannel *channel;

      close (parent_exit_notification[0]);
      close (pipe_from_child[1]);

      channel = g_io_channel_unix_new (pipe_from_child[0]);
      g_io_add_watch (channel,
		      G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
		      read_pipe_from_child,
		      NULL);
      g_io_channel_unref (channel);
      g_child_watch_add (pid, child_done_notification, NULL);
    }
  else
    /* George awesomely wrote code originally to handle the
     * could-not-fork case synchronously.  I'm not copying it, as I'm
     * guessing that the system is pretty hosed if that's the case.
     * However, he gets major kudos for trying. (-:
     */
    g_assert_not_reached ();
}