Compare commits
	
		
			37 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f42ecedd42 | |||
| 63a7980329 | |||
| bc54bf520d | |||
| 11aaf1b325 | |||
| 5ca07656a1 | |||
| f20c6fb28e | |||
| 1613e75a48 | |||
| abd892cbd7 | |||
| 4ae95be9db | |||
| 328bf9af1e | |||
| ce83f8244c | |||
| 8a8ff11887 | |||
| 131aee6f08 | |||
| 07f6d0b350 | |||
| 1cc8656368 | |||
| 4c81112840 | |||
| 5dda5661ae | |||
| 628facf286 | |||
| 7225b68f74 | |||
| e188de5501 | |||
| cdf6544c94 | |||
| a28528d260 | |||
| 27f185e8aa | |||
| d207c90577 | |||
| 2afc9f99c3 | |||
| 4ab247ead0 | |||
| 1dd464f35c | |||
| 955b3728a3 | |||
| aa77bc41d0 | |||
| 5b208547c4 | |||
| c8890953b3 | |||
| cfc78ffdf0 | |||
| 637a3d2bf7 | |||
| a912b3f28c | |||
| 27cd8b3a63 | |||
| 2bde385dc7 | |||
| 74c9759932 | 
@@ -14,7 +14,7 @@ endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC)
 | 
			
		||||
# Version
 | 
			
		||||
set (project_VERSION_MAJOR "0")
 | 
			
		||||
set (project_VERSION_MINOR "9")
 | 
			
		||||
set (project_VERSION_PATCH "0")
 | 
			
		||||
set (project_VERSION_PATCH "1")
 | 
			
		||||
 | 
			
		||||
set (project_VERSION "${project_VERSION_MAJOR}")
 | 
			
		||||
set (project_VERSION "${project_VERSION}.${project_VERSION_MINOR}")
 | 
			
		||||
@@ -27,18 +27,26 @@ pkg_check_modules (libssl REQUIRED libssl libcrypto)
 | 
			
		||||
pkg_check_modules (ncursesw ncursesw)
 | 
			
		||||
 | 
			
		||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "BSD")
 | 
			
		||||
	# iconv() doesn't have to be present in libc
 | 
			
		||||
	# FIXME: detect if we need the library independently on the platform
 | 
			
		||||
	list (APPEND project_libraries iconv)
 | 
			
		||||
	# Need this for SIGWINCH; our POSIX version macros make it undefined
 | 
			
		||||
	add_definitions (-D__BSD_VISIBLE=1)
 | 
			
		||||
	include_directories(/usr/local/include)
 | 
			
		||||
	link_directories(/usr/local/lib)
 | 
			
		||||
	# Need this for SIGWINCH in FreeBSD and OpenBSD respectively;
 | 
			
		||||
	# our POSIX version macros make it undefined
 | 
			
		||||
	add_definitions (-D__BSD_VISIBLE=1 -D_BSD_SOURCE=1)
 | 
			
		||||
endif ("${CMAKE_SYSTEM_NAME}" MATCHES "BSD")
 | 
			
		||||
 | 
			
		||||
list (APPEND project_libraries ${libssl_LIBRARIES})
 | 
			
		||||
include_directories (${libssl_INCLUDE_DIRS})
 | 
			
		||||
link_directories (${libssl_LIBRARY_DIRS})
 | 
			
		||||
 | 
			
		||||
# -lpthread is only there for debugging (gdb & errno)
 | 
			
		||||
# -lrt is only for glibc < 2.17
 | 
			
		||||
list (APPEND project_libraries ${libssl_LIBRARIES} rt pthread)
 | 
			
		||||
include_directories (${libssl_INCLUDE_DIRS})
 | 
			
		||||
link_directories (${libssl_LIBRARY_DIRS})
 | 
			
		||||
# -liconv may or may not be a part of libc
 | 
			
		||||
foreach (extra iconv rt pthread)
 | 
			
		||||
	find_library (extra_lib_${extra} ${extra})
 | 
			
		||||
	if (extra_lib_${extra})
 | 
			
		||||
		list (APPEND project_libraries ${extra})
 | 
			
		||||
	endif (extra_lib_${extra})
 | 
			
		||||
endforeach (extra)
 | 
			
		||||
 | 
			
		||||
if (ncursesw_FOUND)
 | 
			
		||||
	list (APPEND project_libraries ${ncursesw_LIBRARIES})
 | 
			
		||||
@@ -53,7 +61,13 @@ endif (ncursesw_FOUND)
 | 
			
		||||
if ((WANT_READLINE AND WANT_LIBEDIT) OR (NOT WANT_READLINE AND NOT WANT_LIBEDIT))
 | 
			
		||||
	message (SEND_ERROR "You have to choose either GNU Readline or libedit")
 | 
			
		||||
elseif (WANT_READLINE)
 | 
			
		||||
	list (APPEND project_libraries readline)
 | 
			
		||||
	# OpenBSD's default readline is too old
 | 
			
		||||
	if ("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD")
 | 
			
		||||
		include_directories (/usr/local/include/ereadline)
 | 
			
		||||
		list (APPEND project_libraries ereadline)
 | 
			
		||||
	else ("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD")
 | 
			
		||||
		list (APPEND project_libraries readline)
 | 
			
		||||
	endif ("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD")
 | 
			
		||||
elseif (WANT_LIBEDIT)
 | 
			
		||||
	pkg_check_modules (libedit REQUIRED libedit)
 | 
			
		||||
	list (APPEND project_libraries ${libedit_LIBRARIES})
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								NEWS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								NEWS
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
0.9.1 (2015-09-25)
 | 
			
		||||
 | 
			
		||||
 * All "ssl" options have been renamed to "tls"
 | 
			
		||||
 | 
			
		||||
 * The project now builds on OpenBSD
 | 
			
		||||
 | 
			
		||||
 * Pulled in kqueue support
 | 
			
		||||
 | 
			
		||||
 * degesch: added backlog/scrollback functionality using less(1)
 | 
			
		||||
 | 
			
		||||
 * degesch: made showing the entire set of channel mode user prefixes optional
 | 
			
		||||
 | 
			
		||||
 * degesch: nicknames in /names are now ordered
 | 
			
		||||
 | 
			
		||||
 * degesch: nicknames now use the 256-color terminal palette if available
 | 
			
		||||
 | 
			
		||||
 * degesch: now we skip entries in the "addresses" list that can't be resolved
 | 
			
		||||
   to an address, along with displaying a more helpful message
 | 
			
		||||
 | 
			
		||||
 * degesch: joins, parts, nick changes and quits don't count as new buffer
 | 
			
		||||
   activity anymore
 | 
			
		||||
 | 
			
		||||
 * degesch: add Meta-H to open the full log file
 | 
			
		||||
 | 
			
		||||
 * degesch: various bugfixes and little improvements
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
0.9.0 (2015-07-23)
 | 
			
		||||
 | 
			
		||||
 * Initial release
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								README
									
									
									
									
									
								
							@@ -30,7 +30,7 @@ a small network of respectful users (or bots), or testing, this one will do it.
 | 
			
		||||
