2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-22 01:49:11 +00:00

Use port 30343 for plaintext and port 30344 for TLS.

For TLS connections we now do the TLS handshake immediately before
the ServerHello message.  This lets the client recieve an alert
from the server is there is a handshake error after the TLS connect
has succeeded.  It also means that the contents of the ServerHello
are protected from a man-in-the-middle attack.
This commit is contained in:
Todd C. Miller 2020-05-04 11:28:38 -06:00
parent b5a317aeb9
commit 1659d96c55
10 changed files with 426 additions and 358 deletions

View File

@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.TH "SUDO_LOGSRV.PROTO" "@mansectform@" "April 20, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.TH "SUDO_LOGSRV.PROTO" "@mansectform@" "April 30, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh
.if n .ad l
.SH "NAME"
@ -438,9 +438,6 @@ message ServerHello {
string server_id = 1;
string redirect = 2;
repeated string servers = 3;
bool tls = 4;
bool tls_server_auth = 5;
bool tls_reqcert = 6;
}
.RE
.fi
@ -475,22 +472,6 @@ This can be used to implement log server redundancy and allows the
client to discover all other log servers simply by connecting to
one known server.
This member may be omitted when there is only a single log server.
.TP 8n
tls
If set to true, the connection between the client and the server
must be secured via Transport Layer Security (TLS) version 1.2 or
higher.
.TP 8n
tls_server_auth
If set to true, the client should validate the server's certificate
and only proceed if the certificate can be verified.
.TP 8n
tls_reqcert
If set to true, the client must present its own certificate to the server.
If the server is unable to verify the client's certificate, the TLS
handshake will fail.
This can be used by the server to only allow connections from authorized
clients.
.SS "TimeSpec commit_point"
A periodic time stamp sent by the server to indicate when I/O log
buffers have been committed to storage.
@ -529,7 +510,9 @@ message.
The expected protocol flow is as follows:
.TP 5n
1.\&
Client connect to server.
Client connects to the first available server.
If the client is configured to use TLS, a TLS handshake will be
attempted.
.TP 5n
2.\&
Server sends
@ -573,6 +556,14 @@ if one is pending.
.TP 5n
9.\&
Server closes the connection.
After receiving the final
\fIcommit_point\fR,
the client client shuts down its side of the TLS connection if TLS
is in use, and closes the connection.
.TP 5n
10.\&
Server shuts down its side of the TLS connection if TLS is in use,
and closes the connection.
.PP
At any point, the server may send an
\fIerror\fR

View File

@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd April 20, 2020
.Dd April 30, 2020
.Dt SUDO_LOGSRV.PROTO @mansectform@
.Os Sudo @PACKAGE_VERSION@
.Sh NAME
@ -404,9 +404,6 @@ message ServerHello {
string server_id = 1;
string redirect = 2;
repeated string servers = 3;
bool tls = 4;
bool tls_server_auth = 5;
bool tls_reqcert = 6;
}
.Ed
.Pp
@ -437,19 +434,6 @@ This can be used to implement log server redundancy and allows the
client to discover all other log servers simply by connecting to
one known server.
This member may be omitted when there is only a single log server.
.It tls
If set to true, the connection between the client and the server
must be secured via Transport Layer Security (TLS) version 1.2 or
higher.
.It tls_server_auth
If set to true, the client should validate the server's certificate
and only proceed if the certificate can be verified.
.It tls_reqcert
If set to true, the client must present its own certificate to the server.
If the server is unable to verify the client's certificate, the TLS
handshake will fail.
This can be used by the server to only allow connections from authorized
clients.
.El
.Ss TimeSpec commit_point
A periodic time stamp sent by the server to indicate when I/O log
@ -489,7 +473,9 @@ message.
The expected protocol flow is as follows:
.Bl -enum
.It
Client connect to server.
Client connects to the first available server.
If the client is configured to use TLS, a TLS handshake will be
attempted.
.It
Server sends
.Em ServerHello .
@ -525,6 +511,13 @@ Server sends the final
if one is pending.
.It
Server closes the connection.
After receiving the final
.Em commit_point ,
the client client shuts down its side of the TLS connection if TLS
is in use, and closes the connection.
.It
Server shuts down its side of the TLS connection if TLS is in use,
and closes the connection.
.El
.Pp
At any point, the server may send an

View File

