Merge pull request #9 from sudo-project/audit-server-tls-support
Audit server tls support
This commit is contained in:
3
configure
vendored
3
configure
vendored
@@ -744,6 +744,7 @@ LOCALEDIR_SUFFIX
|
||||
SUDO_NLS
|
||||
LIBPTHREAD
|
||||
LIBMD
|
||||
OPENSSL_LIBS
|
||||
LIBINTL
|
||||
LIBRT
|
||||
LIBDL
|
||||
@@ -3152,6 +3153,7 @@ PSMAN=0
|
||||
SEMAN=0
|
||||
LIBINTL=
|
||||
LIBMD=
|
||||
OPENSSL_LIBS=
|
||||
ZLIB=
|
||||
ZLIB_SRC=
|
||||
AUTH_OBJS=
|
||||
@@ -6428,6 +6430,7 @@ if test "${enable_openssl+set}" = set; then :
|
||||
enableval=$enable_openssl; case $enableval in
|
||||
no) ;;
|
||||
*) LIBMD="-lcrypto"
|
||||
OPENSSL_LIBS="-lcrypto -lssl"
|
||||
DIGEST=digest_openssl.lo
|
||||
$as_echo "#define HAVE_OPENSSL 1" >>confdefs.h
|
||||
|
||||
|
@@ -17,6 +17,51 @@
|
||||
# The default is to listen on all addresses.
|
||||
#listen_address = *:30344
|
||||
|
||||
# Sets timeout for the socket. If this parameter is not set,
|
||||
# the value will be 0 (no timeout)
|
||||
#timeout = 30
|
||||
|
||||
# Sets audit server's communication over TLS on/off.
|
||||
# Minimum negotiable TLS version is 1.2
|
||||
#tls = true
|
||||
|
||||
# Path to the certificate authority bundle file
|
||||
# It must be in PEM format!
|
||||
#tls_cacert = /etc/sudo_logsrvd_ca.pem
|
||||
|
||||
# Path to the audit server's private key file
|
||||
# It must be in PEM format!
|
||||
#tls_key = /etc/sudo_logsrvd_key.pem
|
||||
|
||||
# Path to the audit server's certificate file
|
||||
# It must be in PEM format!
|
||||
#tls_cert = /etc/sudo_logsrvd_cert.pem
|
||||
|
||||
# Path to the Diffie-Hellman parameter file
|
||||
# If this parameter is not set, the audit server
|
||||
# will use the OpenSSL defaults for Diffie-Hellman key generation
|
||||
# It must be in PEM format!
|
||||
#tls_dhparams = /etc/sudo_logsrvd_dhparams.pem
|
||||
|
||||
# TLS cipher list (see "CIPHER LIST FORMAT" in the OpenSSL manual)
|
||||
# NOTE that this setting is only effective if the negotiated protocol
|
||||
# is TLSver1.2.
|
||||
#tls_ciphers_v12 = HIGH:!aNULL
|
||||
|
||||
# TLS cipher list if negotiated protocol is TLSver1.3
|
||||
# available ciphersuites are:
|
||||
# TLS_AES_128_GCM_SHA256
|
||||
# TLS_AES_256_GCM_SHA384
|
||||
# TLS_CHACHA20_POLY1305_SHA256
|
||||
# TLS_AES_128_CCM_SHA256
|
||||
# TLS_AES_128_CCM_8_SHA256
|
||||
# multiple ciphersuites can be set separated by ':'
|
||||
# by default, all ciphersuites are enabled
|
||||
#tls_ciphers_v13 = TLS_AES_256_GCM_SHA384
|
||||
|
||||
# Validate client certificates
|
||||
#tls_checkpeer = false
|
||||
|
||||
[iolog]
|
||||
# The top-level directory to use when constructing the path name for the
|
||||
# I/O log directory. The session sequence number, if any, is stored here.
|
||||
|
@@ -72,6 +72,8 @@ PIE_LDFLAGS = @PIE_LDFLAGS@
|
||||
SSP_CFLAGS = @SSP_CFLAGS@
|
||||
SSP_LDFLAGS = @SSP_LDFLAGS@
|
||||
|
||||
OPENSSL_LIBS = @OPENSSL_LIBS@
|
||||
|
||||
# cppcheck options, usually set in the top-level Makefile
|
||||
CPPCHECK_OPTS = -q --force --enable=warning,performance,portability --suppress=constStatement --error-exitcode=1 --inline-suppr -Dva_copy=va_copy -U__cplusplus -UQUAD_MAX -UQUAD_MIN -UUQUAD_MAX -U_POSIX_HOST_NAME_MAX -U_POSIX_PATH_MAX -U__NBBY -DNSIG=64
|
||||
|
||||
@@ -145,10 +147,10 @@ Makefile: $(srcdir)/Makefile.in
|
||||
ifile=$<; rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $${ifile%i}c --i-file $< --output-file $@
|
||||
|
||||
sudo_logsrvd: $(LOGSRVD_OBJS) $(LT_LIBS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(LOGSRVD_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(LOGSRVD_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) $(OPENSSL_LIBS)
|
||||
|
||||
sudo_sendlog: $(SENDLOG_OBJS) $(LT_LIBS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(SENDLOG_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
|
||||
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(SENDLOG_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) $(OPENSSL_LIBS)
|
||||
|
||||
GENERATED = log_server.pb-c.h log_server.pb-c.c
|
||||
|
||||
|
@@ -40,6 +40,11 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
#include "log_server.pb-c.h"
|
||||
#include "sudo_gettext.h" /* must be included before sudo_compat.h */
|
||||
#include "sudo_compat.h"
|
||||
@@ -60,6 +65,11 @@
|
||||
# include "compat/getopt.h"
|
||||
#endif /* HAVE_GETOPT_LONG */
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
# define LOGSRVD_DEFAULT_CIPHER_LST12 "HIGH:!aNULL"
|
||||
# define LOGSRVD_DEFAULT_CIPHER_LST13 "TLS_AES_256_GCM_SHA384"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Sudo I/O audit server.
|
||||
*/
|
||||
@@ -81,6 +91,13 @@ connection_closure_free(struct connection_closure *closure)
|
||||
if (closure != NULL) {
|
||||
bool shutting_down = closure->state == SHUTDOWN;
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
/* deallocate the connection's ssl object */
|
||||
if (logsrvd_conf_get_tls_opt() == true) {
|
||||
if (closure->ssl)
|
||||
SSL_free(closure->ssl);
|
||||
}
|
||||
#endif
|
||||
TAILQ_REMOVE(&connections, closure, entries);
|
||||
close(closure->sock);
|
||||
iolog_close_all(closure);
|
||||
@@ -556,6 +573,12 @@ shutdown_cb(int unused, int what, void *v)
|
||||
struct sudo_event_base *base = v;
|
||||
debug_decl(shutdown_cb, SUDO_DEBUG_UTIL)
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
/* deallocate server's SSL context object */
|
||||
if (logsrvd_conf_get_tls_opt() == true) {
|
||||
SSL_CTX_free(logsrvd_get_tls_runtime()->ssl_ctx);
|
||||
}
|
||||
#endif
|
||||
sudo_ev_loopbreak(base);
|
||||
|
||||
debug_return;
|
||||
@@ -614,7 +637,16 @@ server_msg_cb(int fd, int what, void *v)
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: sending %u bytes to client",
|
||||
__func__, buf->len - buf->off);
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
if (logsrvd_conf_get_tls_opt() == true) {
|
||||
nwritten = SSL_write(closure->ssl, buf->data + buf->off, buf->len - buf->off);
|
||||
} else {
|
||||
nwritten = send(fd, buf->data + buf->off, buf->len - buf->off, 0);
|
||||
}
|
||||
#else
|
||||
nwritten = send(fd, buf->data + buf->off, buf->len - buf->off, 0);
|
||||
#endif
|
||||
|
||||
if (nwritten == -1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||
"unable to send %u bytes", buf->len - buf->off);
|
||||
@@ -652,7 +684,16 @@ client_msg_cb(int fd, int what, void *v)
|
||||
ssize_t nread;
|
||||
debug_decl(client_msg_cb, SUDO_DEBUG_UTIL)
|
||||
|
||||
nread = recv(fd, buf->data + buf->len, buf->size - buf->len, 0);
|
||||
#if defined(HAVE_OPENSSL)
|
||||
if (logsrvd_conf_get_tls_opt() == true) {
|
||||
nread = SSL_read(closure->ssl, buf->data + buf->len, buf->size);
|
||||
} else {
|
||||
nread = recv(fd, buf->data + buf->len, buf->size - buf->len, 0);
|
||||
}
|
||||
#else
|
||||
nread = recv(fd, buf->data + buf->len, buf->size - buf->len, 0);
|
||||
#endif
|
||||
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received %zd bytes from client",
|
||||
__func__, nread);
|
||||
switch (nread) {
|
||||
@@ -784,6 +825,306 @@ signal_cb(int signo, int what, void *v)
|
||||
debug_return;
|
||||
}
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
static X509 *
|
||||
load_cert(const char *file)
|
||||
{
|
||||
X509 *x509 = NULL;
|
||||
BIO *cert = NULL;
|
||||
|
||||
debug_decl(load_cert, SUDO_DEBUG_UTIL)
|
||||
|
||||
if ((cert = BIO_new(BIO_s_file())) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to allocate new BIO object for certificate: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (BIO_read_filename(cert, file) <= 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to read certificate file: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
x509 = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
|
||||
|
||||
exit:
|
||||
if (cert)
|
||||
BIO_free(cert);
|
||||
|
||||
debug_return_ptr(x509);
|
||||
}
|
||||
|
||||
static bool
|
||||
check_cert(X509_STORE *ca_store_ctx, SSL_CTX *ctx, const char *cert_file)
|
||||
{
|
||||
bool ret = false;
|
||||
X509_STORE_CTX *store_ctx = NULL;
|
||||
X509 *x509 = NULL;
|
||||
|
||||
debug_decl(check_cert, SUDO_DEBUG_UTIL)
|
||||
|
||||
if ((x509 = load_cert(cert_file)) == NULL)
|
||||
goto exit;
|
||||
|
||||
if ((store_ctx = X509_STORE_CTX_new()) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to allocate X509_STORE_CTX object: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
X509_STORE_set_flags(ca_store_ctx, X509_V_FLAG_X509_STRICT);
|
||||
|
||||
if (!X509_STORE_CTX_init(store_ctx, ca_store_ctx, x509, 0)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to initialize X509_STORE_CTX object: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (X509_verify_cert(store_ctx) <= 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to verify cert: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* everything is good, use this server certificate during TLS handshakes */
|
||||
if (!SSL_CTX_use_certificate(ctx, x509)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to load cert to the ssl context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
ret = true;
|
||||
exit:
|
||||
X509_STORE_CTX_free(store_ctx);
|
||||
X509_free(x509);
|
||||
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_server_cert(SSL_CTX *ctx, const struct logsrvd_tls_config *tls_config)
|
||||
{
|
||||
bool ret = false;
|
||||
X509_STORE *ca_store_ctx = NULL;
|
||||
X509_LOOKUP *x509_lookup = NULL;
|
||||
|
||||
debug_decl(verify_server_cert, SUDO_DEBUG_UTIL)
|
||||
|
||||
if ((ca_store_ctx = X509_STORE_new()) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to allocate X509_STORE object for CA bundle: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((x509_lookup = X509_STORE_add_lookup(ca_store_ctx, X509_LOOKUP_file())) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to set lookup method: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if(!X509_LOOKUP_load_file(x509_lookup, tls_config->cacert_path, X509_FILETYPE_PEM)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to load CA bundle file: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = check_cert(ca_store_ctx, ctx, tls_config->cert_path);
|
||||
|
||||
exit:
|
||||
X509_STORE_free(ca_store_ctx);
|
||||
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
static bool
|
||||
init_tls_ciphersuites(SSL_CTX *ctx, const struct logsrvd_tls_config *tls_config)
|
||||
{
|
||||
debug_decl(init_tls_ciphersuites, SUDO_DEBUG_UTIL)
|
||||
|
||||
/* try to set TLS v1.2 ciphersuite list from config if given */
|
||||
if (tls_config->ciphers_v12) {
|
||||
if (SSL_CTX_set_cipher_list(ctx, tls_config->ciphers_v12)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||
"TLS v1.2 ciphersuite list is set from config");
|
||||
} else {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to set configured TLS v1.2 ciphersuite list (%s). Falling back to default...",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
debug_return_bool(false);
|
||||
}
|
||||
/* fallback to default ciphersuites for TLS v1.2 */
|
||||
} else {
|
||||
if (SSL_CTX_set_cipher_list(ctx, LOGSRVD_DEFAULT_CIPHER_LST12) <= 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to load default TLS v1.2 ciphersuite list: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
debug_return_bool(false);
|
||||
} else {
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||
"TLS v1.2 ciphersuite list is set to default (%s)",
|
||||
LOGSRVD_DEFAULT_CIPHER_LST12);
|
||||
}
|
||||
}
|
||||
|
||||
/* try to set TLSv1.3 ciphersuite list from config */
|
||||
if (tls_config->ciphers_v13) {
|
||||
if (SSL_CTX_set_ciphersuites(ctx, tls_config->ciphers_v13)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||
"TLS v1.3 ciphersuite list is set from config");
|
||||
} else {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to load configured TLS v1.3 ciphersuite list (%s). Falling back to default...",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
debug_return_bool(false);
|
||||
}
|
||||
/* fallback to default ciphersuites for TLS v1.3 */
|
||||
} else {
|
||||
if (SSL_CTX_set_ciphersuites(ctx, LOGSRVD_DEFAULT_CIPHER_LST13) <= 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to load default TLS v1.3 ciphersuite list: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
debug_return_bool(false);
|
||||
} else {
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||
"TLS v1.3 ciphersuite list is set to default (%s)",
|
||||
LOGSRVD_DEFAULT_CIPHER_LST13);
|
||||
}
|
||||
}
|
||||
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls series of openssl initialization functions in order to
|
||||
* be able to establish configured network connections over TLS
|
||||
*/
|
||||
static SSL_CTX *
|
||||
init_tls_server_context(void)
|
||||
{
|
||||
const SSL_METHOD *method;
|
||||
SSL_CTX *ctx = NULL;
|
||||
const struct logsrvd_tls_config *tls_config = logsrvd_get_tls_config();
|
||||
|
||||
debug_decl(init_tls_server_context, SUDO_DEBUG_UTIL)
|
||||
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
|
||||
if ((method = TLS_server_method()) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"creation of SSL_METHOD failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
if ((ctx = SSL_CTX_new(method)) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"creation of new SSL_CTX object failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* verify server certification against the CA bundle file */
|
||||
if (!verify_server_cert(ctx, tls_config)) {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* if peer authentication is enabled, verify client cert during TLS handshake */
|
||||
if (tls_config->check_peer) {
|
||||
X509 *cacert = load_cert(tls_config->cacert_path);
|
||||
|
||||
/* server will send the name of the CA to the client during the handshake */
|
||||
if (SSL_CTX_add_client_CA(ctx, cacert) <= 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"calling SSL_CTX_add_client_CA() failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
|
||||
/* sets the location of the CA bundle file for verification purposes */
|
||||
if (SSL_CTX_load_verify_locations(ctx, tls_config->cacert_path, NULL) <= 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"calling SSL_CTX_load_verify_locations() failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
|
||||
/* server will send a client certificate request to the peer during the handshake */
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
|
||||
}
|
||||
|
||||
if (!SSL_CTX_use_PrivateKey_file(ctx, tls_config->pkey_path, SSL_FILETYPE_PEM)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to load key file: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
if (!SSL_CTX_check_private_key(ctx)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to verify key file: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* initialize TLSv1.2 and TLSv1.3 ciphersuites */
|
||||
if (!init_tls_ciphersuites(ctx, tls_config)) {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* try to load and set diffie-hellman parameters */
|
||||
FILE *dhparam_file = fopen(tls_config->dhparams_path, "r");
|
||||
if (dhparam_file != NULL) {
|
||||
DH* dhparams;
|
||||
if ((dhparams = PEM_read_DHparams(dhparam_file, NULL, NULL, NULL)) != NULL) {
|
||||
if (!SSL_CTX_set_tmp_dh(ctx, dhparams)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to set dh parameters: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
} else {
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
|
||||
"diffie-hellman parameters are loaded");
|
||||
}
|
||||
} else {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"dhparam file can't be loaded: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
fclose(dhparam_file);
|
||||
} else {
|
||||
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
|
||||
"dhparam file not found, will use default parameters");
|
||||
}
|
||||
|
||||
/* audit server supports TLS ver1.2 or higher */
|
||||
if (!SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to restrict min. protocol version: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
goto good;
|
||||
|
||||
bad:
|
||||
if (ctx) {
|
||||
SSL_CTX_free(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
|
||||
good:
|
||||
debug_return_ptr(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate a new connection closure.
|
||||
*/
|
||||
@@ -796,6 +1137,33 @@ connection_closure_alloc(int sock)
|
||||
if ((closure = calloc(1, sizeof(*closure))) == NULL)
|
||||
debug_return_ptr(NULL);
|
||||
|
||||
TAILQ_INSERT_TAIL(&connections, closure, entries);
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
if (logsrvd_conf_get_tls_opt() == true) {
|
||||
if ((closure->ssl = SSL_new(logsrvd_get_tls_runtime()->ssl_ctx)) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to create new ssl object: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (SSL_set_fd(closure->ssl, sock) != 1) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to set fd for TLS: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (SSL_accept(closure->ssl) != 1 ) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"TLS handshake was unsuccessful: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
closure->iolog_dir_fd = -1;
|
||||
closure->sock = sock;
|
||||
|
||||
@@ -819,7 +1187,6 @@ connection_closure_alloc(int sock)
|
||||
if (closure->write_ev == NULL)
|
||||
goto bad;
|
||||
|
||||
TAILQ_INSERT_TAIL(&connections, closure, entries);
|
||||
debug_return_ptr(closure);
|
||||
bad:
|
||||
connection_closure_free(closure);
|
||||
@@ -859,6 +1226,7 @@ static int
|
||||
create_listener(struct listen_address *addr)
|
||||
{
|
||||
int flags, i, sock;
|
||||
struct timeval timeout;
|
||||
debug_decl(create_listener, SUDO_DEBUG_UTIL)
|
||||
|
||||
if ((sock = socket(addr->sa_un.sa.sa_family, SOCK_STREAM, 0)) == -1) {
|
||||
@@ -868,6 +1236,12 @@ create_listener(struct listen_address *addr)
|
||||
i = 1;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) == -1)
|
||||
sudo_warn("SO_REUSEADDR");
|
||||
timeout.tv_sec = logsrvd_conf_get_sock_timeout();
|
||||
timeout.tv_usec = 0;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1)
|
||||
sudo_warn("SO_RCVTIMEO");
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) == -1)
|
||||
sudo_warn("SO_SNDTIMEO");
|
||||
if (bind(sock, &addr->sa_un.sa, addr->sa_len) == -1) {
|
||||
sudo_warn("bind");
|
||||
goto bad;
|
||||
@@ -923,12 +1297,13 @@ register_listener(struct listen_address *addr, struct sudo_event_base *base)
|
||||
debug_decl(register_listener, SUDO_DEBUG_UTIL)
|
||||
|
||||
sock = create_listener(addr);
|
||||
|
||||
if (sock != -1) {
|
||||
ev = sudo_ev_alloc(sock, SUDO_EV_READ|SUDO_EV_PERSIST, listener_cb, base);
|
||||
if (ev == NULL)
|
||||
sudo_fatal(NULL);
|
||||
if (sudo_ev_add(base, ev, NULL, false) == -1)
|
||||
sudo_fatal(U_("unable to add event to queue"));
|
||||
ev = sudo_ev_alloc(sock, SUDO_EV_READ|SUDO_EV_PERSIST, listener_cb, base);
|
||||
if (ev == NULL)
|
||||
sudo_fatal(NULL);
|
||||
if (sudo_ev_add(base, ev, NULL, false) == -1)
|
||||
sudo_fatal(U_("unable to add event to queue"));
|
||||
}
|
||||
|
||||
debug_return;
|
||||
@@ -938,7 +1313,7 @@ static void
|
||||
register_signal(int signo, struct sudo_event_base *base)
|
||||
{
|
||||
struct sudo_event *ev;
|
||||
debug_decl(register_listener, SUDO_DEBUG_UTIL)
|
||||
debug_decl(register_signal, SUDO_DEBUG_UTIL)
|
||||
|
||||
ev = sudo_ev_alloc(signo, SUDO_EV_SIGNAL, signal_cb, base);
|
||||
if (ev == NULL)
|
||||
@@ -1104,6 +1479,14 @@ main(int argc, char *argv[])
|
||||
TAILQ_FOREACH(addr, logsrvd_conf_listen_address(), entries)
|
||||
register_listener(addr, evbase);
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
if (logsrvd_conf_get_tls_opt() == true) {
|
||||
struct logsrvd_tls_runtime *tls_runtime = logsrvd_get_tls_runtime();
|
||||
if ((tls_runtime->ssl_ctx = init_tls_server_context()) == NULL)
|
||||
sudo_fatal(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
register_signal(SIGHUP, evbase);
|
||||
register_signal(SIGINT, evbase);
|
||||
register_signal(SIGTERM, evbase);
|
||||
|
@@ -21,11 +21,20 @@
|
||||
# error protobuf-c version 1.30 or higher required
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
# include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#include "logsrv_util.h"
|
||||
|
||||
/* Default listen address (port 30344 on all interfaces). */
|
||||
#define DEFAULT_LISTEN_ADDR "*:" DEFAULT_PORT_STR
|
||||
|
||||
/* Default timeout value for server socket */
|
||||
#define DEFAULT_SOCKET_TIMEOUT_SEC 30
|
||||
|
||||
/* How often to send an ACK to the client (commit point) in seconds */
|
||||
#define ACK_FREQUENCY 10
|
||||
|
||||
@@ -81,6 +90,9 @@ struct connection_closure {
|
||||
struct sudo_event *commit_ev;
|
||||
struct sudo_event *read_ev;
|
||||
struct sudo_event *write_ev;
|
||||
#if defined(HAVE_OPENSSL)
|
||||
SSL *ssl;
|
||||
#endif
|
||||
const char *errstr;
|
||||
struct iolog_file iolog_files[IOFD_MAX];
|
||||
int iolog_dir_fd;
|
||||
@@ -106,6 +118,23 @@ struct listen_address {
|
||||
};
|
||||
TAILQ_HEAD(listen_address_list, listen_address);
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
/* parameters to configure tls */
|
||||
struct logsrvd_tls_config {
|
||||
char *pkey_path;
|
||||
char *cert_path;
|
||||
char *cacert_path;
|
||||
char *dhparams_path;
|
||||
char *ciphers_v12;
|
||||
char *ciphers_v13;
|
||||
bool check_peer;
|
||||
};
|
||||
|
||||
struct logsrvd_tls_runtime {
|
||||
SSL_CTX *ssl_ctx;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Supported eventlog types */
|
||||
enum logsrvd_eventlog_type {
|
||||
EVLOG_NONE,
|
||||
@@ -138,6 +167,12 @@ bool logsrvd_conf_read(const char *path);
|
||||
const char *logsrvd_conf_iolog_dir(void);
|
||||
const char *logsrvd_conf_iolog_file(void);
|
||||
struct listen_address_list *logsrvd_conf_listen_address(void);
|
||||
int logsrvd_conf_get_sock_timeout(void);
|
||||
#if defined(HAVE_OPENSSL)
|
||||
bool logsrvd_conf_get_tls_opt(void);
|
||||
const struct logsrvd_tls_config *logsrvd_get_tls_config(void);
|
||||
struct logsrvd_tls_runtime *logsrvd_get_tls_runtime(void);
|
||||
#endif
|
||||
enum logsrvd_eventlog_type logsrvd_conf_eventlog_type(void);
|
||||
enum logsrvd_eventlog_format logsrvd_conf_eventlog_format(void);
|
||||
unsigned int logsrvd_conf_syslog_maxlen(void);
|
||||
|
@@ -67,7 +67,13 @@ struct logsrvd_config_section {
|
||||
|
||||
static struct logsrvd_config {
|
||||
struct logsrvd_config_server {
|
||||
struct listen_address_list addresses;
|
||||
struct listen_address_list addresses;
|
||||
int timeout;
|
||||
#if defined(HAVE_OPENSSL)
|
||||
bool tls;
|
||||
struct logsrvd_tls_config tls_config;
|
||||
struct logsrvd_tls_runtime tls_runtime;
|
||||
#endif
|
||||
} server;
|
||||
struct logsrvd_config_iolog {
|
||||
bool compress;
|
||||
@@ -123,6 +129,32 @@ logsrvd_conf_listen_address(void)
|
||||
return &logsrvd_config->server.addresses;
|
||||
}
|
||||
|
||||
int
|
||||
logsrvd_conf_get_sock_timeout(void)
|
||||
{
|
||||
return logsrvd_config->server.timeout;
|
||||
}
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
bool
|
||||
logsrvd_conf_get_tls_opt(void)
|
||||
{
|
||||
return logsrvd_config->server.tls;
|
||||
}
|
||||
|
||||
const struct logsrvd_tls_config *
|
||||
logsrvd_get_tls_config(void)
|
||||
{
|
||||
return &logsrvd_config->server.tls_config;
|
||||
}
|
||||
|
||||
struct logsrvd_tls_runtime *
|
||||
logsrvd_get_tls_runtime(void)
|
||||
{
|
||||
return &logsrvd_config->server.tls_runtime;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* eventlog getters */
|
||||
enum logsrvd_eventlog_type
|
||||
logsrvd_conf_eventlog_type(void)
|
||||
@@ -358,6 +390,128 @@ done:
|
||||
debug_return_bool(ret);
|
||||
}
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
static bool
|
||||
cb_tls_opt(struct logsrvd_config *config, const char *str)
|
||||
{
|
||||
int val;
|
||||
debug_decl(cb_tls_opt, SUDO_DEBUG_UTIL)
|
||||
|
||||
if ((val = sudo_strtobool(str)) == -1)
|
||||
debug_return_bool(false);
|
||||
|
||||
config->server.tls = val;
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
static bool
|
||||
cb_timeout(struct logsrvd_config *config, const char *str)
|
||||
{
|
||||
int timeout;
|
||||
const char* errstr;
|
||||
debug_decl(cb_timeout, SUDO_DEBUG_UTIL)
|
||||
|
||||
timeout = sudo_strtonum(str, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
debug_return_bool(false);
|
||||
|
||||
config->server.timeout = timeout;
|
||||
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
static bool
|
||||
cb_tls_key(struct logsrvd_config *config, const char *path)
|
||||
{
|
||||
debug_decl(cb_tls_key, SUDO_DEBUG_UTIL)
|
||||
|
||||
free(config->server.tls_config.pkey_path);
|
||||
if ((config->server.tls_config.pkey_path = strdup(path)) == NULL) {
|
||||
sudo_warn(NULL);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
static bool
|
||||
cb_tls_cacert(struct logsrvd_config *config, const char *path)
|
||||
{
|
||||
debug_decl(cb_tls_cacert, SUDO_DEBUG_UTIL)
|
||||
|
||||
free(config->server.tls_config.cacert_path);
|
||||
if ((config->server.tls_config.cacert_path = strdup(path)) == NULL) {
|
||||
sudo_warn(NULL);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
static bool
|
||||
cb_tls_cert(struct logsrvd_config *config, const char *path)
|
||||
{
|
||||
debug_decl(cb_tls_cert, SUDO_DEBUG_UTIL)
|
||||
|
||||
free(config->server.tls_config.cert_path);
|
||||
if ((config->server.tls_config.cert_path = strdup(path)) == NULL) {
|
||||
sudo_warn(NULL);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
static bool
|
||||
cb_tls_dhparam(struct logsrvd_config *config, const char *path)
|
||||
{
|
||||
debug_decl(cb_tls_dhparam, SUDO_DEBUG_UTIL)
|
||||
|
||||
free(config->server.tls_config.dhparams_path);
|
||||
if ((config->server.tls_config.dhparams_path = strdup(path)) == NULL) {
|
||||
sudo_warn(NULL);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
static bool
|
||||
cb_tls_ciphers12(struct logsrvd_config *config, const char *str)
|
||||
{
|
||||
debug_decl(cb_tls_ciphers12, SUDO_DEBUG_UTIL)
|
||||
|
||||
free(config->server.tls_config.ciphers_v12);
|
||||
if ((config->server.tls_config.ciphers_v12 = strdup(str)) == NULL) {
|
||||
sudo_warn(NULL);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
static bool
|
||||
cb_tls_ciphers13(struct logsrvd_config *config, const char *str)
|
||||
{
|
||||
debug_decl(cb_tls_ciphers13, SUDO_DEBUG_UTIL)
|
||||
|
||||
free(config->server.tls_config.ciphers_v13);
|
||||
if ((config->server.tls_config.ciphers_v13 = strdup(str)) == NULL) {
|
||||
sudo_warn(NULL);
|
||||
debug_return_bool(false);
|
||||
}
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
static bool
|
||||
cb_tls_checkpeer(struct logsrvd_config *config, const char *str)
|
||||
{
|
||||
int val;
|
||||
debug_decl(cb_tls_checkpeer, SUDO_DEBUG_UTIL)
|
||||
|
||||
if ((val = sudo_strtobool(str)) == -1)
|
||||
debug_return_bool(false);
|
||||
|
||||
config->server.tls_config.check_peer = val;
|
||||
debug_return_bool(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* eventlog callbacks */
|
||||
static bool
|
||||
cb_eventlog_type(struct logsrvd_config *config, const char *str)
|
||||
@@ -513,6 +667,17 @@ cb_logfile_time_format(struct logsrvd_config *config, const char *str)
|
||||
|
||||
static struct logsrvd_config_entry server_conf_entries[] = {
|
||||
{ "listen_address", cb_listen_address },
|
||||
{ "timeout", cb_timeout },
|
||||
#if defined(HAVE_OPENSSL)
|
||||
{ "tls", cb_tls_opt },
|
||||
{ "tls_key", cb_tls_key },
|
||||
{ "tls_cacert", cb_tls_cacert },
|
||||
{ "tls_cert", cb_tls_cert },
|
||||
{ "tls_dhparams", cb_tls_dhparam },
|
||||
{ "tls_ciphers_v12", cb_tls_ciphers12 },
|
||||
{ "tls_ciphers_v13", cb_tls_ciphers13 },
|
||||
{ "tls_checkpeer", cb_tls_checkpeer },
|
||||
#endif
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -682,6 +847,7 @@ logsrvd_conf_alloc(void)
|
||||
|
||||
/* Server defaults */
|
||||
TAILQ_INIT(&config->server.addresses);
|
||||
config->server.timeout = DEFAULT_SOCKET_TIMEOUT_SEC;
|
||||
|
||||
/* I/O log defaults */
|
||||
config->iolog.compress = false;
|
||||
|
@@ -53,6 +53,11 @@
|
||||
#include "sudo_iolog.h"
|
||||
#include "sendlog.h"
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
# include "compat/getaddrinfo.h"
|
||||
#endif
|
||||
@@ -65,10 +70,20 @@
|
||||
static struct iolog_file iolog_files[IOFD_MAX];
|
||||
static char *iolog_dir;
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
static bool tls = false;
|
||||
static SSL_CTX *ssl_ctx = NULL;
|
||||
static SSL *ssl = NULL;
|
||||
#endif
|
||||
|
||||
static void
|
||||
usage(bool fatal)
|
||||
{
|
||||
#if defined(HAVE_OPENSSL)
|
||||
fprintf(stderr, "usage: %s [-h host] [-i iolog-id] [-p port] [-t -b ca_bundle] [-c cert_file [-k key_file]] "
|
||||
#else
|
||||
fprintf(stderr, "usage: %s [-h host] [-i iolog-id] [-p port] "
|
||||
#endif
|
||||
"[-r restart-point] /path/to/iolog\n", getprogname());
|
||||
exit(1);
|
||||
}
|
||||
@@ -85,10 +100,78 @@ help(void)
|
||||
" -i, --iolog_id remote ID of I/O log to be resumed\n"
|
||||
" -p, --port port to use when connecting to host\n"
|
||||
" -r, --restart restart previous I/O log transfer\n"
|
||||
#if defined(HAVE_OPENSSL)
|
||||
" -t, --tls set the communication over TLS with the audit server\n"
|
||||
" -b, --ca-bundle certificate bundle file to verify server's cert against\n"
|
||||
" -c, --cert certificate file for TLS handshake\n"
|
||||
" -k, --key private key file\n"
|
||||
#endif
|
||||
" -V, --version display version information and exit\n"));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
static SSL_CTX *
|
||||
init_tls_client_context(const char *ca_bundle_file, const char *cert_file, const char *key_file)
|
||||
{
|
||||
const SSL_METHOD *method;
|
||||
SSL_CTX *ctx;
|
||||
|
||||
debug_decl(init_tls_client_context, SUDO_DEBUG_UTIL)
|
||||
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
|
||||
if ((method = TLS_client_method()) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"creation of SSL_METHOD failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
if ((ctx = SSL_CTX_new(method)) == NULL) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"creation of new SSL_CTX object failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (cert_file) {
|
||||
if (!SSL_CTX_use_certificate_chain_file(ctx, cert_file)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to load cert to the ssl context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
if (!SSL_CTX_use_PrivateKey_file(ctx, key_file, X509_FILETYPE_PEM)) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"unable to load key to the ssl context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
/* sets the location of the CA bundle file for verification purposes */
|
||||
if (SSL_CTX_load_verify_locations(ctx, ca_bundle_file, NULL) <= 0) {
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"calling SSL_CTX_load_verify_locations() failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
|
||||
/* set verify server cert during the handshake */
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
|
||||
|
||||
goto exit;
|
||||
|
||||
bad:
|
||||
if (ctx)
|
||||
SSL_CTX_free(ctx);
|
||||
|
||||
exit:
|
||||
return ctx;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Connect to specified host:port
|
||||
* If host has multiple addresses, the first one that connects is used.
|
||||
@@ -129,16 +212,6 @@ connect_server(const char *host, const char *port)
|
||||
}
|
||||
break; /* success */
|
||||
}
|
||||
if (sock != -1) {
|
||||
int flags = fcntl(sock, F_GETFL, 0);
|
||||
if (flags == -1 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
cause = "fcntl(O_NONBLOCK)";
|
||||
save_errno = errno;
|
||||
close(sock);
|
||||
errno = save_errno;
|
||||
sock = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (sock == -1)
|
||||
sudo_warn("%s", cause);
|
||||
@@ -877,7 +950,15 @@ server_msg_cb(int fd, int what, void *v)
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: reading ServerMessage", __func__);
|
||||
|
||||
/* XXX - make common */
|
||||
#if defined(HAVE_OPENSSL)
|
||||
if (tls) {
|
||||
nread = SSL_read(ssl, buf->data + buf->len, buf->size - buf->len);
|
||||
} else {
|
||||
nread = recv(fd, buf->data + buf->len, buf->size - buf->len, 0);
|
||||
}
|
||||
#else
|
||||
nread = recv(fd, buf->data + buf->len, buf->size - buf->len, 0);
|
||||
#endif
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received %zd bytes from server",
|
||||
__func__, nread);
|
||||
switch (nread) {
|
||||
@@ -942,7 +1023,15 @@ client_msg_cb(int fd, int what, void *v)
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||
"%s: sending %u bytes to server", __func__, buf->len - buf->off);
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
if (tls) {
|
||||
nwritten = SSL_write(ssl, buf->data + buf->off, buf->len - buf->off);
|
||||
} else {
|
||||
nwritten = send(fd, buf->data + buf->off, buf->len - buf->off, 0);
|
||||
}
|
||||
#else
|
||||
nwritten = send(fd, buf->data + buf->off, buf->len - buf->off, 0);
|
||||
#endif
|
||||
if (nwritten == -1) {
|
||||
sudo_warn("send");
|
||||
goto bad;
|
||||
@@ -1049,13 +1138,23 @@ parse_timespec(struct timespec *ts, const char *strval)
|
||||
debug_return_bool(true);
|
||||
}
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
static const char short_opts[] = "h:i:p:r:tb:c:k:V";
|
||||
#else
|
||||
static const char short_opts[] = "h:i:p:r:V";
|
||||
#endif
|
||||
static struct option long_opts[] = {
|
||||
{ "help", no_argument, NULL, 1 },
|
||||
{ "host", required_argument, NULL, 'h' },
|
||||
{ "iolog-id", required_argument, NULL, 'i' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "restart", required_argument, NULL, 'r' },
|
||||
#if defined(HAVE_OPENSSL)
|
||||
{ "tls", no_argument, NULL, 't' },
|
||||
{ "ca-bundle", required_argument, NULL, 'b' },
|
||||
{ "cert", required_argument, NULL, 'c' },
|
||||
{ "key", required_argument, NULL, 'k' },
|
||||
#endif
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, no_argument, NULL, 0 },
|
||||
};
|
||||
@@ -1068,6 +1167,11 @@ main(int argc, char *argv[])
|
||||
struct client_closure closure;
|
||||
struct sudo_event_base *evbase;
|
||||
struct iolog_info *log_info;
|
||||
#if defined(HAVE_OPENSSL)
|
||||
const char *ca_bundle = NULL;
|
||||
const char *cert = NULL;
|
||||
const char *key = NULL;
|
||||
#endif
|
||||
const char *host = "localhost";
|
||||
const char *port = DEFAULT_PORT_STR;
|
||||
struct timespec restart = { 0, 0 };
|
||||
@@ -1120,6 +1224,20 @@ main(int argc, char *argv[])
|
||||
case 1:
|
||||
help();
|
||||
break;
|
||||
#if defined(HAVE_OPENSSL)
|
||||
case 'b':
|
||||
ca_bundle = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
cert = optarg;
|
||||
break;
|
||||
case 'k':
|
||||
key = optarg;
|
||||
break;
|
||||
case 't':
|
||||
tls = true;
|
||||
break;
|
||||
#endif
|
||||
case 'V':
|
||||
(void)printf(_("%s version %s\n"), getprogname(),
|
||||
PACKAGE_VERSION);
|
||||
@@ -1131,6 +1249,21 @@ main(int argc, char *argv[])
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
/* if the protocol is tls, the CA bundle file is a required argument
|
||||
* to be able to verify the server's certificate
|
||||
*/
|
||||
if (tls && !ca_bundle) {
|
||||
sudo_warnx("%s", U_("with the tls protocol, the CA bundle file must be specified"));
|
||||
usage(true);
|
||||
}
|
||||
|
||||
/* if no key file is given explicitly, try to load the key from the cert */
|
||||
if (cert && !key) {
|
||||
key = cert;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sudo_timespecisset(&restart) != (iolog_id != NULL)) {
|
||||
sudo_warnx("%s", U_("both restart point and iolog ID must be specified"));
|
||||
usage(true);
|
||||
@@ -1167,7 +1300,39 @@ main(int argc, char *argv[])
|
||||
sock = connect_server(host, port);
|
||||
if (sock == -1)
|
||||
goto bad;
|
||||
printf("connected to %s:%s\n", host, port);
|
||||
#if defined(HAVE_OPENSSL)
|
||||
if (tls) {
|
||||
int ret;
|
||||
if ((ssl_ctx = init_tls_client_context(ca_bundle, cert, key)) == NULL) {
|
||||
sudo_warnx(U_("Unable to initialize ssl context: %s\n"),
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
if ((ssl = SSL_new(ssl_ctx)) == NULL) {
|
||||
sudo_warnx(U_("Unable to allocate ssl object: %s\n"),
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
if (SSL_set_fd(ssl, sock) <= 0) {
|
||||
sudo_warnx(U_("Unable to attach socket to the ssl object: %s\n"),
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
ret = SSL_ERROR_NONE;
|
||||
|
||||
if ((ret = SSL_connect(ssl)) != 1) {
|
||||
sudo_warnx(U_("SSL_connect failed: ret=%d ssl_error=%d, stack=%s\n"),
|
||||
ret,
|
||||
SSL_get_error(ssl, ret),
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
printf("Protocol version: %s\n", SSL_get_version(ssl));
|
||||
printf("Negotiated ciphersuite: %s\n", SSL_get_cipher(ssl));
|
||||
}
|
||||
#endif
|
||||
printf("Connected to %s:%s\n", host, port);
|
||||
|
||||
if ((evbase = sudo_ev_base_alloc()) == NULL)
|
||||
sudo_fatal(NULL);
|
||||
|
Reference in New Issue
Block a user