Notable features:
 | 
			
		||||
 - TLS autodetection (why doesn't everyone have this?)
 | 
			
		||||
 - IRCop authentication through TLS client certificates
 | 
			
		||||
 - epoll support on Linux; it should be able to handle quite a number of users
 | 
			
		||||
 - epoll/kqueue support; it should be able to handle quite a number of users
 | 
			
		||||
 - partial IRCv3 support
 | 
			
		||||
 | 
			
		||||
Not supported:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										382
									
								
								common.c
									
									
									
									
									
								
							
							
						
						
									
										382
									
								
								common.c
									
									
									
									
									
								
							@@ -41,12 +41,6 @@
 | 
			
		||||
		return false;                                                          \
 | 
			
		||||
	BLOCK_END
 | 
			
		||||
 | 
			
		||||
// A few other debugging shorthands
 | 
			
		||||
#define LOG_FUNC_FAILURE(name, desc)                                           \
 | 
			
		||||
	print_debug ("%s: %s: %s", __func__, (name), (desc))
 | 
			
		||||
#define LOG_LIBC_FAILURE(name)                                                 \
 | 
			
		||||
	print_debug ("%s: %s: %s", __func__, (name), strerror (errno))
 | 
			
		||||
 | 
			
		||||
// --- To be moved to liberty --------------------------------------------------
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -90,240 +84,6 @@ log_message_syslog (void *user_data, const char *quote, const char *fmt,
 | 
			
		||||
		syslog (prio, "%s%s", quote, buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// --- Connector ---------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// This is a helper that tries to establish a connection with any address on
 | 
			
		||||
// a given list.  Sadly it also introduces a bit of a callback hell.
 | 
			
		||||
 | 
			
		||||
struct connector_target
 | 
			
		||||
{
 | 
			
		||||
	LIST_HEADER (struct connector_target)
 | 
			
		||||
 | 
			
		||||
	char *hostname;                     ///< Target hostname or address
 | 
			
		||||
	char *service;                      ///< Target service name or port
 | 
			
		||||
 | 
			
		||||
	struct addrinfo *results;           ///< Resolved target
 | 
			
		||||
	struct addrinfo *iter;              ///< Current endpoint
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct connector_target *
 | 
			
		||||
connector_target_new (void)
 | 
			
		||||
{
 | 
			
		||||
	struct connector_target *self = xmalloc (sizeof *self);
 | 
			
		||||
	return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
connector_target_destroy (struct connector_target *self)
 | 
			
		||||
{
 | 
			
		||||
	free (self->hostname);
 | 
			
		||||
	free (self->service);
 | 
			
		||||
	freeaddrinfo (self->results);
 | 
			
		||||
	free (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
			
		||||
 | 
			
		||||
struct connector
 | 
			
		||||
{
 | 
			
		||||
	int socket;                         ///< Socket FD for the connection
 | 
			
		||||
	struct poller_fd connected_event;   ///< We've connected or failed
 | 
			
		||||
	struct connector_target *targets;   ///< Targets
 | 
			
		||||
	struct connector_target *targets_t; ///< Tail of targets
 | 
			
		||||
 | 
			
		||||
	void *user_data;                    ///< User data for callbacks
 | 
			
		||||
 | 
			
		||||
	// You may destroy the connector object in these two main callbacks:
 | 
			
		||||
 | 
			
		||||
	/// Connection has been successfully established
 | 
			
		||||
	void (*on_connected) (void *user_data, int socket);
 | 
			
		||||
	/// Failed to establish a connection to either target
 | 
			
		||||
	void (*on_failure) (void *user_data);
 | 
			
		||||
 | 
			
		||||
	// Optional:
 | 
			
		||||
 | 
			
		||||
	/// Connecting to a new address
 | 
			
		||||
	void (*on_connecting) (void *user_data, const char *address);
 | 
			
		||||
	/// Connecting to the last address has failed
 | 
			
		||||
	void (*on_error) (void *user_data, const char *error);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
connector_notify_connecting (struct connector *self,
 | 
			
		||||
	struct connector_target *target, struct addrinfo *gai_iter)
 | 
			
		||||
{
 | 
			
		||||
	if (!self->on_connecting)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	const char *real_host = target->hostname;
 | 
			
		||||
 | 
			
		||||
	// We don't really need this, so we can let it quietly fail
 | 
			
		||||
	char buf[NI_MAXHOST];
 | 
			
		||||
	int err = getnameinfo (gai_iter->ai_addr, gai_iter->ai_addrlen,
 | 
			
		||||
		buf, sizeof buf, NULL, 0, NI_NUMERICHOST);
 | 
			
		||||
	if (err)
 | 
			
		||||
		LOG_FUNC_FAILURE ("getnameinfo", gai_strerror (err));
 | 
			
		||||
	else
 | 
			
		||||
		real_host = buf;
 | 
			
		||||
 | 
			
		||||
	char *address = format_host_port_pair (real_host, target->service);
 | 
			
		||||
	self->on_connecting (self->user_data, address);
 | 
			
		||||
	free (address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
connector_notify_error (struct connector *self, const char *error)
 | 
			
		||||
{
 | 
			
		||||
	if (self->on_error)
 | 
			
		||||
		self->on_error (self->user_data, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
connector_prepare_next (struct connector *self)
 | 
			
		||||
{
 | 
			
		||||
	struct connector_target *target = self->targets;
 | 
			
		||||
	if (!(target->iter = target->iter->ai_next))
 | 
			
		||||
	{
 | 
			
		||||
		LIST_UNLINK_WITH_TAIL (self->targets, self->targets_t, target);
 | 
			
		||||
		connector_target_destroy (target);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
connector_step (struct connector *self)
 | 
			
		||||
{
 | 
			
		||||
	struct connector_target *target = self->targets;
 | 
			
		||||
	if (!target)
 | 
			
		||||
	{
 | 
			
		||||
		// Total failure, none of the targets has succeeded
 | 
			
		||||
		self->on_failure (self->user_data);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct addrinfo *gai_iter = target->iter;
 | 
			
		||||
	hard_assert (gai_iter != NULL);
 | 
			
		||||
 | 
			
		||||
	connector_notify_connecting (self, target, gai_iter);
 | 
			
		||||
 | 
			
		||||
	int fd = socket (gai_iter->ai_family,
 | 
			
		||||
		gai_iter->ai_socktype, gai_iter->ai_protocol);
 | 
			
		||||
	if (fd == -1)
 | 
			
		||||
	{
 | 
			
		||||
		connector_notify_error (self, strerror (errno));
 | 
			
		||||
 | 
			
		||||
		connector_prepare_next (self);
 | 
			
		||||
		connector_step (self);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	set_cloexec (fd);
 | 
			
		||||
	set_blocking (fd, false);
 | 
			
		||||
 | 
			
		||||
	int yes = 1;
 | 
			
		||||
	soft_assert (setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE,
 | 
			
		||||
		&yes, sizeof yes) != -1);
 | 
			
		||||
 | 
			
		||||
	if (!connect (fd, gai_iter->ai_addr, gai_iter->ai_addrlen))
 | 
			
		||||
	{
 | 
			
		||||
		set_blocking (fd, true);
 | 
			
		||||
		self->on_connected (self->user_data, fd);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if (errno != EINPROGRESS)
 | 
			
		||||
	{
 | 
			
		||||
		connector_notify_error (self, strerror (errno));
 | 
			
		||||
		xclose (fd);
 | 
			
		||||
 | 
			
		||||
		connector_prepare_next (self);
 | 
			
		||||
		connector_step (self);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	self->connected_event.fd = self->socket = fd;
 | 
			
		||||
	poller_fd_set (&self->connected_event, POLLOUT);
 | 
			
		||||
 | 
			
		||||
	connector_prepare_next (self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
connector_on_ready (const struct pollfd *pfd, struct connector *self)
 | 
			
		||||
{
 | 
			
		||||
	// See http://cr.yp.to/docs/connect.html if this doesn't work.
 | 
			
		||||
	// The second connect() method doesn't work with DragonflyBSD.
 | 
			
		||||
 | 
			
		||||
	int error = 0;
 | 
			
		||||
	socklen_t error_len = sizeof error;
 | 
			
		||||
	hard_assert (!getsockopt (pfd->fd,
 | 
			
		||||
		SOL_SOCKET, SO_ERROR, &error, &error_len));
 | 
			
		||||
 | 
			
		||||
	if (error)
 | 
			
		||||
	{
 | 
			
		||||
		connector_notify_error (self, strerror (error));
 | 
			
		||||
 | 
			
		||||
		poller_fd_reset (&self->connected_event);
 | 
			
		||||
		xclose (self->socket);
 | 
			
		||||
		self->socket = -1;
 | 
			
		||||
 | 
			
		||||
		connector_step (self);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		poller_fd_reset (&self->connected_event);
 | 
			
		||||
		self->socket = -1;
 | 
			
		||||
 | 
			
		||||
		set_blocking (pfd->fd, true);
 | 
			
		||||
		self->on_connected (self->user_data, pfd->fd);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
connector_init (struct connector *self, struct poller *poller)
 | 
			
		||||
{
 | 
			
		||||
	memset (self, 0, sizeof *self);
 | 
			
		||||
	self->socket = -1;
 | 
			
		||||
	poller_fd_init (&self->connected_event, poller, self->socket);
 | 
			
		||||
	self->connected_event.user_data = self;
 | 
			
		||||
	self->connected_event.dispatcher = (poller_fd_fn) connector_on_ready;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
connector_free (struct connector *self)
 | 
			
		||||
{
 | 
			
		||||
	poller_fd_reset (&self->connected_event);
 | 
			
		||||
	if (self->socket != -1)
 | 
			
		||||
		xclose (self->socket);
 | 
			
		||||
 | 
			
		||||
	LIST_FOR_EACH (struct connector_target, iter, self->targets)
 | 
			
		||||
		connector_target_destroy (iter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
connector_add_target (struct connector *self,
 | 
			
		||||
	const char *hostname, const char *service, struct error **e)
 | 
			
		||||
{
 | 
			
		||||
	struct addrinfo hints, *results;
 | 
			
		||||
	memset (&hints, 0, sizeof hints);
 | 
			
		||||
	hints.ai_socktype = SOCK_STREAM;
 | 
			
		||||
 | 
			
		||||
	// TODO: even this should be done asynchronously, most likely in
 | 
			
		||||
	//   a thread pool, similarly to how libuv does it
 | 
			
		||||
	int err = getaddrinfo (hostname, service, &hints, &results);
 | 
			
		||||
	if (err)
 | 
			
		||||
	{
 | 
			
		||||
		error_set (e, "%s: %s", "getaddrinfo", gai_strerror (err));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct connector_target *target = connector_target_new ();
 | 
			
		||||
	target->hostname = xstrdup (hostname);
 | 
			
		||||
	target->service = xstrdup (service);
 | 
			
		||||
	target->results = results;
 | 
			
		||||
	target->iter = target->results;
 | 
			
		||||
 | 
			
		||||
	LIST_APPEND_WITH_TAIL (self->targets, self->targets_t, target);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// --- SOCKS 5/4a --------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// Asynchronous SOCKS connector.  Adds more stuff on top of the regular one.
 | 
			
		||||
@@ -516,12 +276,11 @@ socks_4a_start (struct socks_connector *self)
 | 
			
		||||
 | 
			
		||||
	struct str *wb = &self->write_buffer;
 | 
			
		||||
	str_init (wb);
 | 
			
		||||
	str_append_c (wb, 4);                  // version
 | 
			
		||||
	str_append_c (wb, 1);                  // connect
 | 
			
		||||
	str_pack_u8 (wb, 4);                  // version
 | 
			
		||||
	str_pack_u8 (wb, 1);                  // connect
 | 
			
		||||
 | 
			
		||||
	str_append_c (wb, target->port >> 8);  // higher bits of port
 | 
			
		||||
	str_append_c (wb, target->port);       // lower bits of port
 | 
			
		||||
	str_append_data (wb, dest_ipv4, 4);    // destination address
 | 
			
		||||
	str_pack_u16 (wb, target->port);      // port
 | 
			
		||||
	str_append_data (wb, dest_ipv4, 4);   // destination address
 | 
			
		||||
 | 
			
		||||
	if (self->username)
 | 
			
		||||
		str_append (wb, self->username);
 | 
			
		||||
@@ -613,10 +372,10 @@ socks_5_request_start (struct socks_connector *self)
 | 
			
		||||
{
 | 
			
		||||
	struct socks_target *target = self->targets_iter;
 | 
			
		||||
	struct str *wb = &self->write_buffer;
 | 
			
		||||
	str_append_c (wb, 0x05);  // version
 | 
			
		||||
	str_append_c (wb, 0x01);  // connect
 | 
			
		||||
	str_append_c (wb, 0x00);  // reserved
 | 
			
		||||
	str_append_c (wb, target->address.type);
 | 
			
		||||
	str_pack_u8 (wb, 0x05);  // version
 | 
			
		||||
	str_pack_u8 (wb, 0x01);  // connect
 | 
			
		||||
	str_pack_u8 (wb, 0x00);  // reserved
 | 
			
		||||
	str_pack_u8 (wb, target->address.type);
 | 
			
		||||
 | 
			
		||||
	switch (target->address.type)
 | 
			
		||||
	{
 | 
			
		||||
@@ -630,7 +389,7 @@ socks_5_request_start (struct socks_connector *self)
 | 
			
		||||
		if (dlen > 255)
 | 
			
		||||
			dlen = 255;
 | 
			
		||||
 | 
			
		||||
		str_append_c (wb, dlen);
 | 
			
		||||
		str_pack_u8 (wb, dlen);
 | 
			
		||||
		str_append_data (wb, target->address.data.domain, dlen);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
@@ -639,8 +398,7 @@ socks_5_request_start (struct socks_connector *self)
 | 
			
		||||
			target->address.data.ipv6, sizeof target->address.data.ipv6);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	str_append_c (wb, target->port >> 8);
 | 
			
		||||
	str_append_c (wb, target->port);
 | 
			
		||||
	str_pack_u16 (wb, target->port);
 | 
			
		||||
 | 
			
		||||
	SOCKS_GO (socks_5_request_finish, 4);
 | 
			
		||||
}
 | 
			
		||||
@@ -673,10 +431,10 @@ socks_5_userpass_start (struct socks_connector *self)
 | 
			
		||||
		plen = 255;
 | 
			
		||||
 | 
			
		||||
	struct str *wb = &self->write_buffer;
 | 
			
		||||
	str_append_c (wb, 0x01);  // version
 | 
			
		||||
	str_append_c (wb, ulen);  // username length
 | 
			
		||||
	str_pack_u8 (wb, 0x01);  // version
 | 
			
		||||
	str_pack_u8 (wb, ulen);  // username length
 | 
			
		||||
	str_append_data (wb, self->username, ulen);
 | 
			
		||||
	str_append_c (wb, plen);  // password length
 | 
			
		||||
	str_pack_u8 (wb, plen);  // password length
 | 
			
		||||
	str_append_data (wb, self->password, plen);
 | 
			
		||||
 | 
			
		||||
	SOCKS_GO (socks_5_userpass_finish, 2);
 | 
			
		||||
@@ -715,11 +473,11 @@ socks_5_auth_start (struct socks_connector *self)
 | 
			
		||||
	bool can_auth = self->username && self->password;
 | 
			
		||||
 | 
			
		||||
	struct str *wb = &self->write_buffer;
 | 
			
		||||
	str_append_c (wb, 0x05);          // version
 | 
			
		||||
	str_append_c (wb, 1 + can_auth);  // number of authentication methods
 | 
			
		||||
	str_append_c (wb, 0x00);          // no authentication required
 | 
			
		||||
	str_pack_u8 (wb, 0x05);          // version
 | 
			
		||||
	str_pack_u8 (wb, 1 + can_auth);  // number of authentication methods
 | 
			
		||||
	str_pack_u8 (wb, 0x00);          // no authentication required
 | 
			
		||||
	if (can_auth)
 | 
			
		||||
		str_append_c (wb, 0x02);      // username/password
 | 
			
		||||
		str_pack_u8 (wb, 0x02);      // username/password
 | 
			
		||||
 | 
			
		||||
	SOCKS_GO (socks_5_auth_finish, 2);
 | 
			
		||||
}
 | 
			
		||||
@@ -1256,7 +1014,7 @@ enum config_item_type
 | 
			
		||||
	CONFIG_ITEM_STRING_ARRAY            ///< Comma-separated list of strings
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct config_item_
 | 
			
		||||
struct config_item
 | 
			
		||||
{
 | 
			
		||||
	enum config_item_type type;         ///< Type of the item
 | 
			
		||||
	union
 | 
			
		||||
@@ -1282,10 +1040,10 @@ struct config_schema
 | 
			
		||||
 | 
			
		||||
	/// Check if the new value can be accepted.
 | 
			
		||||
	/// In addition to this, "type" and having a default is considered.
 | 
			
		||||
	bool (*validate) (const struct config_item_ *, struct error **e);
 | 
			
		||||
	bool (*validate) (const struct config_item *, struct error **e);
 | 
			
		||||
 | 
			
		||||
	/// The value has changed
 | 
			
		||||
	void (*on_change) (struct config_item_ *);
 | 
			
		||||
	void (*on_change) (struct config_item *);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
			
		||||
@@ -1315,7 +1073,7 @@ config_item_type_is_string (enum config_item_type type)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_item_free (struct config_item_ *self)
 | 
			
		||||
config_item_free (struct config_item *self)
 | 
			
		||||
{
 | 
			
		||||
	switch (self->type)
 | 
			
		||||
	{
 | 
			
		||||
@@ -1331,7 +1089,7 @@ config_item_free (struct config_item_ *self)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_item_destroy (struct config_item_ *self)
 | 
			
		||||
config_item_destroy (struct config_item *self)
 | 
			
		||||
{
 | 
			
		||||
	config_item_free (self);
 | 
			
		||||
	free (self);
 | 
			
		||||
@@ -1340,7 +1098,7 @@ config_item_destroy (struct config_item_ *self)
 | 
			
		||||
/// Doesn't do any validations or handle schemas, just moves source data
 | 
			
		||||
/// to the target item and destroys the source item
 | 
			
		||||
static void
 | 
			
		||||
config_item_move (struct config_item_ *self, struct config_item_ *source)
 | 
			
		||||
config_item_move (struct config_item *self, struct config_item *source)
 | 
			
		||||
{
 | 
			
		||||
	// Not quite sure how to handle that
 | 
			
		||||
	hard_assert (!source->schema);
 | 
			
		||||
@@ -1351,40 +1109,40 @@ config_item_move (struct config_item_ *self, struct config_item_ *source)
 | 
			
		||||
	free (source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_item_new (enum config_item_type type)
 | 
			
		||||
{
 | 
			
		||||
	struct config_item_ *self = xcalloc (1, sizeof *self);
 | 
			
		||||
	struct config_item *self = xcalloc (1, sizeof *self);
 | 
			
		||||
	self->type = type;
 | 
			
		||||
	return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_item_null (void)
 | 
			
		||||
{
 | 
			
		||||
	return config_item_new (CONFIG_ITEM_NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_item_boolean (bool b)
 | 
			
		||||
{
 | 
			
		||||
	struct config_item_ *self = config_item_new (CONFIG_ITEM_BOOLEAN);
 | 
			
		||||
	struct config_item *self = config_item_new (CONFIG_ITEM_BOOLEAN);
 | 
			
		||||
	self->value.boolean = b;
 | 
			
		||||
	return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_item_integer (int64_t i)
 | 
			
		||||
{
 | 
			
		||||
	struct config_item_ *self = config_item_new (CONFIG_ITEM_INTEGER);
 | 
			
		||||
	struct config_item *self = config_item_new (CONFIG_ITEM_INTEGER);
 | 
			
		||||
	self->value.integer = i;
 | 
			
		||||
	return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_item_string (const struct str *s)
 | 
			
		||||
{
 | 
			
		||||
	struct config_item_ *self = config_item_new (CONFIG_ITEM_STRING);
 | 
			
		||||
	struct config_item *self = config_item_new (CONFIG_ITEM_STRING);
 | 
			
		||||
	str_init (&self->value.string);
 | 
			
		||||
	hard_assert (utf8_validate
 | 
			
		||||
		(self->value.string.str, self->value.string.len));
 | 
			
		||||
@@ -1392,29 +1150,29 @@ config_item_string (const struct str *s)
 | 
			
		||||
	return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_item_string_from_cstr (const char *s)
 | 
			
		||||
{
 | 
			
		||||
	struct str tmp;
 | 
			
		||||
	str_init (&tmp);
 | 
			
		||||
	str_append (&tmp, s);
 | 
			
		||||
	struct config_item_ *self = config_item_string (&tmp);
 | 
			
		||||
	struct config_item *self = config_item_string (&tmp);
 | 
			
		||||
	str_free (&tmp);
 | 
			
		||||
	return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_item_string_array (const struct str *s)
 | 
			
		||||
{
 | 
			
		||||
	struct config_item_ *self = config_item_string (s);
 | 
			
		||||
	struct config_item *self = config_item_string (s);
 | 
			
		||||
	self->type = CONFIG_ITEM_STRING_ARRAY;
 | 
			
		||||
	return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_item_object (void)
 | 
			
		||||
{
 | 
			
		||||
	struct config_item_ *self = config_item_new (CONFIG_ITEM_OBJECT);
 | 
			
		||||
	struct config_item *self = config_item_new (CONFIG_ITEM_OBJECT);
 | 
			
		||||
	str_map_init (&self->value.object);
 | 
			
		||||
	self->value.object.free = (void (*)(void *)) config_item_destroy;
 | 
			
		||||
	return self;
 | 
			
		||||
@@ -1434,7 +1192,7 @@ config_schema_accepts_type
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
config_item_validate_by_schema (struct config_item_ *self,
 | 
			
		||||
config_item_validate_by_schema (struct config_item *self,
 | 
			
		||||
	struct config_schema *schema, struct error **e)
 | 
			
		||||
{
 | 
			
		||||
	struct error *error = NULL;
 | 
			
		||||
@@ -1453,7 +1211,7 @@ config_item_validate_by_schema (struct config_item_ *self,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
config_item_set_from (struct config_item_ *self, struct config_item_ *source,
 | 
			
		||||
config_item_set_from (struct config_item *self, struct config_item *source,
 | 
			
		||||
	struct error **e)
 | 
			
		||||
{
 | 
			
		||||
	struct config_schema *schema = self->schema;
 | 
			
		||||
@@ -1480,8 +1238,8 @@ config_item_set_from (struct config_item_ *self, struct config_item_ *source,
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
config_item_get (struct config_item_ *self, const char *path, struct error **e)
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_item_get (struct config_item *self, const char *path, struct error **e)
 | 
			
		||||
{
 | 
			
		||||
	hard_assert (self->type == CONFIG_ITEM_OBJECT);
 | 
			
		||||
 | 
			
		||||
@@ -1489,7 +1247,7 @@ config_item_get (struct config_item_ *self, const char *path, struct error **e)
 | 
			
		||||
	str_vector_init (&v);
 | 
			
		||||
	split_str (path, '.', &v);
 | 
			
		||||
 | 
			
		||||
	struct config_item_ *result = NULL;
 | 
			
		||||
	struct config_item *result = NULL;
 | 
			
		||||
	size_t i = 0;
 | 
			
		||||
	while (true)
 | 
			
		||||
	{
 | 
			
		||||
@@ -1519,7 +1277,7 @@ struct config_writer
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void config_item_write_object_innards
 | 
			
		||||
	(struct config_writer *self, struct config_item_ *object);
 | 
			
		||||
	(struct config_writer *self, struct config_item *object);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_item_write_string (struct str *output, const struct str *s)
 | 
			
		||||
@@ -1541,7 +1299,7 @@ config_item_write_string (struct str *output, const struct str *s)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_item_write_object
 | 
			
		||||
	(struct config_writer *self, struct config_item_ *value)
 | 
			
		||||
	(struct config_writer *self, struct config_item *value)
 | 
			
		||||
{
 | 
			
		||||
	char indent[self->indent + 1];
 | 
			
		||||
	memset (indent, '\t', self->indent);
 | 
			
		||||
@@ -1560,7 +1318,7 @@ config_item_write_object
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_item_write_value (struct config_writer *self, struct config_item_ *value)
 | 
			
		||||
config_item_write_value (struct config_writer *self, struct config_item *value)
 | 
			
		||||
{
 | 
			
		||||
	switch (value->type)
 | 
			
		||||
	{
 | 
			
		||||
@@ -1587,7 +1345,7 @@ config_item_write_value (struct config_writer *self, struct config_item_ *value)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_item_write_kv_pair (struct config_writer *self,
 | 
			
		||||
	const char *key, struct config_item_ *value)
 | 
			
		||||
	const char *key, struct config_item *value)
 | 
			
		||||
{
 | 
			
		||||
	char indent[self->indent + 1];
 | 
			
		||||
	memset (indent, '\t', self->indent);
 | 
			
		||||
@@ -1604,20 +1362,20 @@ config_item_write_kv_pair (struct config_writer *self,
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_item_write_object_innards
 | 
			
		||||
	(struct config_writer *self, struct config_item_ *object)
 | 
			
		||||
	(struct config_writer *self, struct config_item *object)
 | 
			
		||||
{
 | 
			
		||||
	hard_assert (object->type == CONFIG_ITEM_OBJECT);
 | 
			
		||||
 | 
			
		||||
	struct str_map_iter iter;
 | 
			
		||||
	str_map_iter_init (&iter, &object->value.object);
 | 
			
		||||
 | 
			
		||||
	struct config_item_ *value;
 | 
			
		||||
	struct config_item *value;
 | 
			
		||||
	while ((value = str_map_iter_next (&iter)))
 | 
			
		||||
		config_item_write_kv_pair (self, iter.link->key, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_item_write (struct config_item_ *value,
 | 
			
		||||
config_item_write (struct config_item *value,
 | 
			
		||||
	bool object_innards, struct str *output)
 | 
			
		||||
{
 | 
			
		||||
	struct config_writer writer = { .output = output, .indent = 0 };
 | 
			
		||||
@@ -2011,13 +1769,13 @@ config_parser_expect
 | 
			
		||||
#define EXPECT(token)  config_parser_expect (self, token, err)
 | 
			
		||||
#define SKIP_NL()      do {} while (ACCEPT (CONFIG_T_NEWLINE))
 | 
			
		||||
 | 
			
		||||
static struct config_item_ *config_parser_parse_object
 | 
			
		||||
static struct config_item *config_parser_parse_object
 | 
			
		||||
	(struct config_parser *self, jmp_buf out);
 | 
			
		||||
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_parser_parse_value (struct config_parser *self, jmp_buf out)
 | 
			
		||||
{
 | 
			
		||||
	struct config_item_ *volatile result = NULL;
 | 
			
		||||
	struct config_item *volatile result = NULL;
 | 
			
		||||
	jmp_buf err;
 | 
			
		||||
 | 
			
		||||
	if (setjmp (err))
 | 
			
		||||
@@ -2052,7 +1810,7 @@ config_parser_parse_value (struct config_parser *self, jmp_buf out)
 | 
			
		||||
/// Parse a single "key = value" assignment into @a object
 | 
			
		||||
static bool
 | 
			
		||||
config_parser_parse_kv_pair (struct config_parser *self,
 | 
			
		||||
	struct config_item_ *object, jmp_buf out)
 | 
			
		||||
	struct config_item *object, jmp_buf out)
 | 
			
		||||
{
 | 
			
		||||
	char *volatile key = NULL;
 | 
			
		||||
	jmp_buf err;
 | 
			
		||||
@@ -2093,10 +1851,10 @@ config_parser_parse_kv_pair (struct config_parser *self,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Parse the inside of an object definition
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_parser_parse_object (struct config_parser *self, jmp_buf out)
 | 
			
		||||
{
 | 
			
		||||
	struct config_item_ *volatile object = config_item_object ();
 | 
			
		||||
	struct config_item *volatile object = config_item_object ();
 | 
			
		||||
	jmp_buf err;
 | 
			
		||||
 | 
			
		||||
	if (setjmp (err))
 | 
			
		||||
@@ -2119,14 +1877,14 @@ config_parser_parse_object (struct config_parser *self, jmp_buf out)
 | 
			
		||||
 | 
			
		||||
/// Parse a configuration snippet either as an object or a bare value.
 | 
			
		||||
/// If it's the latter (@a single_value_only), no newlines may follow.
 | 
			
		||||
static struct config_item_ *
 | 
			
		||||
static struct config_item *
 | 
			
		||||
config_item_parse (const char *script, size_t len,
 | 
			
		||||
	bool single_value_only, struct error **e)
 | 
			
		||||
{
 | 
			
		||||
	struct config_parser parser;
 | 
			
		||||
	config_parser_init (&parser, script, len);
 | 
			
		||||
 | 
			
		||||
	struct config_item_ *volatile object = NULL;
 | 
			
		||||
	struct config_item *volatile object = NULL;
 | 
			
		||||
	jmp_buf err;
 | 
			
		||||
 | 
			
		||||
	if (setjmp (err))
 | 
			
		||||
@@ -2158,14 +1916,14 @@ end:
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Clone an item.  Schema assignments aren't retained.
 | 
			
		||||
struct config_item_ *
 | 
			
		||||
config_item_clone (struct config_item_ *self)
 | 
			
		||||
struct config_item *
 | 
			
		||||
config_item_clone (struct config_item *self)
 | 
			
		||||
{
 | 
			
		||||
	// Oh well, it saves code
 | 
			
		||||
	struct str tmp;
 | 
			
		||||
	str_init (&tmp);
 | 
			
		||||
	config_item_write (self, false, &tmp);
 | 
			
		||||
	struct config_item_ *result =
 | 
			
		||||
	struct config_item *result =
 | 
			
		||||
		config_item_parse (tmp.str, tmp.len, true, NULL);
 | 
			
		||||
	str_free (&tmp);
 | 
			
		||||
	return result;
 | 
			
		||||
@@ -2175,9 +1933,9 @@ config_item_clone (struct config_item_ *self)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_schema_initialize_item (struct config_schema *schema,
 | 
			
		||||
	struct config_item_ *parent, void *user_data)
 | 
			
		||||
	struct config_item *parent, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	struct config_item_ *item =
 | 
			
		||||
	struct config_item *item =
 | 
			
		||||
		str_map_find (&parent->value.object, schema->name);
 | 
			
		||||
 | 
			
		||||
	bool replace = true;
 | 
			
		||||
@@ -2223,7 +1981,7 @@ config_schema_initialize_item (struct config_schema *schema,
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_schema_apply_to_object (struct config_schema *schema_array,
 | 
			
		||||
	struct config_item_ *object, void *user_data)
 | 
			
		||||
	struct config_item *object, void *user_data)
 | 
			
		||||
{
 | 
			
		||||
	hard_assert (object->type == CONFIG_ITEM_OBJECT);
 | 
			
		||||
	while (schema_array->name)
 | 
			
		||||
@@ -2231,14 +1989,14 @@ config_schema_apply_to_object (struct config_schema *schema_array,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_schema_call_changed (struct config_item_ *item)
 | 
			
		||||
config_schema_call_changed (struct config_item *item)
 | 
			
		||||
{
 | 
			
		||||
	if (item->type == CONFIG_ITEM_OBJECT)
 | 
			
		||||
	{
 | 
			
		||||
		struct str_map_iter iter;
 | 
			
		||||
		str_map_iter_init (&iter, &item->value.object);
 | 
			
		||||
 | 
			
		||||
		struct config_item_ *child;
 | 
			
		||||
		struct config_item *child;
 | 
			
		||||
		while ((child = str_map_iter_next (&iter)))
 | 
			
		||||
			config_schema_call_changed (child);
 | 
			
		||||
	}
 | 
			
		||||
@@ -2251,7 +2009,7 @@ config_schema_call_changed (struct config_item_ *item)
 | 
			
		||||
// XXX: this doesn't necessarily have to be well designed at all
 | 
			
		||||
 | 
			
		||||
typedef void (*config_module_load_fn)
 | 
			
		||||
	(struct config_item_ *subtree, void *user_data);
 | 
			
		||||
	(struct config_item *subtree, void *user_data);
 | 
			
		||||
 | 
			
		||||
struct config_module
 | 
			
		||||
{
 | 
			
		||||
@@ -2277,7 +2035,7 @@ config_module_destroy (struct config_module *self)
 | 
			
		||||
struct config
 | 
			
		||||
{
 | 
			
		||||
	struct str_map modules;             ///< Toplevel modules
 | 
			
		||||
	struct config_item_ *root;          ///< CONFIG_ITEM_OBJECT
 | 
			
		||||
	struct config_item *root;           ///< CONFIG_ITEM_OBJECT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -2309,7 +2067,7 @@ config_register_module (struct config *self,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_load (struct config *self, struct config_item_ *root)
 | 
			
		||||
config_load (struct config *self, struct config_item *root)
 | 
			
		||||
{
 | 
			
		||||
	hard_assert (root->type == CONFIG_ITEM_OBJECT);
 | 
			
		||||
	self->root = root;
 | 
			
		||||
@@ -2320,7 +2078,7 @@ config_load (struct config *self, struct config_item_ *root)
 | 
			
		||||
	struct config_module *module;
 | 
			
		||||
	while ((module = str_map_iter_next (&iter)))
 | 
			
		||||
	{
 | 
			
		||||
		struct config_item_ *subtree = str_map_find
 | 
			
		||||
		struct config_item *subtree = str_map_find
 | 
			
		||||
			(&root->value.object, module->name);
 | 
			
		||||
		// Silently fix inputs that only a lunatic user could create
 | 
			
		||||
		if (!subtree || subtree->type != CONFIG_ITEM_OBJECT)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										52
									
								
								kike.c
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								kike.c
									
									
									
									
									
								
							@@ -34,7 +34,7 @@ enum { PIPE_READ, PIPE_WRITE };
 | 
			
		||||
// Just get rid of the crappiest ciphers available by default
 | 
			
		||||
#define DEFAULT_CIPHERS "DEFAULT:!MEDIUM:!LOW"
 | 
			
		||||
 | 
			
		||||
static struct config_item g_config_table[] =
 | 
			
		||||
static struct simple_config_item g_config_table[] =
 | 
			
		||||
{
 | 
			
		||||
	{ "pid_file",        NULL,              "Path or name of the PID file"   },
 | 
			
		||||
	{ "server_name",     NULL,              "Server name"                    },
 | 
			
		||||
@@ -44,9 +44,9 @@ static struct config_item g_config_table[] =
 | 
			
		||||
 | 
			
		||||
	{ "bind_host",       NULL,              "Address of the IRC server"      },
 | 
			
		||||
	{ "bind_port",       "6667",            "Port of the IRC server"         },
 | 
			
		||||
	{ "ssl_cert",        NULL,              "Server TLS certificate (PEM)"   },
 | 
			
		||||
	{ "ssl_key",         NULL,              "Server TLS private key (PEM)"   },
 | 
			
		||||
	{ "ssl_ciphers",     DEFAULT_CIPHERS,   "OpenSSL cipher list"            },
 | 
			
		||||
	{ "tls_cert",        NULL,              "Server TLS certificate (PEM)"   },
 | 
			
		||||
	{ "tls_key",         NULL,              "Server TLS private key (PEM)"   },
 | 
			
		||||
	{ "tls_ciphers",     DEFAULT_CIPHERS,   "OpenSSL cipher list"            },
 | 
			
		||||
 | 
			
		||||
	{ "operators",       NULL,              "IRCop TLS cert. fingerprints"   },
 | 
			
		||||
 | 
			
		||||
@@ -666,7 +666,7 @@ server_context_init (struct server_context *self)
 | 
			
		||||
 | 
			
		||||
	str_map_init (&self->config);
 | 
			
		||||
	self->config.free = free;
 | 
			
		||||
	load_config_defaults (&self->config, g_config_table);
 | 
			
		||||
	simple_config_load_defaults (&self->config, g_config_table);
 | 
			
		||||
 | 
			
		||||
	str_vector_init (&self->motd);
 | 
			
		||||
	self->catalog = (nl_catd) -1;
 | 
			
		||||
@@ -3106,7 +3106,7 @@ irc_try_read (struct client *c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
irc_try_read_ssl (struct client *c)
 | 
			
		||||
irc_try_read_tls (struct client *c)
 | 
			
		||||
{
 | 
			
		||||
	if (c->ssl_tx_want_rx)
 | 
			
		||||
		return true;
 | 
			
		||||
@@ -3174,7 +3174,7 @@ irc_try_write (struct client *c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
irc_try_write_ssl (struct client *c)
 | 
			
		||||
irc_try_write_tls (struct client *c)
 | 
			
		||||
{
 | 
			
		||||
	if (c->ssl_rx_want_tx)
 | 
			
		||||
		return true;
 | 
			
		||||
@@ -3212,7 +3212,7 @@ irc_try_write_ssl (struct client *c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
irc_autodetect_ssl (struct client *c)
 | 
			
		||||
irc_autodetect_tls (struct client *c)
 | 
			
		||||
{
 | 
			
		||||
	// Trivial SSL/TLS autodetection.  The first block of data returned by
 | 
			
		||||
	// recv() must be at least three bytes long for this to work reliably,
 | 
			
		||||
@@ -3251,7 +3251,7 @@ start:
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
client_initialize_ssl (struct client *c)
 | 
			
		||||
client_initialize_tls (struct client *c)
 | 
			
		||||
{
 | 
			
		||||
	const char *error_info = NULL;
 | 
			
		||||
	if (!c->ctx->ssl_ctx)
 | 
			
		||||
@@ -3288,7 +3288,7 @@ on_client_ready (const struct pollfd *pfd, void *user_data)
 | 
			
		||||
	if (!c->initialized)
 | 
			
		||||
	{
 | 
			
		||||
		hard_assert (pfd->events == POLLIN);
 | 
			
		||||
		if (irc_autodetect_ssl (c) && !client_initialize_ssl (c))
 | 
			
		||||
		if (irc_autodetect_tls (c) && !client_initialize_tls (c))
 | 
			
		||||
		{
 | 
			
		||||
			client_kill (c, NULL);
 | 
			
		||||
			return;
 | 
			
		||||
@@ -3301,7 +3301,7 @@ on_client_ready (const struct pollfd *pfd, void *user_data)
 | 
			
		||||
	{
 | 
			
		||||
		// Reads may want to write, writes may want to read, poll() may
 | 
			
		||||
		// return unexpected things in `revents'... let's try both
 | 
			
		||||
		if (!irc_try_read_ssl (c) || !irc_try_write_ssl (c))
 | 
			
		||||
		if (!irc_try_read_tls (c) || !irc_try_write_tls (c))
 | 
			
		||||
			return;
 | 
			
		||||
	}
 | 
			
		||||
	else if (!irc_try_read (c) || !irc_try_write (c))
 | 
			
		||||
@@ -3510,7 +3510,7 @@ irc_initialize_ssl_ctx (struct server_context *ctx,
 | 
			
		||||
	SSL_CTX_set_options (ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
 | 
			
		||||
 | 
			
		||||
	// XXX: perhaps we should read the files ourselves for better messages
 | 
			
		||||
	const char *ciphers = str_map_find (&ctx->config, "ssl_ciphers");
 | 
			
		||||
	const char *ciphers = str_map_find (&ctx->config, "tls_ciphers");
 | 
			
		||||
	if (!SSL_CTX_set_cipher_list (ctx->ssl_ctx, ciphers))
 | 
			
		||||
		error_set (e, "failed to select any cipher from the cipher list");
 | 
			
		||||
	else if (!SSL_CTX_use_certificate_chain_file (ctx->ssl_ctx, cert_path))
 | 
			
		||||
@@ -3531,33 +3531,33 @@ irc_initialize_ssl_ctx (struct server_context *ctx,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
irc_initialize_ssl (struct server_context *ctx, struct error **e)
 | 
			
		||||
irc_initialize_tls (struct server_context *ctx, struct error **e)
 | 
			
		||||
{
 | 
			
		||||
	const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
 | 
			
		||||
	const char *ssl_key = str_map_find (&ctx->config, "ssl_key");
 | 
			
		||||
	const char *tls_cert = str_map_find (&ctx->config, "tls_cert");
 | 
			
		||||
	const char *tls_key  = str_map_find (&ctx->config, "tls_key");
 | 
			
		||||
 | 
			
		||||
	// Only try to enable SSL support if the user configures it; it is not
 | 
			
		||||
	// a failure if no one has requested it.
 | 
			
		||||
	if (!ssl_cert && !ssl_key)
 | 
			
		||||
	if (!tls_cert && !tls_key)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	if (!ssl_cert)
 | 
			
		||||
	if (!tls_cert)
 | 
			
		||||
		error_set (e, "no TLS certificate set");
 | 
			
		||||
	else if (!ssl_key)
 | 
			
		||||
	else if (!tls_key)
 | 
			
		||||
		error_set (e, "no TLS private key set");
 | 
			
		||||
	if (!ssl_cert || !ssl_key)
 | 
			
		||||
	if (!tls_cert || !tls_key)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	bool result = false;
 | 
			
		||||
 | 
			
		||||
	char *cert_path = resolve_filename
 | 
			
		||||
		(ssl_cert, resolve_relative_config_filename);
 | 
			
		||||
		(tls_cert, resolve_relative_config_filename);
 | 
			
		||||
	char *key_path = resolve_filename
 | 
			
		||||
		(ssl_key, resolve_relative_config_filename);
 | 
			
		||||
		(tls_key, resolve_relative_config_filename);
 | 
			
		||||
	if (!cert_path)
 | 
			
		||||
		error_set (e, "%s: %s", "cannot open file", ssl_cert);
 | 
			
		||||
		error_set (e, "%s: %s", "cannot open file", tls_cert);
 | 
			
		||||
	else if (!key_path)
 | 
			
		||||
		error_set (e, "%s: %s", "cannot open file", ssl_key);
 | 
			
		||||
		error_set (e, "%s: %s", "cannot open file", tls_key);
 | 
			
		||||
	else
 | 
			
		||||
		result = irc_initialize_ssl_ctx (ctx, cert_path, key_path, e);
 | 
			
		||||
 | 
			
		||||
@@ -3982,7 +3982,7 @@ main (int argc, char *argv[])
 | 
			
		||||
		printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
 | 
			
		||||
		exit (EXIT_SUCCESS);
 | 
			
		||||
	case 'w':
 | 
			
		||||
		call_write_default_config (optarg, g_config_table);
 | 
			
		||||
		call_simple_config_write_default (optarg, g_config_table);
 | 
			
		||||
		exit (EXIT_SUCCESS);
 | 
			
		||||
	default:
 | 
			
		||||
		print_error ("wrong options");
 | 
			
		||||
@@ -4007,7 +4007,7 @@ main (int argc, char *argv[])
 | 
			
		||||
	irc_register_cap_handlers (&ctx);
 | 
			
		||||
 | 
			
		||||
	struct error *e = NULL;
 | 
			
		||||
	if (!read_config_file (&ctx.config, &e))
 | 
			
		||||
	if (!simple_config_update_from_file (&ctx.config, &e))
 | 
			
		||||
	{
 | 
			
		||||
		print_error ("error loading configuration: %s", e->message);
 | 
			
		||||
		error_free (e);
 | 
			
		||||
@@ -4019,7 +4019,7 @@ main (int argc, char *argv[])
 | 
			
		||||
	ctx.signal_event.user_data = &ctx;
 | 
			
		||||
	poller_fd_set (&ctx.signal_event, POLLIN);
 | 
			
		||||
 | 
			
		||||
	if (!irc_initialize_ssl (&ctx, &e)
 | 
			
		||||
	if (!irc_initialize_tls (&ctx, &e)
 | 
			
		||||
	 || !irc_initialize_server_name (&ctx, &e)
 | 
			
		||||
	 || !irc_initialize_motd (&ctx, &e)
 | 
			
		||||
	 || !irc_initialize_catalog (&ctx, &e)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								liberty
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								liberty
									
									
									
									
									
								
							 Submodule liberty updated: 02708608a9...649c351560
									
								
							
							
								
								
									
										44
									
								
								zyklonb.c
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								zyklonb.c
									
									
									
									
									
								
							@@ -24,7 +24,7 @@
 | 
			
		||||
 | 
			
		||||
// --- Configuration (application-specific) ------------------------------------
 | 
			
		||||
 | 
			
		||||
static struct config_item g_config_table[] =
 | 
			
		||||
static struct simple_config_item g_config_table[] =
 | 
			
		||||
{
 | 
			
		||||
	{ "nickname",        "ZyklonB",         "IRC nickname"                   },
 | 
			
		||||
	{ "username",        "bot",             "IRC user name"                  },
 | 
			
		||||
@@ -32,11 +32,11 @@ static struct config_item g_config_table[] =
 | 
			
		||||
 | 
			
		||||
	{ "irc_host",        NULL,              "Address of the IRC server"      },
 | 
			
		||||
	{ "irc_port",        "6667",            "Port of the IRC server"         },
 | 
			
		||||
	{ "ssl",             "off",             "Whether to use SSL"             },
 | 
			
		||||
	{ "ssl_cert",        NULL,              "Client SSL certificate (PEM)"   },
 | 
			
		||||
	{ "ssl_verify",      "on",              "Whether to verify certificates" },
 | 
			
		||||
	{ "ssl_ca_file",     NULL,              "OpenSSL CA bundle file"         },
 | 
			
		||||
	{ "ssl_ca_path",     NULL,              "OpenSSL CA bundle path"         },
 | 
			
		||||
	{ "tls",             "off",             "Whether to use TLS"             },
 | 
			
		||||
	{ "tls_cert",        NULL,              "Client TLS certificate (PEM)"   },
 | 
			
		||||
	{ "tls_verify",      "on",              "Whether to verify certificates" },
 | 
			
		||||
	{ "tls_ca_file",     NULL,              "OpenSSL CA bundle file"         },
 | 
			
		||||
	{ "tls_ca_path",     NULL,              "OpenSSL CA bundle path"         },
 | 
			
		||||
	{ "autojoin",        NULL,              "Channels to join on start"      },
 | 
			
		||||
	{ "reconnect",       "on",              "Whether to reconnect on error"  },
 | 
			
		||||
	{ "reconnect_delay", "5",               "Time between reconnecting"      },
 | 
			
		||||
@@ -153,7 +153,7 @@ bot_context_init (struct bot_context *self)
 | 
			
		||||
{
 | 
			
		||||
	str_map_init (&self->config);
 | 
			
		||||
	self->config.free = free;
 | 
			
		||||
	load_config_defaults (&self->config, g_config_table);
 | 
			
		||||
	simple_config_load_defaults (&self->config, g_config_table);
 | 
			
		||||
	self->admin_re = NULL;
 | 
			
		||||
 | 
			
		||||
	self->irc_fd = -1;
 | 
			
		||||
@@ -320,7 +320,7 @@ irc_initialize_ssl_ctx (struct bot_context *ctx, struct error **e)
 | 
			
		||||
	SSL_CTX_set_options (ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
 | 
			
		||||
 | 
			
		||||
	bool verify;
 | 
			
		||||
	if (!irc_get_boolean_from_config (ctx, "ssl_verify", &verify, e))
 | 
			
		||||
	if (!irc_get_boolean_from_config (ctx, "tls_verify", &verify, e))
 | 
			
		||||
		return false;
 | 
			
		||||
	SSL_CTX_set_verify (ctx->ssl_ctx,
 | 
			
		||||
		verify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
 | 
			
		||||
@@ -363,7 +363,7 @@ ca_error:
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
irc_initialize_ssl (struct bot_context *ctx, struct error **e)
 | 
			
		||||
irc_initialize_tls (struct bot_context *ctx, struct error **e)
 | 
			
		||||
{
 | 
			
		||||
	const char *error_info = NULL;
 | 
			
		||||
	ctx->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
 | 
			
		||||
@@ -376,17 +376,17 @@ irc_initialize_ssl (struct bot_context *ctx, struct error **e)
 | 
			
		||||
	if (!ctx->ssl)
 | 
			
		||||
		goto error_ssl_2;
 | 
			
		||||
 | 
			
		||||
	const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
 | 
			
		||||
	if (ssl_cert)
 | 
			
		||||
	const char *tls_cert = str_map_find (&ctx->config, "tls_cert");
 | 
			
		||||
	if (tls_cert)
 | 
			
		||||
	{
 | 
			
		||||
		char *path = resolve_filename
 | 
			
		||||
			(ssl_cert, resolve_relative_config_filename);
 | 
			
		||||
			(tls_cert, resolve_relative_config_filename);
 | 
			
		||||
		if (!path)
 | 
			
		||||
			print_error ("%s: %s", "cannot open file", ssl_cert);
 | 
			
		||||
			print_error ("%s: %s", "cannot open file", tls_cert);
 | 
			
		||||
		// XXX: perhaps we should read the file ourselves for better messages
 | 
			
		||||
		else if (!SSL_use_certificate_file (ctx->ssl, path, SSL_FILETYPE_PEM)
 | 
			
		||||
			|| !SSL_use_PrivateKey_file (ctx->ssl, path, SSL_FILETYPE_PEM))
 | 
			
		||||
			print_error ("%s: %s", "setting the SSL client certificate failed",
 | 
			
		||||
			print_error ("%s: %s", "setting the TLS client certificate failed",
 | 
			
		||||
				ERR_error_string (ERR_get_error (), NULL));
 | 
			
		||||
		free (path);
 | 
			
		||||
	}
 | 
			
		||||
@@ -418,7 +418,7 @@ error_ssl_1:
 | 
			
		||||
	//   multiple errors on the OpenSSL stack.
 | 
			
		||||
	if (!error_info)
 | 
			
		||||
		error_info = ERR_error_string (ERR_get_error (), NULL);
 | 
			
		||||
	error_set (e, "%s: %s", "could not initialize SSL", error_info);
 | 
			
		||||
	error_set (e, "%s: %s", "could not initialize TLS", error_info);
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1444,7 +1444,7 @@ enum irc_read_result
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static enum irc_read_result
 | 
			
		||||
irc_fill_read_buffer_ssl (struct bot_context *ctx, struct str *buf)
 | 
			
		||||
irc_fill_read_buffer_tls (struct bot_context *ctx, struct str *buf)
 | 
			
		||||
{
 | 
			
		||||
	int n_read;
 | 
			
		||||
start:
 | 
			
		||||
@@ -1608,7 +1608,7 @@ on_irc_readable (const struct pollfd *fd, struct bot_context *ctx)
 | 
			
		||||
	struct str *buf = &ctx->read_buffer;
 | 
			
		||||
	enum irc_read_result (*fill_buffer)(struct bot_context *, struct str *)
 | 
			
		||||
		= ctx->ssl
 | 
			
		||||
		? irc_fill_read_buffer_ssl
 | 
			
		||||
		? irc_fill_read_buffer_tls
 | 
			
		||||
		: irc_fill_read_buffer;
 | 
			
		||||
	bool disconnected = false;
 | 
			
		||||
	while (true)
 | 
			
		||||
@@ -1754,8 +1754,8 @@ irc_connect (struct bot_context *ctx, struct error **e)
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool use_ssl;
 | 
			
		||||
	if (!irc_get_boolean_from_config (ctx, "ssl", &use_ssl, e))
 | 
			
		||||
	bool use_tls;
 | 
			
		||||
	if (!irc_get_boolean_from_config (ctx, "tls", &use_tls, e))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	bool connected = socks_host
 | 
			
		||||
@@ -1765,7 +1765,7 @@ irc_connect (struct bot_context *ctx, struct error **e)
 | 
			
		||||
	if (!connected)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (use_ssl && !irc_initialize_ssl (ctx, e))
 | 
			
		||||
	if (use_tls && !irc_initialize_tls (ctx, e))
 | 
			
		||||
	{
 | 
			
		||||
		xclose (ctx->irc_fd);
 | 
			
		||||
		ctx->irc_fd = -1;
 | 
			
		||||
@@ -1965,7 +1965,7 @@ main (int argc, char *argv[])
 | 
			
		||||
		printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
 | 
			
		||||
		exit (EXIT_SUCCESS);
 | 
			
		||||
	case 'w':
 | 
			
		||||
		call_write_default_config (optarg, g_config_table);
 | 
			
		||||
		call_simple_config_write_default (optarg, g_config_table);
 | 
			
		||||
		exit (EXIT_SUCCESS);
 | 
			
		||||
	default:
 | 
			
		||||
		print_error ("wrong options");
 | 
			
		||||
@@ -1988,7 +1988,7 @@ main (int argc, char *argv[])
 | 
			
		||||
	bot_context_init (&ctx);
 | 
			
		||||
 | 
			
		||||
	struct error *e = NULL;
 | 
			
		||||
	if (!read_config_file (&ctx.config, &e)
 | 
			
		||||
	if (!simple_config_update_from_file (&ctx.config, &e)
 | 
			
		||||
	 || !setup_recovery_handler (&ctx, &e))
 | 
			
		||||
	{
 | 
			
		||||
		print_error ("%s", e->message);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user