@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.TH "SUDO_LOGSRVD.CONF" "@mansectform@" "March 28, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.TH "SUDO_LOGSRVD.CONF" "@mansectform@" "April 30, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh
.if n .ad l
.SH "NAME"
@ -84,9 +84,10 @@ The
section configures the address and port the server will listen on.
The following keys are recognized:
.TP 10n
listen_address = host[:port]
The host name or IP address and optional port to listen on.
If no port is specified, port 30344 will be used.
listen_address = host[:port][(tls)]
The host name or IP address, optional port to listen on and
an optional Transport Layer Security (TLS) flag in parentheses.
.sp
The host may be a host name, an IPv4 address, an IPv6 address
in square brackets or the wild card entry
\(oq*\(cq.
@ -96,14 +97,33 @@ will cause
\fBsudo_logsrvd\fR
to listen on all configured network interfaces.
.sp
If the tls flag is set,
\fBsudo_logsrvd\fR
will secure the connection with TLS version 1.2 or 1.3.
Versions of TLS prior to 1.2 are not supported.
See
sudo_logsrvd(8)
for details on generating TLS keys and certificates.
.sp
If a port is specified, it may either be a port number or a known
service name as defined by the system service name database.
The default value is
\fRlisten_address = *:30344\fR
which will listen on all configured network interfaces.
If no port is specified, port 30343 will be used for plaintext
connections and port 30344 will be used for TLS connections.
.sp
The default value is:
.nf
.RS 16n
listen_address = *:30343
listen_address = *:30344(tls)
.RE
.fi
.RS 10n
which will listen on all configured network interfaces for both
plaintext and TLS connections.
Multiple
\fIlisten_address\fR
lines may be specified to listen on more than one interface.
lines may be specified to listen on more than one port or interface.
.RE
.TP 10n
pid_file = path
The path to the file containing the process ID of the running
@ -130,17 +150,6 @@ will wait for the client to respond.
A value of 0 will disable the timeout.
The default value is 30.
.TP 10n
tls = boolean
If true,
\fBsudo_logsrvd\fR
will secure network connections with Transport Layer Security (TLS)
version 1.2 or 1.3.
Versions of TLS prior to 1.2 are not supported.
See
sudo_logsrvd(8)
for details on generating TLS keys and certificates.
The default value is false.
.TP 10n
tls_cacert = path
The path to a certificate authority bundle file, in PEM format,
to use instead of the system's default certificate authority database
@ -552,19 +561,23 @@ Sudo log server configuration file
#
[server]
# The host name or IP address and port to listen on. If no port is
# specified, port 30344 will be used.
# The host name or IP address and port to listen on with an optional TLS
# flag. If no port is specified, port 30343 will be used for plaintext
# connections and port 30344 will be used to TLS connections.
# The following forms are accepted:
# listen_address = hostname
# listen_address = hostname:port
# listen_address = IPv4_address
# listen_address = IPv4_address:port
# listen_address = [IPv6_address]
# listen_address = [IPv6_address]:port
# listen_address = hostname(tls)
# listen_address = hostname:port(tls)
# listen_address = IPv4_address(tls)
# listen_address = IPv4_address:port(tls)
# listen_address = [IPv6_address](tls)
# listen_address = [IPv6_address]:port(tls)
#
# The (tls) suffix should be omitted for plaintext connections.
#
# Multiple listen_address settings may be specified.
# The default is to listen on all addresses.
#listen_address = *:30344
#listen_address = *:30343
#listen_address = *:30344(tls)
# The file containing the ID of the running sudo_logsrvd process.
#pid_file = @rundir@/sudo_logsrvd.pid
@ -576,10 +589,6 @@ Sudo log server configuration file
# respond. A value of 0 will disable the timeout. The default value is 30.
#timeout = 30
# If set, secure connections with TLS 1.2 or 1.3.
# By default, server connections are not encrypted.
#tls = true
# If set, server certificate will be verified at server startup and
# also connecting clients will perform server authentication by
# verifying the server's certificate and identity.

View File

@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd March 28, 2020
.Dd April 30, 2020
.Dt SUDO_LOGSRVD.CONF @mansectform@
.Os Sudo @PACKAGE_VERSION@
.Sh NAME
@ -76,9 +76,10 @@ The
section configures the address and port the server will listen on.
The following keys are recognized:
.Bl -tag -width 8n
.It listen_address = host Ns Op : Ns port
The host name or IP address and optional port to listen on.
If no port is specified, port 30344 will be used.
.It listen_address = host Ns Oo : Ns port Oc Ns Op (tls)
The host name or IP address, optional port to listen on and
an optional Transport Layer Security (TLS) flag in parentheses.
.Pp
The host may be a host name, an IPv4 address, an IPv6 address
in square brackets or the wild card entry
.Ql * .
@ -88,14 +89,29 @@ will cause
.Nm sudo_logsrvd
to listen on all configured network interfaces.
.Pp
If the tls flag is set,
.Nm sudo_logsrvd
will secure the connection with TLS version 1.2 or 1.3.
Versions of TLS prior to 1.2 are not supported.
See
.Xr sudo_logsrvd @mansectsu@
for details on generating TLS keys and certificates.
.Pp
If a port is specified, it may either be a port number or a known
service name as defined by the system service name database.
The default value is
.Li listen_address = *:30344
which will listen on all configured network interfaces.
If no port is specified, port 30343 will be used for plaintext
connections and port 30344 will be used for TLS connections.
.Pp
The default value is:
.Bd -literal -compact -offset indent
listen_address = *:30343
listen_address = *:30344(tls)
.Ed
which will listen on all configured network interfaces for both
plaintext and TLS connections.
Multiple
.Em listen_address
lines may be specified to listen on more than one interface.
lines may be specified to listen on more than one port or interface.
.It pid_file = path
The path to the file containing the process ID of the running
.Nm sudo_logsrvd .
@ -118,16 +134,6 @@ The amount of time, in seconds,
will wait for the client to respond.
A value of 0 will disable the timeout.
The default value is 30.
.It tls = boolean
If true,
.Nm sudo_logsrvd
will secure network connections with Transport Layer Security (TLS)
version 1.2 or 1.3.
Versions of TLS prior to 1.2 are not supported.
See
.Xr sudo_logsrvd @mansectsu@
for details on generating TLS keys and certificates.
The default value is false.
.It tls_cacert = path
The path to a certificate authority bundle file, in PEM format,
to use instead of the system's default certificate authority database
@ -500,19 +506,23 @@ Sudo log server configuration file
#
[server]
# The host name or IP address and port to listen on. If no port is
# specified, port 30344 will be used.
# The host name or IP address and port to listen on with an optional TLS
# flag. If no port is specified, port 30343 will be used for plaintext
# connections and port 30344 will be used to TLS connections.
# The following forms are accepted:
# listen_address = hostname
# listen_address = hostname:port
# listen_address = IPv4_address
# listen_address = IPv4_address:port
# listen_address = [IPv6_address]
# listen_address = [IPv6_address]:port
# listen_address = hostname(tls)
# listen_address = hostname:port(tls)
# listen_address = IPv4_address(tls)
# listen_address = IPv4_address:port(tls)
# listen_address = [IPv6_address](tls)
# listen_address = [IPv6_address]:port(tls)
#
# The (tls) suffix should be omitted for plaintext connections.
#
# Multiple listen_address settings may be specified.
# The default is to listen on all addresses.
#listen_address = *:30344
#listen_address = *:30343
#listen_address = *:30344(tls)
# The file containing the ID of the running sudo_logsrvd process.
#pid_file = @rundir@/sudo_logsrvd.pid
@ -524,10 +534,6 @@ Sudo log server configuration file
# respond. A value of 0 will disable the timeout. The default value is 30.
#timeout = 30
# If set, secure connections with TLS 1.2 or 1.3.
# By default, server connections are not encrypted.
#tls = true
# If set, server certificate will be verified at server startup and
# also connecting clients will perform server authentication by
# verifying the server's certificate and identity.

View File

@ -3,19 +3,23 @@
#
[server]
# The host name or IP address and port to listen on. If no port is
# specified, port 30344 will be used.
# The host name or IP address and port to listen on with an optional TLS
# flag. If no port is specified, port 30343 will be used for plaintext
# connections and port 30344 will be used to TLS connections.
# The following forms are accepted:
# listen_address = hostname
# listen_address = hostname:port
# listen_address = IPv4_address
# listen_address = IPv4_address:port
# listen_address = [IPv6_address]
# listen_address = [IPv6_address]:port
# listen_address = hostname(tls)
# listen_address = hostname:port(tls)
# listen_address = IPv4_address(tls)
# listen_address = IPv4_address:port(tls)
# listen_address = [IPv6_address](tls)
# listen_address = [IPv6_address]:port(tls)
#
# The (tls) suffix should be omitted for plaintext connections.
#
# Multiple listen_address settings may be specified.
# The default is to listen on all addresses.
#listen_address = *:30344
#listen_address = *:30343
#listen_address = *:30344(tls)
# The file containing the ID of the running sudo_logsrvd process.
#pid_file = /var/run/sudo/sudo_logsrvd.pid
@ -27,10 +31,6 @@
# respond. A value of 0 will disable the timeout. The default value is 30.
#timeout = 30
# If set, secure connections with TLS 1.2 or 1.3.
# By default, server connections are not encrypted.
#tls = true
# If set, server certificate will be verified at server startup and
# also connecting clients will perform server authentication by
# verifying the server's certificate and identity.

View File

@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2019 Todd C. Miller <Todd.Miller@sudo.ws>
* Copyright (c) 2019-2020 Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -19,8 +19,9 @@
#ifndef SUDO_LOGSRV_UTIL_H
#define SUDO_LOGSRV_UTIL_H
/* Default port to listen on */
#define DEFAULT_PORT_STR "30344"
/* Default ports to listen on */
#define DEFAULT_PORT "30343"
#define DEFAULT_PORT_TLS "30344"
/* Maximum message size (2Mb) */
#define MESSAGE_SIZE_MAX (2 * 1024 * 1024)

View File

@ -102,13 +102,13 @@ connection_closure_free(struct connection_closure *closure)
bool shutting_down = closure->state == SHUTDOWN;
struct sudo_event_base *evbase = closure->evbase;
#if defined(HAVE_OPENSSL)
if (logsrvd_conf_get_tls_opt()) {
SSL_shutdown(closure->ssl);
SSL_free(closure->ssl);
}
#endif
TAILQ_REMOVE(&connections, closure, entries);
#if defined(HAVE_OPENSSL)
if (closure->tls) {
SSL_shutdown(closure->ssl);
SSL_free(closure->ssl);
}
#endif
close(closure->sock);
iolog_close_all(closure);
sudo_ev_free(closure->commit_ev);
@ -149,6 +149,7 @@ fmt_server_message(struct connection_buffer *buf, ServerMessage *msg)
"server message too large: %zu", len);
goto done;
}
/* Wire message size is used for length encoding, precedes message. */
msg_len = htonl((uint32_t)len);
len += sizeof(msg_len);
@ -164,6 +165,8 @@ fmt_server_message(struct connection_buffer *buf, ServerMessage *msg)
goto done;
}
}
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"size + server message %zu bytes", len);
memcpy(buf->data, &msg_len, sizeof(msg_len));
server_message__pack(msg, buf->data + sizeof(msg_len));
@ -175,7 +178,7 @@ done:
}
static bool
fmt_hello_message(struct connection_buffer *buf)
fmt_hello_message(struct connection_buffer *buf, bool tls)
{
ServerMessage msg = SERVER_MESSAGE__INIT;
ServerHello hello = SERVER_HELLO__INIT;
@ -184,14 +187,17 @@ fmt_hello_message(struct connection_buffer *buf)
/* TODO: implement redirect and servers array. */
hello.server_id = (char *)server_id;
#if defined(HAVE_OPENSSL)
hello.tls = logsrvd_conf_get_tls_opt();
hello.tls_server_auth = logsrvd_get_tls_config()->verify;
hello.tls_reqcert = logsrvd_get_tls_config()->check_peer;
#else
hello.tls = false;
hello.tls_server_auth = false;
hello.tls_reqcert = false;
if (tls) {
hello.tls = true;
hello.tls_server_auth = logsrvd_get_tls_config()->verify;
hello.tls_reqcert = logsrvd_get_tls_config()->check_peer;
} else
#endif
{
hello.tls = false;
hello.tls_server_auth = false;
hello.tls_reqcert = false;
}
msg.hello = &hello;
msg.type_case = SERVER_MESSAGE__TYPE_HELLO;
@ -601,8 +607,9 @@ shutdown_cb(int unused, int what, void *v)
#if defined(HAVE_OPENSSL)
/* deallocate server's SSL context object */
if (logsrvd_conf_get_tls_opt()) {
SSL_CTX_free(logsrvd_get_tls_runtime()->ssl_ctx);
struct logsrvd_tls_runtime *tls_runtime = logsrvd_get_tls_runtime();
if (tls_runtime != NULL) {
SSL_CTX_free(tls_runtime->ssl_ctx);
}
#endif
sudo_ev_loopbreak(base);
@ -682,9 +689,9 @@ server_msg_cb(int fd, int what, void *v)
__func__, buf->len - buf->off);
#if defined(HAVE_OPENSSL)
/* The initial ServerHello msg is not encrypted */
if ((closure->ssl) != NULL && (closure->state != INITIAL)) {
nwritten = SSL_write(closure->ssl, buf->data + buf->off, buf->len - buf->off);
if (closure->tls) {
nwritten = SSL_write(closure->ssl, buf->data + buf->off,
buf->len - buf->off);
if (nwritten <= 0) {
int err = SSL_get_error(closure->ssl, nwritten);
switch (err) {
@ -700,19 +707,23 @@ server_msg_cb(int fd, int what, void *v)
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
"SSL_write returns SSL_ERROR_WANT_WRITE");
debug_return;
case SSL_ERROR_SYSCALL:
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unexpected error during SSL_write(): %d (%s)",
err, strerror(errno));
goto finished;
default:
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unexpected error during SSL_write(). SSL error=%d (%s)",
"unexpected error during SSL_write(): %d (%s)",
err, ERR_error_string(ERR_get_error(), NULL));
goto finished;
goto finished;
}
}
} 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);
} else
#endif
{
nwritten = send(fd, buf->data + buf->off, buf->len - buf->off, 0);
}
if (nwritten == -1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
@ -765,7 +776,7 @@ client_msg_cb(int fd, int what, void *v)
}
#if defined(HAVE_OPENSSL)
if (closure->ssl != NULL) {
if (closure->tls) {
nread = SSL_read(closure->ssl, buf->data + buf->len, buf->size);
if (nread <= 0) {
int err = SSL_get_error(closure->ssl, nread);
@ -797,19 +808,23 @@ client_msg_cb(int fd, int what, void *v)
/* Redirect write event to finish SSL_read() */
closure->read_instead_of_write = true;
debug_return;
case SSL_ERROR_SYSCALL:
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unexpected error during SSL_read(): %d (%s)",
err, strerror(errno));
goto finished;
default:
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unexpected error during SSL_read(). SSL error=%d (%s)",
"unexpected error during SSL_read(): %d (%s)",
err, ERR_error_string(ERR_get_error(), NULL));
goto finished;
}
}
} else {
} else
#endif
{
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);
@ -920,6 +935,30 @@ bad:
debug_return;
}
/*
* Begin the sudo logserver protocol.
* When we enter the event loop the ServerHello message will be written
* and any pending ClientMessage will be read.
*/
static bool
start_protocol(struct connection_closure *closure)
{
const struct timespec *timeout = logsrvd_conf_get_sock_timeout();
debug_decl(start_protocol, SUDO_DEBUG_UTIL);
if (!fmt_hello_message(&closure->write_buf, closure->tls))
debug_return_bool(false);
if (sudo_ev_add(closure->evbase, closure->write_ev, timeout, false) == -1)
debug_return_bool(false);
/* No read timeout, client messages may happen at arbitrary times. */
if (sudo_ev_add(closure->evbase, closure->read_ev, NULL, false) == -1)
debug_return_bool(false);
debug_return_bool(true);
}
#if defined(HAVE_OPENSSL)
static int
verify_peer_identity(int preverify_ok, X509_STORE_CTX *ctx)
@ -1238,7 +1277,6 @@ static void
tls_handshake_cb(int fd, int what, void *v)
{
struct connection_closure *closure = v;
debug_decl(tls_handshake_cb, SUDO_DEBUG_UTIL);
if (what == SUDO_EV_TIMEOUT) {
@ -1293,6 +1331,11 @@ tls_handshake_cb(int fd, int what, void *v)
goto bad;
}
debug_return;
case SSL_ERROR_SYSCALL:
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unexpected error during TLS handshake: %d (%s)",
err, strerror(errno));
goto bad;
default:
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unexpected error during TLS handshake: %d (%s)",
@ -1300,16 +1343,15 @@ tls_handshake_cb(int fd, int what, void *v)
goto bad;
}
/* Enable reader for ClientMessage */
if (sudo_ev_add(closure->evbase, closure->read_ev, NULL, false) == -1) {
sudo_warn(U_("unable to add event to queue"));
}
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"TLS version: %s, negotiated cipher suite: %s",
SSL_get_version(closure->ssl),
SSL_get_cipher(closure->ssl));
/* Start the actual protocol now that the TLS handshake is complete. */
if (!start_protocol(closure))
goto bad;
debug_return;
bad:
connection_closure_free(closure);
@ -1321,7 +1363,7 @@ bad:
* Allocate a new connection closure.
*/
static struct connection_closure *
connection_closure_alloc(int sock, struct sudo_event_base *base)
connection_closure_alloc(int sock, bool tls, struct sudo_event_base *base)
{
struct connection_closure *closure;
debug_decl(connection_closure_alloc, SUDO_DEBUG_UTIL);
@ -1331,6 +1373,7 @@ connection_closure_alloc(int sock, struct sudo_event_base *base)
closure->iolog_dir_fd = -1;
closure->sock = sock;
closure->tls = tls;
closure->evbase = base;
TAILQ_INSERT_TAIL(&connections, closure, entries);
@ -1356,10 +1399,12 @@ connection_closure_alloc(int sock, struct sudo_event_base *base)
goto bad;
#if defined(HAVE_OPENSSL)
closure->ssl_accept_ev = sudo_ev_alloc(sock, SUDO_EV_READ,
tls_handshake_cb, closure);
if (closure->ssl_accept_ev == NULL)
goto bad;
if (tls) {
closure->ssl_accept_ev = sudo_ev_alloc(sock, SUDO_EV_READ,
tls_handshake_cb, closure);
if (closure->ssl_accept_ev == NULL)
goto bad;
}
#endif
debug_return_ptr(closure);
@ -1370,32 +1415,40 @@ bad:
/*
* New connection.
* Allocate a connection closure and send a server hello message.
* Allocate a connection closure and optionally perform TLS handshake.
*/
static bool
new_connection(int sock, const struct sockaddr *sa, struct sudo_event_base *base)
new_connection(int sock, bool tls, const struct sockaddr *sa,
struct sudo_event_base *evbase)
{
struct connection_closure *closure;
debug_decl(new_connection, SUDO_DEBUG_UTIL);
if ((closure = connection_closure_alloc(sock, base)) == NULL)
if ((closure = connection_closure_alloc(sock, tls, evbase)) == NULL)
goto bad;
/* Format and write ServerHello message. */
if (!fmt_hello_message(&closure->write_buf))
goto bad;
if (sudo_ev_add(base, closure->write_ev,
logsrvd_conf_get_sock_timeout(), false) == -1)
/* store the peer's IP address in the closure object */
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
inet_ntop(AF_INET, &sin->sin_addr, closure->ipaddr,
sizeof(closure->ipaddr));
#if defined(HAVE_STRUCT_IN6_ADDR)
} else if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
inet_ntop(AF_INET6, &sin6->sin6_addr, closure->ipaddr,
sizeof(closure->ipaddr));
#endif /* HAVE_STRUCT_IN6_ADDR */
} else {
sudo_fatal(U_("unable to get remote IP addr"));
goto bad;
}
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"connection from %s", closure->ipaddr);
#if defined(HAVE_OPENSSL)
/* if TLS is ON, first we need to do handshake with client,
* otherwise just enable the reader
*/
if (logsrvd_conf_get_tls_opt()) {
/* create the SSL object for the closure and attach it to the socket */
/* If TLS is enabled, perform the TLS handshake first. */
if (tls) {
/* Create the SSL object for the closure and attach it to the socket */
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",
@ -1419,39 +1472,18 @@ new_connection(int sock, const struct sockaddr *sa, struct sudo_event_base *base
goto bad;
}
/* enable SSL_accept to begin handshake with client */
if (sudo_ev_add(base, closure->ssl_accept_ev,
/* Enable SSL_accept to begin handshake with client. */
if (sudo_ev_add(evbase, closure->ssl_accept_ev,
logsrvd_conf_get_sock_timeout(), false) == -1) {
sudo_fatal(U_("unable to add event to queue"));
goto bad;
}
} else {
/* Enable reader for ClientMessage*/
if (sudo_ev_add(base, closure->read_ev, NULL, false) == -1)
goto bad;
}
#else
/* Enable reader for ClientMessage*/
if (sudo_ev_add(base, closure->read_ev, NULL, false) == -1)
goto bad;
#endif
/* store the peer's IP address in the closure object*/
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
inet_ntop(AF_INET, &sin->sin_addr, closure->ipaddr,
sizeof(closure->ipaddr));
}
#if defined(HAVE_STRUCT_IN6_ADDR)
else if (sa->sa_family == AF_INET6){
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
inet_ntop(AF_INET6, &sin6->sin6_addr, closure->ipaddr,
sizeof(closure->ipaddr));
}
#endif /* HAVE_STRUCT_IN6_ADDR */
else {
sudo_fatal(U_("unable to get remote IP addr"));
goto bad;
/* If no TLS handshake, start the protocol immediately. */
if (!tls) {
if (!start_protocol(closure))
goto bad;
}
debug_return_bool(true);
@ -1464,6 +1496,7 @@ static int
create_listener(struct listen_address *addr)
{
int flags, on, sock;
const char *family = "inet4";
debug_decl(create_listener, SUDO_DEBUG_UTIL);
if ((sock = socket(addr->sa_un.sa.sa_family, SOCK_STREAM, 0)) == -1) {
@ -1471,17 +1504,21 @@ create_listener(struct listen_address *addr)
goto bad;
}
on = 1;
#ifdef IPV6_V6ONLY
#ifdef HAVE_STRUCT_IN6_ADDR
if (addr->sa_un.sa.sa_family == AF_INET6) {
family = "inet6";
# ifdef IPV6_V6ONLY
/* Disable IPv4-mapped IPv6 addresses. */
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1)
sudo_warn("IPV6_V6ONLY");
# endif
}
#endif
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
sudo_warn("SO_REUSEADDR");
if (bind(sock, &addr->sa_un.sa, addr->sa_len) == -1) {
sudo_warn("%s", addr->sa_str);
/* TODO: only warn once for IPv4 and IPv6 or disambiguate */
sudo_warn("%s (%s)", addr->sa_str, family);
goto bad;
}
if (listen(sock, SOMAXCONN) == -1) {
@ -1493,8 +1530,8 @@ create_listener(struct listen_address *addr)
sudo_warn("fcntl(O_NONBLOCK)");
goto bad;
}
sudo_debug_printf(SUDO_DEBUG_INFO, "listening on %s (AF_INET%s)",
addr->sa_str, addr->sa_un.sa.sa_family == AF_INET6 ? "6" : "");
sudo_debug_printf(SUDO_DEBUG_INFO, "listening on %s (%s)", addr->sa_str,
family);
debug_return_int(sock);
bad:
@ -1506,7 +1543,8 @@ bad:
static void
listener_cb(int fd, int what, void *v)
{
struct sudo_event_base *base = v;
struct listener *l = v;
struct sudo_event_base *evbase = sudo_ev_get_base(l->ev);
union sockaddr_union s_un;
socklen_t salen = sizeof(s_un);
int sock;
@ -1523,7 +1561,7 @@ listener_cb(int fd, int what, void *v)
"unable to set SO_KEEPALIVE option");
}
}
if (!new_connection(sock, &s_un.sa, base)) {
if (!new_connection(sock, l->tls, &s_un.sa, evbase)) {
/* TODO: pause accepting on ENOMEM */
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to start new connection");
@ -1540,10 +1578,9 @@ listener_cb(int fd, int what, void *v)
}
static bool
register_listener(struct listen_address *addr, struct sudo_event_base *base)
register_listener(struct listen_address *addr, struct sudo_event_base *evbase)
{
struct listener *l;
struct sudo_event *ev;
int sock;
debug_decl(register_listener, SUDO_DEBUG_UTIL);
@ -1552,15 +1589,15 @@ register_listener(struct listen_address *addr, struct sudo_event_base *base)
debug_return_bool(false);
/* TODO: make non-fatal */
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"));
if ((l = malloc(sizeof(*l))) == NULL)
sudo_fatal(NULL);
l->sock = sock;
l->ev = ev;
l->tls = addr->tls;
l->ev = sudo_ev_alloc(sock, SUDO_EV_READ|SUDO_EV_PERSIST, listener_cb, l);
if (l->ev == NULL)
sudo_fatal(NULL);
if (sudo_ev_add(evbase, l->ev, NULL, false) == -1)
sudo_fatal(U_("unable to add event to queue"));
TAILQ_INSERT_TAIL(&listeners, l, entries);
debug_return_bool(true);
@ -1575,6 +1612,7 @@ server_setup(struct sudo_event_base *base)
struct listen_address *addr;
struct listener *l;
int nlisteners = 0;
bool config_tls = false;
debug_decl(server_setup, SUDO_DEBUG_UTIL);
/* Free old listeners (if any) and register new ones. */
@ -1586,14 +1624,16 @@ server_setup(struct sudo_event_base *base)
}
TAILQ_FOREACH(addr, logsrvd_conf_listen_address(), entries) {
nlisteners += register_listener(addr, base);
if (addr->tls)
config_tls = true;
}
if (config_tls) {
#if defined(HAVE_OPENSSL)
if (logsrvd_conf_get_tls_opt()) {
if (!init_tls_server_context())
sudo_fatal(NULL);
}
#endif
}
debug_return_bool(nlisteners > 0);
}

View File

@ -31,9 +31,6 @@
#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
@ -102,6 +99,7 @@ struct connection_closure {
#endif
const char *errstr;
struct iolog_file iolog_files[IOFD_MAX];
bool tls;
bool read_instead_of_write;
bool write_instead_of_read;
bool temporary_write_event;
@ -131,6 +129,7 @@ struct listen_address {
char *sa_str;
union sockaddr_union sa_un;
socklen_t sa_len;
bool tls;
};
TAILQ_HEAD(listen_address_list, listen_address);
@ -141,6 +140,7 @@ struct listener {
TAILQ_ENTRY(listener) entries;
struct sudo_event *ev;
int sock;
bool tls;
};
TAILQ_HEAD(listener_list, listener);
@ -199,7 +199,6 @@ bool logsrvd_conf_tcp_keepalive(void);
const char *logsrvd_conf_pid_file(void);
struct timespec *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

View File

@ -164,12 +164,6 @@ logsrvd_conf_get_sock_timeout(void)
}
#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)
{
@ -373,7 +367,6 @@ cb_iolog_maxseq(struct logsrvd_config *config, const char *str)
}
/* Server callbacks */
/* TODO: unit test */
static bool
cb_listen_address(struct logsrvd_config *config, const char *str)
{
@ -389,12 +382,19 @@ cb_listen_address(struct logsrvd_config *config, const char *str)
}
/* Parse host[:port] */
if (!sudo_parse_host_port(copy, &host, &port, &tls, DEFAULT_PORT_STR,
DEFAULT_PORT_STR))
if (!sudo_parse_host_port(copy, &host, &port, &tls, DEFAULT_PORT,
DEFAULT_PORT_TLS))
goto done;
if (host[0] == '*' && host[1] == '\0')
host = NULL;
#if !defined(HAVE_OPENSSL)
if (tls) {
sudo_warn("%s", U_("TLS not supported"));
goto done;
}
#endif
/* Resolve host (and port if it is a service). */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
@ -402,7 +402,7 @@ cb_listen_address(struct logsrvd_config *config, const char *str)
hints.ai_flags = AI_PASSIVE;
error = getaddrinfo(host, port, &hints, &res0);
if (error != 0) {
sudo_warnx("%s", gai_strerror(error));
sudo_gai_warn(error, U_("%s:%s"), host ? host : "*", port);
goto done;
}
for (res = res0; res != NULL; res = res->ai_next) {
@ -419,6 +419,7 @@ cb_listen_address(struct logsrvd_config *config, const char *str)
}
memcpy(&addr->sa_un, res->ai_addr, res->ai_addrlen);
addr->sa_len = res->ai_addrlen;
addr->tls = tls;
TAILQ_INSERT_TAIL(&config->server.addresses, addr, entries);
}
@ -482,19 +483,6 @@ cb_pid_file(struct logsrvd_config *config, const char *str)
}
#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_tls_key(struct logsrvd_config *config, const char *path)
{
@ -761,7 +749,6 @@ static struct logsrvd_config_entry server_conf_entries[] = {
{ "tcp_keepalive", cb_keepalive },
{ "pid_file", cb_pid_file },
#if defined(HAVE_OPENSSL)
{ "tls", cb_tls_opt },
{ "tls_key", cb_tls_key },
{ "tls_cacert", cb_tls_cacert },
{ "tls_cert", cb_tls_cert },
@ -1069,8 +1056,12 @@ logsrvd_conf_apply(struct logsrvd_config *config)
/* There can be multiple addresses so we can't set a default earlier. */
if (TAILQ_EMPTY(&config->server.addresses)) {
if (!cb_listen_address(config, "*:30344"))
if (!cb_listen_address(config, "*:" DEFAULT_PORT))
debug_return_bool(false);
#if defined(HAVE_OPENSSL)
if (!cb_listen_address(config, "*:" DEFAULT_PORT_TLS "(tls)"))
debug_return_bool(false);
#endif
}
/* Open event log if specified. */

View File

@ -24,6 +24,7 @@
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
@ -54,6 +55,7 @@
#include "sudo_event.h"
#include "sudo_fatal.h"
#include "sudo_iolog.h"
#include "hostcheck.h"
#include "sendlog.h"
#if defined(HAVE_OPENSSL)
@ -77,19 +79,23 @@
TAILQ_HEAD(connection_list, client_closure);
static struct connection_list connections = TAILQ_HEAD_INITIALIZER(connections);
static const char *server_name = "localhost";
#if defined(HAVE_STRUCT_IN6_ADDR)
static char server_ip[INET6_ADDRSTRLEN];
#else
static char server_ip[INET_ADDRSTRLEN];
#endif
static char *iolog_dir;
static bool testrun = false;
static int nr_of_conns = 1;
static int finished_transmissions = 0;
#if defined(HAVE_OPENSSL)
static bool tls = false;
static bool tls_reqcert = false;
static bool tls_server_auth = false;
static SSL_CTX *ssl_ctx = NULL;
const char *ca_bundle = NULL;
const char *cert = NULL;
const char *key = NULL;
static const char *server_cert_error = NULL;
static const char *ca_bundle = NULL;
static const char *cert = NULL;
static const char *key = NULL;
#endif
/* Server callback may redirect to client callback for TLS. */
@ -132,6 +138,44 @@ help(void)
}
#if defined(HAVE_OPENSSL)
/*
* Check the server's certificate. If there is a problem, stores an error
* string in server_cert_error. The TLS handshake is allowed to proceed
* even if the server's cert does not validate. Checking of the server's
* cert status is deferred until after the ServerHello message is parsed.
*/
static int
verify_peer_identity(int preverify_ok, X509_STORE_CTX *ctx)
{
HostnameValidationResult result;
X509 *current_cert;
X509 *peer_cert;
debug_decl(verify_peer_identity, SUDO_DEBUG_UTIL);
/* if pre-verification of the cert failed, store the error string. */
if (preverify_ok != 1) {
int err = X509_STORE_CTX_get_error(ctx);
server_cert_error = X509_verify_cert_error_string(err);
debug_return_int(1);
}
/* since this callback is called for each cert in the chain,
* check that current cert is the peer's certificate
*/
current_cert = X509_STORE_CTX_get_current_cert(ctx);
peer_cert = X509_STORE_CTX_get0_cert(ctx);
if (current_cert != peer_cert) {
debug_return_int(1);
}
result = validate_hostname(peer_cert, server_name, server_ip, 0);
if (result != MatchFound) {
server_cert_error = "server certificate does not match host name";
}
debug_return_int(1);
}
static SSL_CTX *
init_tls_client_context(const char *ca_bundle_file, const char *cert_file, const char *key_file)
{
@ -182,7 +226,7 @@ init_tls_client_context(const char *ca_bundle_file, const char *cert_file, const
}
}
if (tls_server_auth) {
if (ca_bundle_file != NULL) {
/* 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,
@ -190,11 +234,11 @@ init_tls_client_context(const char *ca_bundle_file, const char *cert_file, const
ERR_error_string(ERR_get_error(), NULL));
goto bad;
}
/* set verify server cert during the handshake */
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
}
/* verify server cert during the handshake */
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_peer_identity);
goto exit;
bad:
@ -208,11 +252,10 @@ static void
tls_connect_cb(int sock, int what, void *v)
{
struct client_closure *closure = v;
struct sudo_event_base *evbase = closure->tls_connect_ev->base;
struct sudo_event_base *evbase = closure->evbase;
struct timespec timeo = { TLS_HANDSHAKE_TIMEO_SEC, 0 };
const char *errstr;
int con_stat, err;
debug_decl(tls_connect_cb, SUDO_DEBUG_UTIL);
if (what == SUDO_EV_TIMEOUT) {
@ -223,11 +266,15 @@ tls_connect_cb(int sock, int what, void *v)
con_stat = SSL_connect(closure->ssl);
if (con_stat == 1) {
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"SSL_connect successful");
closure->tls_connect_state = true;
} else {
switch ((err = SSL_get_error(closure->ssl, con_stat))) {
/* TLS connect successful */
case SSL_ERROR_NONE:
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"SSL_connect successful");
closure->tls_connect_state = true;
break;
/* TLS handshake is not finished, reschedule event */
@ -269,6 +316,19 @@ tls_connect_cb(int sock, int what, void *v)
}
}
if (closure->tls_connect_state) {
if (!testrun) {
printf("Negotiated protocol version: %s\n", SSL_get_version(closure->ssl));
printf("Negotiated ciphersuite: %s\n", SSL_get_cipher(closure->ssl));
}
/* Done with TLS connect, read ServerHello */
sudo_ev_free(closure->tls_connect_ev);
closure->tls_connect_ev = NULL;
if (sudo_ev_add(evbase, closure->read_ev, NULL, false) == -1)
goto bad;
}
debug_return;
bad:
@ -277,50 +337,15 @@ bad:
}
static bool
tls_connect_async(struct client_closure *closure)
{
struct sudo_event_base *evbase;
debug_decl(tls_connect_async, SUDO_DEBUG_UTIL);
closure->tls_connect_state = false;
evbase = sudo_ev_base_alloc();
closure->tls_connect_ev = sudo_ev_alloc(closure->sock, SUDO_EV_WRITE,
tls_connect_cb, closure);
if (evbase == NULL || closure->tls_connect_ev == NULL) {
sudo_warnx(U_("unable to allocate memory"));
goto done;
}
if (sudo_ev_add(evbase, closure->tls_connect_ev, NULL, false) == -1) {
sudo_warnx(U_("unable to add event to queue"));
goto done;
}
if (sudo_ev_dispatch(evbase) == -1 || sudo_ev_got_break(evbase)) {
sudo_warn(U_("error in event loop"));
goto done;
}
done:
sudo_ev_base_free(evbase);
sudo_ev_free(closure->tls_connect_ev);
closure->tls_connect_ev = NULL;
debug_return_int(closure->tls_connect_state);
}
static bool
do_tls_handshake(struct client_closure *closure)
tls_setup(struct client_closure *closure)
{
const char *errstr;
debug_decl(do_tls_handshake, SUDO_DEBUG_UTIL);
debug_decl(tls_setup, SUDO_DEBUG_UTIL);
if (ca_bundle == NULL) {
sudo_warnx("%s", U_("CA bundle file was not specified"));
goto bad;
}
if (tls_reqcert && (cert == NULL)) {
sudo_warnx("%s", U_("Client certificate was not specified"));
goto bad;
}
if ((ssl_ctx = init_tls_client_context(ca_bundle, cert, key)) == NULL) {
errstr = ERR_reason_error_string(ERR_get_error());
sudo_warnx(U_("Unable to initialize ssl context: %s"), errstr);
@ -338,12 +363,9 @@ do_tls_handshake(struct client_closure *closure)
goto bad;
}
if (!tls_connect_async(closure))
goto bad;
if (!testrun) {
printf("Negotiated protocol version: %s\n", SSL_get_version(closure->ssl));
printf("Negotiated ciphersuite: %s\n", SSL_get_cipher(closure->ssl));
if (sudo_ev_add(closure->evbase, closure->tls_connect_ev, NULL, false) == -1) {
sudo_warnx(U_("unable to add event to queue"));
goto bad;
}
debug_return_bool(true);
@ -391,8 +413,16 @@ connect_server(const char *host, const char *port)
sock = -1;
continue;
}
if (*server_ip == '\0') {
if (inet_ntop(res->ai_family, res->ai_addr, server_ip,
sizeof(server_ip)) == NULL) {
sudo_warnx(U_("unable to get server IP addr"));
}
}
break; /* success */
}
freeaddrinfo(res0);
if (sock != -1) {
int flags = fcntl(sock, F_GETFL, 0);
if (flags == -1 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
@ -403,10 +433,8 @@ connect_server(const char *host, const char *port)
sock = -1;
}
}
if (sock == -1)
sudo_warn("%s", cause);
freeaddrinfo(res0);
debug_return_int(sock);
}
@ -420,22 +448,20 @@ client_closure_free(struct client_closure *closure)
debug_decl(connection_closure_free, SUDO_DEBUG_UTIL);
if (closure != NULL) {
TAILQ_REMOVE(&connections, closure, entries);
#if defined(HAVE_OPENSSL)
if (closure->ssl != NULL) {
SSL_shutdown(closure->ssl);
SSL_free(closure->ssl);
}
sudo_ev_free(closure->tls_connect_ev);
#endif
TAILQ_REMOVE(&connections, closure, entries);
close(closure->sock);
sudo_ev_free(closure->read_ev);
sudo_ev_free(closure->write_ev);
#if defined(HAVE_OPENSSL)
sudo_ev_free(closure->tls_connect_ev);
#endif
free(closure->read_buf.data);
free(closure->write_buf.data);
free(closure->buf);
close(closure->sock);
free(closure);
}
@ -487,10 +513,12 @@ client_closure_alloc(int sock, struct sudo_event_base *base,
goto bad;
#if defined(HAVE_OPENSSL)
closure->tls_connect_ev = sudo_ev_alloc(sock, SUDO_EV_WRITE,
tls_connect_cb, closure);
if (closure->tls_connect_ev == NULL)
goto bad;
if (cert != NULL) {
closure->tls_connect_ev = sudo_ev_alloc(sock, SUDO_EV_WRITE,
tls_connect_cb, closure);
if (closure->tls_connect_ev == NULL)
goto bad;
}
#endif
debug_return_ptr(closure);
@ -1062,25 +1090,31 @@ handle_server_hello(ServerHello *msg, struct client_closure *closure)
}
#if defined(HAVE_OPENSSL)
tls = msg->tls;
tls_reqcert = msg->tls_reqcert;
tls_server_auth = msg->tls_server_auth;
if (msg->tls_reqcert && cert == NULL) {
sudo_warnx("%s", U_("Client certificate was not specified"));
debug_return_bool(false);
}
if (msg->tls_server_auth && server_cert_error != NULL) {
sudo_warnx("%s", server_cert_error);
debug_return_bool(false);
}
#endif
if (!testrun) {
printf("server ID: %s\n", msg->server_id);
printf("Server ID: %s\n", msg->server_id);
/* TODO: handle redirect */
if (msg->redirect != NULL && msg->redirect[0] != '\0')
printf("redirect: %s\n", msg->redirect);
printf("Redirect: %s\n", msg->redirect);
for (n = 0; n < msg->n_servers; n++) {
printf("server %zu: %s\n", n + 1, msg->servers[n]);
printf("Server %zu: %s\n", n + 1, msg->servers[n]);
}
#if defined(HAVE_OPENSSL)
if (tls) {
if (msg->tls) {
printf("Requested protocol: TLS\n");
printf("Server authentication: %s\n", tls_server_auth ? "Required":"Not Required");
printf("Client authentication: %s\n", tls_reqcert ? "Required":"Not Required");
printf("Server authentication: %s\n", msg->tls_server_auth ? "Required":"Not Required");
printf("Client authentication: %s\n", msg->tls_reqcert ? "Required":"Not Required");
} else {
printf("Requested protocol: ClearText\n");
}
@ -1123,7 +1157,7 @@ handle_log_id(char *id, struct client_closure *closure)
debug_decl(handle_log_id, SUDO_DEBUG_UTIL);
if (!testrun)
printf("remote log ID: %s\n", id);
printf("Remote log ID: %s\n", id);
debug_return_bool(true);
}
@ -1176,20 +1210,12 @@ handle_server_message(uint8_t *buf, size_t len,
switch (msg->type_case) {
case SERVER_MESSAGE__TYPE_HELLO:
if ((ret = handle_server_hello(msg->hello, closure))) {
/* if server wants to communicate over TLS,
* we have to initialize tls context and do
* a tls connection to the server
*/
#if defined(HAVE_OPENSSL)
if (tls && !do_tls_handshake(closure))
debug_return_bool(false);
#endif
if (sudo_timespecisset(&closure->restart)) {
closure->state = SEND_RESTART;
ret = fmt_restart_message(closure);
closure->state = SEND_RESTART;
ret = fmt_restart_message(closure);
} else {
closure->state = SEND_ACCEPT;
ret = fmt_accept_message(closure);
closure->state = SEND_ACCEPT;
ret = fmt_accept_message(closure);
}
}
break;
@ -1247,9 +1273,9 @@ server_msg_cb(int fd, int what, void *v)
goto bad;
}
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: reading ServerMessage", __func__);
#if defined(HAVE_OPENSSL)
if (tls && closure->state != RECV_HELLO) {
if (cert != NULL) {
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: reading ServerMessage (TLS)", __func__);
nread = SSL_read(closure->ssl, buf->data + buf->len, buf->size - buf->len);
if (nread <= 0) {
int read_status = SSL_get_error(closure->ssl, nread);
@ -1282,12 +1308,12 @@ server_msg_cb(int fd, int what, void *v)
break;
}
}
} 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);
} else
#endif
{
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: reading ServerMessage", __func__);
nread = recv(fd, buf->data + buf->len, buf->size - buf->len, 0);
}
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received %zd bytes from server",
__func__, nread);
switch (nread) {
@ -1369,7 +1395,7 @@ client_msg_cb(int fd, int what, void *v)
"%s: sending %u bytes to server", __func__, buf->len - buf->off);
#if defined(HAVE_OPENSSL)
if (tls) {
if (cert != NULL) {
nwritten = SSL_write(closure->ssl, buf->data + buf->off, buf->len - buf->off);
if (nwritten <= 0) {
int write_status = SSL_get_error(closure->ssl, nwritten);
@ -1390,12 +1416,11 @@ client_msg_cb(int fd, int what, void *v)
break;
}
}
} 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);
} else
#endif
{
nwritten = send(fd, buf->data + buf->off, buf->len - buf->off, 0);
}
if (nwritten == -1) {
sudo_warn("send");
goto bad;
@ -1481,8 +1506,7 @@ main(int argc, char *argv[])
struct client_closure *closure = NULL;
struct sudo_event_base *evbase;
struct iolog_info *log_info;
const char *host = "localhost";
const char *port = DEFAULT_PORT_STR;
const char *port = NULL;
struct timespec restart = { 0, 0 };
struct timespec elapsed = { 0, 0 };
const char *iolog_id = NULL;
@ -1517,7 +1541,7 @@ main(int argc, char *argv[])
while ((ch = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
switch (ch) {
case 'h':
host = optarg;
server_name = optarg;
break;
case 'i':
iolog_id = optarg;
@ -1565,10 +1589,15 @@ main(int argc, char *argv[])
#if defined(HAVE_OPENSSL)
/* if no key file is given explicitly, try to load the key from the cert */
if (cert && !key) {
key = cert;
if (cert != NULL) {
if (key == NULL)
key = cert;
if (port == NULL)
port = DEFAULT_PORT_TLS;
}
#endif
if (port == NULL)
port = DEFAULT_PORT;
if (sudo_timespecisset(&restart) != (iolog_id != NULL)) {
sudo_warnx("%s", U_("both restart point and iolog ID must be specified"));
@ -1595,12 +1624,12 @@ main(int argc, char *argv[])
printf("connecting clients...\n");
for (int i = 0; i < nr_of_conns; i++) {
sock = connect_server(host, port);
sock = connect_server(server_name, port);
if (sock == -1)
goto bad;
if (!testrun)
printf("Connected to %s:%s\n", host, port);
printf("Connected to %s:%s\n", server_name, port);
closure = client_closure_alloc(sock, evbase, &elapsed, &restart,
iolog_id, log_info);
@ -1616,8 +1645,17 @@ main(int argc, char *argv[])
goto bad;
}
if (sudo_ev_add(evbase, closure->read_ev, NULL, false) == -1)
goto bad;
#if defined(HAVE_OPENSSL)
if (cert != NULL) {
if (!tls_setup(closure))
goto bad;
} else
#endif
{
/* No TLS, read ServerHello */
if (sudo_ev_add(evbase, closure->read_ev, NULL, false) == -1)
goto bad;
}
}
if (testrun)