From 9d737441f48405fb3003a149f706e5edee40a76f Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Sat, 7 Dec 2019 08:42:12 -0700 Subject: [PATCH] Fix event loop called via I/O log close function. We need to set events that were pending in the old base in the new one. Fixes sending the final I/O log data and the ExitMessage to the server. --- plugins/sudoers/iolog.c | 15 +--------- plugins/sudoers/iolog_client.c | 55 +++++++++++++++++++++++++++------- plugins/sudoers/iolog_plugin.h | 2 +- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c index dadc7f5b2..6b45b7474 100644 --- a/plugins/sudoers/iolog.c +++ b/plugins/sudoers/iolog.c @@ -727,18 +727,7 @@ sudoers_io_close(int exit_status, int error) debug_decl(sudoers_io_close, SUDOERS_DEBUG_PLUGIN) if (iolog_remote) { - if (client_closure.disabled) - goto done; - - if (!fmt_exit_message(&client_closure, exit_status, error)) - goto done; - - /* - * Main sudo event loop exited, use our own mini event loop - * to flush the write queue and read the final commit messages. - */ - if (!client_loop(&client_closure)) - goto done; + client_close(&client_closure, exit_status, error); } else { for (i = 0; i < IOFD_MAX; i++) { if (iolog_files[i].fd.v == NULL) @@ -747,8 +736,6 @@ sudoers_io_close(int exit_status, int error) } } -done: - client_closure_free(&client_closure); sudo_freepwcache(); sudo_freegrcache(); diff --git a/plugins/sudoers/iolog_client.c b/plugins/sudoers/iolog_client.c index ba39b09c1..32e38ceea 100644 --- a/plugins/sudoers/iolog_client.c +++ b/plugins/sudoers/iolog_client.c @@ -1390,28 +1390,61 @@ oom: } /* - * Custom event loop called from the plugin close function. - * We cannot use the main sudo event loop as it has already exited. + * Send ExitMessage, wait for final commit message and free closure. */ bool -client_loop(struct client_closure *closure) +client_close(struct client_closure *closure, int exit_status, int error) { - struct sudo_event_base *evbase; - debug_decl(client_loop, SUDOERS_DEBUG_UTIL) + struct sudo_event_base *evbase = NULL; + short events; + bool ret = false; + debug_decl(client_close, SUDOERS_DEBUG_UTIL) - /* Create private event base and reparent the read/write events. */ + if (closure->disabled) + goto done; + + /* + * Create private event base and reparent the read/write events. + * We cannot use the main sudo event loop as it has already exited. + */ if ((evbase = sudo_ev_base_alloc()) == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - debug_return_bool(false); + goto done; } + + events = closure->read_ev->pending(closure->read_ev, SUDO_PLUGIN_EV_READ, + NULL); closure->read_ev->setbase(closure->read_ev, evbase); - closure->write_ev->setbase(closure->read_ev, evbase); + if (events == SUDO_PLUGIN_EV_READ) { + if (closure->read_ev->add(closure->read_ev, + &closure->log_details->server_timeout) == -1) { + sudo_warn(U_("unable to add event to queue")); + goto done; + } + } + + events = closure->write_ev->pending(closure->write_ev, SUDO_PLUGIN_EV_WRITE, + NULL); + closure->write_ev->setbase(closure->write_ev, evbase); + if (events == SUDO_PLUGIN_EV_WRITE) { + if (closure->write_ev->add(closure->write_ev, + &closure->log_details->server_timeout) == -1) { + sudo_warn(U_("unable to add event to queue")); + goto done; + } + } + + /* Format and append an ExitMessage to the write queue. */ + if (!fmt_exit_message(closure, exit_status, error)) + goto done; /* Loop until queues are flushed and final commit point received. */ sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, "flushing buffers and waiting for final commit point"); - sudo_ev_dispatch(evbase); - sudo_ev_base_free(evbase); + ret = sudo_ev_dispatch(evbase) == 0; - debug_return_bool(true); +done: + sudo_ev_base_free(evbase); + client_closure_free(closure); + debug_return_bool(ret); } diff --git a/plugins/sudoers/iolog_plugin.h b/plugins/sudoers/iolog_plugin.h index e4b7609c1..0bfab753e 100644 --- a/plugins/sudoers/iolog_plugin.h +++ b/plugins/sudoers/iolog_plugin.h @@ -135,7 +135,7 @@ struct client_closure { /* iolog_client.c */ bool client_closure_fill(struct client_closure *closure, int sock, struct iolog_details *details, struct io_plugin *sudoers_io); -bool client_loop(struct client_closure *closure); +bool client_close(struct client_closure *closure, int exit_status, int error); bool fmt_accept_message(struct client_closure *closure); bool fmt_client_message(struct client_closure *closure, ClientMessage *msg); bool fmt_exit_message(struct client_closure *closure, int exit_status, int error);