Fix TLS connect when SSL_connect returns SSL_ERROR_WANT_READ.
We need to switch from SUDO_EV_WRITE to SUDO_EV_READ for this case. Also make the tls connect events private to tls_timed_connect() with their own closure. There is no need to store them in the client closure.
This commit is contained in:
@@ -182,14 +182,15 @@ static void
|
|||||||
tls_connect_cb(int sock, int what, void *v)
|
tls_connect_cb(int sock, int what, void *v)
|
||||||
{
|
{
|
||||||
struct client_closure *closure = v;
|
struct client_closure *closure = v;
|
||||||
|
struct sudo_event_base *evbase = closure->tls_connect_ev->base;
|
||||||
struct timespec timeo = { TLS_HANDSHAKE_TIMEO_SEC, 0 };
|
struct timespec timeo = { TLS_HANDSHAKE_TIMEO_SEC, 0 };
|
||||||
int con_stat, err;
|
int con_stat, err;
|
||||||
|
|
||||||
debug_decl(tls_connect_cb, SUDO_DEBUG_UTIL);
|
debug_decl(tls_connect_cb, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
if (what == SUDO_EV_TIMEOUT) {
|
if (what == SUDO_EV_TIMEOUT) {
|
||||||
sudo_warnx(U_("TLS handshake timeout occured"));
|
sudo_warnx(U_("TLS handshake timeout occurred"));
|
||||||
debug_return;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
con_stat = SSL_connect(ssl);
|
con_stat = SSL_connect(ssl);
|
||||||
@@ -204,46 +205,71 @@ tls_connect_cb(int sock, int what, void *v)
|
|||||||
break;
|
break;
|
||||||
/* TLS handshake is not finished, reschedule event */
|
/* TLS handshake is not finished, reschedule event */
|
||||||
case SSL_ERROR_WANT_READ:
|
case SSL_ERROR_WANT_READ:
|
||||||
case SSL_ERROR_WANT_WRITE:
|
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
|
||||||
if (sudo_ev_add(closure->tls_connect_ev->base,
|
"SSL_connect returns SSL_ERROR_WANT_READ");
|
||||||
closure->tls_connect_ev, &timeo, false) == -1) {
|
if (what != SUDO_EV_READ) {
|
||||||
|
if (sudo_ev_set(closure->tls_connect_ev, closure->sock,
|
||||||
|
SUDO_EV_READ, tls_connect_cb, closure) == -1) {
|
||||||
|
sudo_warnx(U_("unable to set event"));
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sudo_ev_add(evbase, closure->tls_connect_ev, &timeo, false) == -1) {
|
||||||
sudo_warnx(U_("unable to add event to queue"));
|
sudo_warnx(U_("unable to add event to queue"));
|
||||||
|
goto bad;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
|
||||||
|
"SSL_connect returns SSL_ERROR_WANT_WRITE");
|
||||||
|
if (what != SUDO_EV_WRITE) {
|
||||||
|
if (sudo_ev_set(closure->tls_connect_ev, closure->sock,
|
||||||
|
SUDO_EV_WRITE, tls_connect_cb, closure) == -1) {
|
||||||
|
sudo_warnx(U_("unable to set event"));
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sudo_ev_add(evbase, closure->tls_connect_ev, &timeo, false) == -1) {
|
||||||
|
sudo_warnx(U_("unable to add event to queue"));
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
sudo_warnx(U_("SSL_connect failed: ssl_error=%d, stack=%s\n"),
|
sudo_warnx(U_("SSL_connect failed: ssl_error=%d, stack=%s\n"),
|
||||||
err,
|
err, ERR_error_string(ERR_get_error(), NULL));
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_return;
|
debug_return;
|
||||||
|
|
||||||
|
bad:
|
||||||
|
sudo_ev_loopbreak(evbase);
|
||||||
|
debug_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
tls_connect_async(struct client_closure *closure)
|
tls_connect_async(struct client_closure *closure)
|
||||||
{
|
{
|
||||||
struct sudo_event_base *evbase = NULL;
|
struct sudo_event_base *evbase;
|
||||||
|
|
||||||
debug_decl(tls_connect_async, SUDO_DEBUG_UTIL);
|
debug_decl(tls_connect_async, SUDO_DEBUG_UTIL);
|
||||||
|
|
||||||
evbase = sudo_ev_base_alloc();
|
|
||||||
closure->tls_connect_ev = sudo_ev_alloc(closure->sock, SUDO_EV_WRITE,
|
|
||||||
tls_connect_cb, closure);
|
|
||||||
closure->tls_connect_state = false;
|
closure->tls_connect_state = false;
|
||||||
if (evbase == NULL || closure->tls_connect_ev == NULL) {
|
evbase = sudo_ev_base_alloc();
|
||||||
sudo_warnx(U_("unable to allocate memory"));
|
closure->tls_connect_ev = sudo_ev_alloc(closure->sock, SUDO_EV_WRITE,
|
||||||
goto done;
|
tls_connect_cb, closure);
|
||||||
}
|
if (evbase == NULL || closure->tls_connect_ev == NULL) {
|
||||||
if (sudo_ev_add(evbase, closure->tls_connect_ev, NULL, false) == -1) {
|
sudo_warnx(U_("unable to allocate memory"));
|
||||||
sudo_warnx(U_("unable to add event to queue"));
|
goto done;
|
||||||
goto done;
|
}
|
||||||
}
|
if (sudo_ev_add(evbase, closure->tls_connect_ev, NULL, false) == -1) {
|
||||||
if (sudo_ev_dispatch(evbase) == -1) {
|
sudo_warnx(U_("unable to add event to queue"));
|
||||||
sudo_warn(U_("error in event loop"));
|
goto done;
|
||||||
goto done;
|
}
|
||||||
}
|
if (sudo_ev_dispatch(evbase) == -1 || sudo_ev_got_break(evbase)) {
|
||||||
|
sudo_warn(U_("error in event loop"));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
sudo_ev_base_free(evbase);
|
sudo_ev_base_free(evbase);
|
||||||
|
@@ -294,18 +294,24 @@ bad:
|
|||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tls_connect_closure {
|
||||||
|
bool tls_conn_status;
|
||||||
|
SSL *ssl;
|
||||||
|
struct sudo_event_base *evbase;
|
||||||
|
struct sudo_event *tls_connect_ev;
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tls_connect_cb(int sock, int what, void *v)
|
tls_connect_cb(int sock, int what, void *v)
|
||||||
{
|
{
|
||||||
struct client_closure *closure = v;
|
struct tls_connect_closure *closure = v;
|
||||||
struct timespec timeo = { 10, 0 };
|
struct timespec timeo = { 10, 0 };
|
||||||
int tls_con, err;
|
int tls_con, err;
|
||||||
|
|
||||||
debug_decl(tls_connect_cb, SUDOERS_DEBUG_UTIL);
|
debug_decl(tls_connect_cb, SUDOERS_DEBUG_UTIL);
|
||||||
|
|
||||||
if (what == SUDO_PLUGIN_EV_TIMEOUT) {
|
if (what == SUDO_PLUGIN_EV_TIMEOUT) {
|
||||||
sudo_warnx(U_("TLS handshake timeout occured"));
|
sudo_warnx(U_("TLS handshake timeout occurred"));
|
||||||
debug_return;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
tls_con = SSL_connect(closure->ssl);
|
tls_con = SSL_connect(closure->ssl);
|
||||||
@@ -318,57 +324,88 @@ tls_connect_cb(int sock, int what, void *v)
|
|||||||
case SSL_ERROR_NONE:
|
case SSL_ERROR_NONE:
|
||||||
closure->tls_conn_status = true;
|
closure->tls_conn_status = true;
|
||||||
break;
|
break;
|
||||||
/* TLS handshake is not finished, reschedule event */
|
/* TLS handshake is not finished, reschedule event */
|
||||||
case SSL_ERROR_WANT_READ:
|
case SSL_ERROR_WANT_READ:
|
||||||
case SSL_ERROR_WANT_WRITE:
|
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
|
||||||
if (closure->tls_connect_ev->add(closure->tls_connect_ev, &timeo) == -1) {
|
"SSL_connect returns SSL_ERROR_WANT_READ");
|
||||||
|
if (what != SUDO_EV_READ) {
|
||||||
|
if (sudo_ev_set(closure->tls_connect_ev, sock,
|
||||||
|
SUDO_EV_READ, tls_connect_cb, closure) == -1) {
|
||||||
|
sudo_warnx(U_("unable to set event"));
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sudo_ev_add(closure->evbase, closure->tls_connect_ev,
|
||||||
|
&timeo, false) == -1) {
|
||||||
sudo_warnx(U_("unable to add event to queue"));
|
sudo_warnx(U_("unable to add event to queue"));
|
||||||
|
goto bad;
|
||||||
}
|
}
|
||||||
debug_return;
|
break;
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
|
||||||
|
"SSL_connect returns SSL_ERROR_WANT_WRITE");
|
||||||
|
if (what != SUDO_EV_WRITE) {
|
||||||
|
if (sudo_ev_set(closure->tls_connect_ev, sock,
|
||||||
|
SUDO_EV_WRITE, tls_connect_cb, closure) == -1) {
|
||||||
|
sudo_warnx(U_("unable to set event"));
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sudo_ev_add(closure->evbase, closure->tls_connect_ev,
|
||||||
|
&timeo, false) == -1) {
|
||||||
|
sudo_warnx(U_("unable to add event to queue"));
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
sudo_warnx(U_("SSL_connect failed: ssl_error=%d, stack=%s"),
|
sudo_warnx(U_("SSL_connect failed: ssl_error=%d, stack=%s"),
|
||||||
err,
|
err, ERR_error_string(ERR_get_error(), NULL));
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
goto bad;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closure->tls_connect_ev->del(closure->tls_connect_ev);
|
debug_return;
|
||||||
|
|
||||||
|
bad:
|
||||||
|
/* Break out of tls connect event loop with an error. */
|
||||||
|
sudo_ev_loopbreak(closure->evbase);
|
||||||
|
|
||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
tls_timed_connect(struct client_closure *closure)
|
tls_timed_connect(int sock, SSL *ssl, struct timespec *timo)
|
||||||
{
|
{
|
||||||
struct sudo_event_base *evbase = NULL;
|
struct tls_connect_closure closure;
|
||||||
debug_decl(tls_timed_connect, SUDOERS_DEBUG_UTIL);
|
debug_decl(tls_timed_connect, SUDOERS_DEBUG_UTIL);
|
||||||
|
|
||||||
evbase = sudo_ev_base_alloc();
|
memset(&closure, 0, sizeof(closure));
|
||||||
closure->tls_conn_status = false;
|
closure.ssl = ssl;
|
||||||
if (evbase == NULL || closure->tls_connect_ev == NULL) {
|
closure.evbase = sudo_ev_base_alloc();
|
||||||
sudo_warnx(U_("unable to allocate memory"));
|
closure.tls_connect_ev = sudo_ev_alloc(sock, SUDO_PLUGIN_EV_WRITE,
|
||||||
goto exit;
|
tls_connect_cb, &closure);
|
||||||
|
|
||||||
|
if (closure.evbase == NULL || closure.tls_connect_ev == NULL) {
|
||||||
|
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
closure->tls_connect_ev->setbase(closure->tls_connect_ev, evbase);
|
if (sudo_ev_add(closure.evbase, closure.tls_connect_ev, timo, false) == -1) {
|
||||||
|
sudo_warnx(U_("unable to add event to queue"));
|
||||||
if (closure->tls_connect_ev->add(closure->tls_connect_ev,
|
goto done;
|
||||||
&closure->log_details->server_timeout) == -1) {
|
|
||||||
sudo_warnx(U_("Unable to add event to queue"));
|
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sudo_ev_dispatch(evbase) == -1) {
|
if (sudo_ev_dispatch(closure.evbase) == -1 || sudo_ev_got_break(closure.evbase)) {
|
||||||
sudo_warnx(U_("error in event loop"));
|
sudo_warnx(U_("error in event loop"));
|
||||||
goto exit;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
done:
|
||||||
sudo_ev_base_free(evbase);
|
if (closure.tls_connect_ev != NULL)
|
||||||
if (closure->tls_connect_ev != NULL)
|
sudo_ev_free(closure.tls_connect_ev);
|
||||||
closure->tls_connect_ev->free(closure->tls_connect_ev);
|
sudo_ev_base_free(closure.evbase);
|
||||||
|
|
||||||
debug_return_int(closure->tls_conn_status);
|
debug_return_bool(closure.tls_conn_status);
|
||||||
}
|
}
|
||||||
#endif /* HAVE_OPENSSL */
|
#endif /* HAVE_OPENSSL */
|
||||||
|
|
||||||
@@ -935,7 +972,8 @@ handle_server_hello(ServerHello *msg, struct client_closure *closure)
|
|||||||
sudo_warnx(U_("TLS initialization was unsuccessful"));
|
sudo_warnx(U_("TLS initialization was unsuccessful"));
|
||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
if (!tls_timed_connect(closure)) {
|
if (!tls_timed_connect(closure->sock, closure->ssl,
|
||||||
|
&closure->log_details->server_timeout)) {
|
||||||
sudo_warnx(U_("TLS handshake was unsuccessful"));
|
sudo_warnx(U_("TLS handshake was unsuccessful"));
|
||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
@@ -1355,11 +1393,6 @@ client_closure_fill(struct client_closure *closure, int sock,
|
|||||||
if ((closure->write_ev = sudoers_io->event_alloc()) == NULL)
|
if ((closure->write_ev = sudoers_io->event_alloc()) == NULL)
|
||||||
goto oom;
|
goto oom;
|
||||||
|
|
||||||
#if defined(HAVE_OPENSSL)
|
|
||||||
if ((closure->tls_connect_ev = sudoers_io->event_alloc()) == NULL)
|
|
||||||
goto oom;
|
|
||||||
#endif /* HAVE_OPENSSL */
|
|
||||||
|
|
||||||
if (closure->read_ev->set(closure->read_ev, sock,
|
if (closure->read_ev->set(closure->read_ev, sock,
|
||||||
SUDO_PLUGIN_EV_READ|SUDO_PLUGIN_EV_PERSIST,
|
SUDO_PLUGIN_EV_READ|SUDO_PLUGIN_EV_PERSIST,
|
||||||
server_msg_cb, closure) == -1)
|
server_msg_cb, closure) == -1)
|
||||||
@@ -1370,13 +1403,6 @@ client_closure_fill(struct client_closure *closure, int sock,
|
|||||||
client_msg_cb, closure) == -1)
|
client_msg_cb, closure) == -1)
|
||||||
goto oom;
|
goto oom;
|
||||||
|
|
||||||
#if defined(HAVE_OPENSSL)
|
|
||||||
if (closure->tls_connect_ev->set(closure->tls_connect_ev, sock,
|
|
||||||
SUDO_PLUGIN_EV_WRITE|SUDO_PLUGIN_EV_PERSIST,
|
|
||||||
tls_connect_cb, closure) == -1)
|
|
||||||
goto oom;
|
|
||||||
#endif /* HAVE_OPENSSL */
|
|
||||||
|
|
||||||
closure->log_details = details;
|
closure->log_details = details;
|
||||||
|
|
||||||
/* Store sock last to avoid double-close in parent on error. */
|
/* Store sock last to avoid double-close in parent on error. */
|
||||||
|
@@ -88,7 +88,6 @@ struct client_closure {
|
|||||||
int sock;
|
int sock;
|
||||||
#if defined(HAVE_OPENSSL)
|
#if defined(HAVE_OPENSSL)
|
||||||
bool tls;
|
bool tls;
|
||||||
bool tls_conn_status;
|
|
||||||
SSL_CTX *ssl_ctx;
|
SSL_CTX *ssl_ctx;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
#endif /* HAVE_OPENSSL */
|
#endif /* HAVE_OPENSSL */
|
||||||
@@ -97,9 +96,6 @@ struct client_closure {
|
|||||||
struct connection_buffer_list write_bufs;
|
struct connection_buffer_list write_bufs;
|
||||||
struct connection_buffer_list free_bufs;
|
struct connection_buffer_list free_bufs;
|
||||||
struct connection_buffer read_buf;
|
struct connection_buffer read_buf;
|
||||||
#if defined(HAVE_OPENSSL)
|
|
||||||
struct sudo_plugin_event *tls_connect_ev;
|
|
||||||
#endif /* HAVE_OPENSSL */
|
|
||||||
struct sudo_plugin_event *read_ev;
|
struct sudo_plugin_event *read_ev;
|
||||||
struct sudo_plugin_event *write_ev;
|
struct sudo_plugin_event *write_ev;
|
||||||
struct iolog_details *log_details;
|
struct iolog_details *log_details;
|
||||||
@@ -114,7 +110,6 @@ struct client_closure {
|
|||||||
{ \
|
{ \
|
||||||
-1, \
|
-1, \
|
||||||
false, \
|
false, \
|
||||||
false, \
|
|
||||||
NULL, \
|
NULL, \
|
||||||
NULL, \
|
NULL, \
|
||||||
ERROR, \
|
ERROR, \
|
||||||
|
Reference in New Issue
Block a user