/* Start listening for connections from clients and processing their
 * requests.  'path' may be:
 *
 *      - NULL, in which case the default socket path is used.  (Only one
 *        Vlog_server_socket per process can use the default path.)
 *
 *      - A name that does not start with '/', in which case it is appended to
 *        the default socket path.
 *
 *      - An absolute path (starting with '/') that gives the exact name of
 *        the Unix domain socket to listen on.
 *
 * A program that (optionally) daemonizes itself should call this function
 * *after* daemonization, so that the socket name contains the pid of the
 * daemon instead of the pid of the program that exited.  (Otherwise, "vlogconf
 * --target <program>.pid" will fail.)
 *
 * Returns 0 if successful, otherwise a positive errno value.  If successful,
 * sets '*serverp' to the new vlog_server, otherwise to NULL. */
int
vlog_server_listen(const char *path, struct vlog_server **serverp)
{
    struct vlog_server *server = xmalloc(sizeof *server);

    if (path && path[0] == '/') {
        server->path = xstrdup(path);
    } else {
        server->path = xasprintf("/tmp/vlogs.%ld%s",
                                 (long int) getpid(), path ? path : "");
    }

    server->fd = make_unix_socket(SOCK_DGRAM, true, true, server->path, NULL);
    if (server->fd < 0) {
        int fd = server->fd;
        fprintf(stderr, "Could not initialize vlog configuration socket: %s\n",
                strerror(-server->fd));
        free(server->path);
        free(server);
        if (serverp) {
            *serverp = NULL; 
        }
        return fd;
    }

    server->waiter = poll_fd_callback(server->fd, POLLIN, poll_server, server);

    if (serverp) {
        *serverp = server; 
    }
    return 0;
}
/* Connects to a Vlog server socket.  'path' may be:
 *
 *      - A string that starts with a PID.  If a non-null, non-absolute name
 *        was passed to Vlog_server_socket::listen(), then it must follow the
 *        PID in 'path'.
 *
 *      - An absolute path (starting with '/') to a Vlog server socket or a
 *        pidfile.  If it is a pidfile, the pidfile will be read and translated
 *        into a Vlog server socket file name.
 *
 *      - A relative path, which is translated into a pidfile name and then
 *        treated as above.
 *
 * Returns 0 if successful, otherwise a positive errno value.  If successful,
 * sets '*clientp' to the new vlog_client, otherwise to NULL. */
int
vlog_client_connect(const char *path, struct vlog_client **clientp)
{
    static int counter;
    struct vlog_client *client;
    struct stat s;
    int error;

    client = xmalloc(sizeof *client);
    if (path[0] == '/') {
        client->connect_path = xstrdup(path);
    } else if (isdigit((unsigned char) path[0])) {
        client->connect_path = xasprintf("/tmp/vlogs.%s", path);
    } else {
        client->connect_path = make_pidfile_name(path);
    }
    client->bind_path = NULL;

    if (stat(client->connect_path, &s)) {
        error = errno;
        VLOG_WARN("could not stat \"%s\": %s",
                  client->connect_path, strerror(error));
        goto error;
    } else if (S_ISREG(s.st_mode)) {
        pid_t pid = read_pidfile(client->connect_path);
        if (pid < 0) {
            error = -pid;
            VLOG_WARN("could not read pidfile \"%s\": %s",
                      client->connect_path, strerror(error));
            goto error;
        }
        free(client->connect_path);
        client->connect_path = xasprintf("/tmp/vlogs.%ld", (long int) pid);
    }
    client->bind_path = xasprintf("/tmp/vlog.%ld.%d",
                                  (long int) getpid(), counter++);
    client->fd = make_unix_socket(SOCK_DGRAM, false, false,
                                  client->bind_path, client->connect_path);
    if (client->fd < 0) {
        error = -client->fd;
        goto error;
    }
    *clientp = client;
    return 0;

error:
    free(client->connect_path);
    free(client->bind_path);
    free(client);
    *clientp = NULL;
    return error;
}
Example #3
0
static int
punix_open(const char *name, char *suffix, struct pvconn **pvconnp)
{
    int fd;

    fd = make_unix_socket(SOCK_STREAM, true, true, suffix, NULL);
    if (fd < 0) {
        VLOG_ERR("%s: binding failed: %s", suffix, strerror(errno));
        return errno;
    }

    return new_pstream_pvconn("punix", fd, punix_accept, pvconnp);
}
Example #4
0
static int
unix_open(const char *name, char *suffix, struct vconn **vconnp)
{
    const char *connect_path = suffix;
    char bind_path[128];
    int fd;

    sprintf(bind_path, "/tmp/vconn-unix.%ld.%d",
            (long int) getpid(), n_unix_sockets++);
    fd = make_unix_socket(SOCK_STREAM, true, false, bind_path, connect_path);
    if (fd < 0) {
        VLOG_ERR("%s: connection to %s failed: %s",
                 bind_path, connect_path, strerror(-fd));
        return -fd;
    }

    return new_stream_vconn(name, fd, check_connection_completion(fd),
                            0, vconnp);
}
Example #5
0
static int
unix_open(const char *name, char *suffix, struct stream **streamp,
          uint8_t dscp OVS_UNUSED)
{
    char *connect_path;
    int fd;

    connect_path = abs_file_name(ovs_rundir(), suffix);
    fd = make_unix_socket(SOCK_STREAM, true, NULL, connect_path);

    if (fd < 0) {
        VLOG_DBG("%s: connection failed (%s)",
                 connect_path, ovs_strerror(-fd));
        free(connect_path);
        return -fd;
    }

    free(connect_path);
    return new_fd_stream(name, fd, check_connection_completion(fd), streamp);
}
Example #6
0
static int
unix_open(const char *name, char *suffix, struct stream **streamp)
{
    const char *connect_path = suffix;
    char *bind_path;
    int fd;

    bind_path = xasprintf("/tmp/stream-unix.%ld.%d",
                          (long int) getpid(), n_unix_sockets++);
    fd = make_unix_socket(SOCK_STREAM, true, false, bind_path, connect_path);
    if (fd < 0) {
        VLOG_ERR("%s: connection to %s failed: %s",
                 bind_path, connect_path, strerror(-fd));
        free(bind_path);
        return -fd;
    }

    return new_fd_stream(name, fd, check_connection_completion(fd),
                         bind_path, streamp);
}
Example #7
0
};

/* Passive UNIX socket. */

static int punix_accept(int fd, const struct sockaddr_storage *ss,
                        size_t ss_len, struct stream **streamp);

static int
punix_open(const char *name OVS_UNUSED, char *suffix,
           struct pstream **pstreamp, uint8_t dscp OVS_UNUSED)
{
    char *bind_path;
    int fd, error;

    bind_path = abs_file_name(ovs_rundir(), suffix);
    fd = make_unix_socket(SOCK_STREAM, true, bind_path, NULL);
    if (fd < 0) {
        VLOG_ERR("%s: binding failed: %s", bind_path, ovs_strerror(errno));
        free(bind_path);
        return errno;
    }

    if (listen(fd, 10) < 0) {
        error = errno;
        VLOG_ERR("%s: listen: %s", name, ovs_strerror(error));
        close(fd);
        free(bind_path);
        return error;
    }

    return new_fd_pstream(name, fd, punix_accept, NULL, bind_path, pstreamp);
Example #8
0
File: titus.cpp Project: 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;
}
Example #9
0
    NULL,                       /* run_wait */
    NULL,                       /* wait */
};

/* Passive UNIX socket. */

static int punix_accept(int fd, const struct sockaddr *sa, size_t sa_len,
                        struct stream **streamp);

static int
punix_open(const char *name OVS_UNUSED, char *suffix,
           struct pstream **pstreamp)
{
    int fd, error;

    fd = make_unix_socket(SOCK_STREAM, true, true, suffix, NULL);
    if (fd < 0) {
        VLOG_ERR("%s: binding failed: %s", suffix, strerror(errno));
        return errno;
    }

    if (listen(fd, 10) < 0) {
        error = errno;
        VLOG_ERR("%s: listen: %s", name, strerror(error));
        close(fd);
        return error;
    }

    return new_fd_pstream("punix", fd, punix_accept,
                          xstrdup(suffix), pstreamp);
}