Fix logging intercepted commands to a log server in sudoers.

Only available when the server supports the subcommands capability.
This commit is contained in:
Todd C. Miller
2021-08-09 15:50:26 -06:00
parent 3a090dcdcd
commit 2e99450d40
5 changed files with 118 additions and 51 deletions

View File

@@ -43,7 +43,6 @@
#endif #endif
#ifdef SUDOERS_LOG_CLIENT #ifdef SUDOERS_LOG_CLIENT
static struct client_closure *client_closure = NULL;
static struct log_details audit_details; static struct log_details audit_details;
#endif #endif
char *audit_msg = NULL; char *audit_msg = NULL;
@@ -251,10 +250,19 @@ log_server_accept(char * const command_info[], char * const run_argv[],
bool ret = false; bool ret = false;
debug_decl(log_server_accept, SUDOERS_DEBUG_PLUGIN); debug_decl(log_server_accept, SUDOERS_DEBUG_PLUGIN);
/* Only send accept event to log server if I/O log plugin did not. */ if (SLIST_EMPTY(&def_log_servers))
if (SLIST_EMPTY(&def_log_servers) || def_log_input || def_log_output)
debug_return_bool(true); debug_return_bool(true);
if (ISSET(sudo_mode, MODE_POLICY_INTERCEPTED)) {
/* Older servers don't support multiple commands per session. */
if (!client_closure->subcommands)
debug_return_bool(true);
} else {
/* Only send accept event to log server if I/O log plugin did not. */
if (def_log_input || def_log_output)
debug_return_bool(true);
}
if (sudo_gettime_real(&now) == -1) { if (sudo_gettime_real(&now) == -1) {
sudo_warn("%s", U_("unable to get time of day")); sudo_warn("%s", U_("unable to get time of day"));
goto done; goto done;
@@ -263,8 +271,19 @@ log_server_accept(char * const command_info[], char * const run_argv[],
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
goto done; goto done;
} }
audit_to_eventlog(evlog, command_info, run_argv, run_envp); audit_to_eventlog(evlog, command_info, run_argv, run_envp);
if (client_closure != NULL) {
/* Use existing client closure. */
if (fmt_accept_message(client_closure, evlog)) {
if (client_closure->write_ev->add(client_closure->write_ev,
&client_closure->log_details->server_timeout) == -1) {
sudo_warn("%s", U_("unable to add event to queue"));
goto done;
}
ret = true;
}
} else {
if (!init_log_details(&audit_details, evlog)) if (!init_log_details(&audit_details, evlog))
goto done; goto done;
@@ -273,6 +292,8 @@ log_server_accept(char * const command_info[], char * const run_argv[],
SEND_ACCEPT, NULL, sudoers_audit.event_alloc); SEND_ACCEPT, NULL, sudoers_audit.event_alloc);
if (client_closure != NULL) if (client_closure != NULL)
ret = true; ret = true;
}
done: done:
debug_return_bool(ret); debug_return_bool(ret);
} }

View File

@@ -64,9 +64,6 @@ static struct sudoers_io_operations {
const char **errstr); const char **errstr);
} io_operations; } io_operations;
#ifdef SUDOERS_LOG_CLIENT
static struct client_closure *client_closure;
#endif
static struct log_details iolog_details; static struct log_details iolog_details;
static bool warned = false; static bool warned = false;
static int iolog_dir_fd = -1; static int iolog_dir_fd = -1;

View File

@@ -63,6 +63,9 @@
#include "hostcheck.h" #include "hostcheck.h"
#include "log_client.h" #include "log_client.h"
/* Shared between iolog.c and audit.c */
struct client_closure *client_closure;
/* Server callback may redirect to client callback for TLS. */ /* Server callback may redirect to client callback for TLS. */
static void client_msg_cb(int fd, int what, void *v); static void client_msg_cb(int fd, int what, void *v);
static void server_msg_cb(int fd, int what, void *v); static void server_msg_cb(int fd, int what, void *v);
@@ -698,6 +701,9 @@ fmt_client_message(struct client_closure *closure, ClientMessage *msg)
msg_len = htonl((uint32_t)len); msg_len = htonl((uint32_t)len);
len += sizeof(msg_len); len += sizeof(msg_len);
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: new ClientMessage, %zu bytes",
__func__, len);
/* Resize buffer as needed. */ /* Resize buffer as needed. */
if (len > buf->size) { if (len > buf->size) {
free(buf->data); free(buf->data);
@@ -775,10 +781,9 @@ free_info_messages(InfoMessage **info_msgs, size_t n)
} }
static InfoMessage ** static InfoMessage **
fmt_info_messages(struct client_closure *closure, size_t *n_info_msgs) fmt_info_messages(struct client_closure *closure, struct eventlog *evlog,
size_t *n_info_msgs)
{ {
struct log_details *details = closure->log_details;
struct eventlog *evlog = details->evlog;
InfoMessage__StringList *runargv = NULL; InfoMessage__StringList *runargv = NULL;
InfoMessage__StringList *runenv = NULL; InfoMessage__StringList *runenv = NULL;
InfoMessage **info_msgs = NULL; InfoMessage **info_msgs = NULL;
@@ -945,8 +950,8 @@ bad:
* Appends the wire format message to the closure's write queue. * Appends the wire format message to the closure's write queue.
* Returns true on success, false on failure. * Returns true on success, false on failure.
*/ */
static bool bool
fmt_accept_message(struct client_closure *closure) fmt_accept_message(struct client_closure *closure, struct eventlog *evlog)
{ {
ClientMessage client_msg = CLIENT_MESSAGE__INIT; ClientMessage client_msg = CLIENT_MESSAGE__INIT;
AcceptMessage accept_msg = ACCEPT_MESSAGE__INIT; AcceptMessage accept_msg = ACCEPT_MESSAGE__INIT;
@@ -969,7 +974,8 @@ fmt_accept_message(struct client_closure *closure)
/* Client will send IoBuffer messages. */ /* Client will send IoBuffer messages. */
accept_msg.expect_iobufs = closure->log_io; accept_msg.expect_iobufs = closure->log_io;
accept_msg.info_msgs = fmt_info_messages(closure, &accept_msg.n_info_msgs); accept_msg.info_msgs = fmt_info_messages(closure, evlog,
&accept_msg.n_info_msgs);
if (accept_msg.info_msgs == NULL) if (accept_msg.info_msgs == NULL)
goto done; goto done;
@@ -993,8 +999,8 @@ done:
* Appends the wire format message to the closure's write queue. * Appends the wire format message to the closure's write queue.
* Returns true on success, false on failure. * Returns true on success, false on failure.
*/ */
static bool bool
fmt_reject_message(struct client_closure *closure) fmt_reject_message(struct client_closure *closure, struct eventlog *evlog)
{ {
ClientMessage client_msg = CLIENT_MESSAGE__INIT; ClientMessage client_msg = CLIENT_MESSAGE__INIT;
RejectMessage reject_msg = REJECT_MESSAGE__INIT; RejectMessage reject_msg = REJECT_MESSAGE__INIT;
@@ -1017,7 +1023,8 @@ fmt_reject_message(struct client_closure *closure)
/* Reason for rejecting the request. */ /* Reason for rejecting the request. */
reject_msg.reason = (char *)closure->reason; reject_msg.reason = (char *)closure->reason;
reject_msg.info_msgs = fmt_info_messages(closure, &reject_msg.n_info_msgs); reject_msg.info_msgs = fmt_info_messages(closure, evlog,
&reject_msg.n_info_msgs);
if (reject_msg.info_msgs == NULL) if (reject_msg.info_msgs == NULL)
goto done; goto done;
@@ -1042,7 +1049,7 @@ done:
* Returns true on success, false on failure. * Returns true on success, false on failure.
*/ */
static bool static bool
fmt_alert_message(struct client_closure *closure) fmt_alert_message(struct client_closure *closure, struct eventlog *evlog)
{ {
ClientMessage client_msg = CLIENT_MESSAGE__INIT; ClientMessage client_msg = CLIENT_MESSAGE__INIT;
AlertMessage alert_msg = ALERT_MESSAGE__INIT; AlertMessage alert_msg = ALERT_MESSAGE__INIT;
@@ -1065,7 +1072,8 @@ fmt_alert_message(struct client_closure *closure)
/* Reason for the alert. */ /* Reason for the alert. */
alert_msg.reason = (char *)closure->reason; alert_msg.reason = (char *)closure->reason;
alert_msg.info_msgs = fmt_info_messages(closure, &alert_msg.n_info_msgs); alert_msg.info_msgs = fmt_info_messages(closure, evlog,
&alert_msg.n_info_msgs);
if (alert_msg.info_msgs == NULL) if (alert_msg.info_msgs == NULL)
goto done; goto done;
@@ -1100,7 +1108,7 @@ fmt_initial_message(struct client_closure *closure)
switch (closure->state) { switch (closure->state) {
case SEND_ACCEPT: case SEND_ACCEPT:
/* Format and schedule AcceptMessage. */ /* Format and schedule AcceptMessage. */
if ((ret = fmt_accept_message(closure))) { if ((ret = fmt_accept_message(closure, closure->log_details->evlog))) {
/* /*
* Move read/write events back to main sudo event loop. * Move read/write events back to main sudo event loop.
* Server messages may occur at any time, so no timeout. * Server messages may occur at any time, so no timeout.
@@ -1116,11 +1124,11 @@ fmt_initial_message(struct client_closure *closure)
break; break;
case SEND_REJECT: case SEND_REJECT:
/* Format and schedule RejectMessage. */ /* Format and schedule RejectMessage. */
ret = fmt_reject_message(closure); ret = fmt_reject_message(closure, closure->log_details->evlog);
break; break;
case SEND_ALERT: case SEND_ALERT:
/* Format and schedule AlertMessage. */ /* Format and schedule AlertMessage. */
ret = fmt_alert_message(closure); ret = fmt_alert_message(closure, closure->log_details->evlog);
break; break;
default: default:
sudo_warnx(U_("%s: unexpected state %d"), __func__, closure->state); sudo_warnx(U_("%s: unexpected state %d"), __func__, closure->state);
@@ -1490,6 +1498,9 @@ handle_server_hello(ServerHello *msg, struct client_closure *closure)
__func__, n + 1, msg->servers[n]); __func__, n + 1, msg->servers[n]);
} }
/* Does the server support logging sub-commands in a session? */
closure->subcommands = msg->subcommands;
debug_return_bool(true); debug_return_bool(true);
} }

View File

@@ -94,6 +94,7 @@ struct client_closure {
SSL *ssl; SSL *ssl;
bool ssl_initialized; bool ssl_initialized;
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
bool subcommands;
enum client_state state; enum client_state state;
enum client_state initial_state; /* XXX - bad name */ enum client_state initial_state; /* XXX - bad name */
struct connection_buffer_list write_bufs; struct connection_buffer_list write_bufs;
@@ -113,6 +114,8 @@ struct client_closure {
struct client_closure *log_server_open(struct log_details *details, struct timespec *now, bool log_io, enum client_state initial_state, const char *reason, struct sudo_plugin_event * (*event_alloc)(void)); struct client_closure *log_server_open(struct log_details *details, struct timespec *now, bool log_io, enum client_state initial_state, const char *reason, struct sudo_plugin_event * (*event_alloc)(void));
bool log_server_close(struct client_closure *closure, int exit_status, int error); bool log_server_close(struct client_closure *closure, int exit_status, int error);
bool fmt_client_message(struct client_closure *closure, ClientMessage *msg); bool fmt_client_message(struct client_closure *closure, ClientMessage *msg);
bool fmt_accept_message(struct client_closure *closure, struct eventlog *evlog);
bool fmt_reject_message(struct client_closure *closure, struct eventlog *evlog);
bool fmt_exit_message(struct client_closure *closure, int exit_status, int error); bool fmt_exit_message(struct client_closure *closure, int exit_status, int error);
bool fmt_io_buf(struct client_closure *closure, int type, const char *buf, unsigned int len, struct timespec *delay); bool fmt_io_buf(struct client_closure *closure, int type, const char *buf, unsigned int len, struct timespec *delay);
bool fmt_suspend(struct client_closure *closure, const char *signame, struct timespec *delay); bool fmt_suspend(struct client_closure *closure, const char *signame, struct timespec *delay);
@@ -120,5 +123,6 @@ bool fmt_winsize(struct client_closure *closure, unsigned int lines, unsigned in
bool log_server_connect(struct client_closure *closure); bool log_server_connect(struct client_closure *closure);
void client_closure_free(struct client_closure *closure); void client_closure_free(struct client_closure *closure);
bool read_server_hello(struct client_closure *closure); bool read_server_hello(struct client_closure *closure);
extern struct client_closure *client_closure;
#endif /* SUDOERS_LOG_CLIENT_H */ #endif /* SUDOERS_LOG_CLIENT_H */

View File

@@ -121,20 +121,35 @@ bool
log_server_reject(struct eventlog *evlog, const char *message, log_server_reject(struct eventlog *evlog, const char *message,
struct sudo_plugin_event * (*event_alloc)(void)) struct sudo_plugin_event * (*event_alloc)(void))
{ {
struct client_closure *client_closure;
struct log_details details;
bool ret = false; bool ret = false;
debug_decl(log_server_reject, SUDOERS_DEBUG_LOGGING); debug_decl(log_server_reject, SUDOERS_DEBUG_LOGGING);
if (SLIST_EMPTY(&def_log_servers)) if (SLIST_EMPTY(&def_log_servers))
debug_return_bool(true); debug_return_bool(true);
if (client_closure != NULL) {
/* Older servers don't support multiple commands per session. */
if (!client_closure->subcommands)
debug_return_bool(true);
/* Use existing client closure. */
if (fmt_reject_message(client_closure, evlog)) {
if (client_closure->write_ev->add(client_closure->write_ev,
&client_closure->log_details->server_timeout) == -1) {
sudo_warn("%s", U_("unable to add event to queue"));
goto done;
}
ret = true;
}
} else {
struct log_details details;
if (!init_log_details(&details, evlog)) if (!init_log_details(&details, evlog))
debug_return_bool(false); debug_return_bool(false);
/* Open connection to log server, send hello and reject messages. */ /* Open connection to log server, send hello and reject messages. */
client_closure = log_server_open(&details, &sudo_user.submit_time, false, client_closure = log_server_open(&details, &sudo_user.submit_time,
SEND_REJECT, message, event_alloc); false, SEND_REJECT, message, event_alloc);
if (client_closure != NULL) { if (client_closure != NULL) {
client_closure_free(client_closure); client_closure_free(client_closure);
ret = true; ret = true;
@@ -142,6 +157,9 @@ log_server_reject(struct eventlog *evlog, const char *message,
/* Only the log_servers string list is dynamically allocated. */ /* Only the log_servers string list is dynamically allocated. */
str_list_free(details.log_servers); str_list_free(details.log_servers);
}
done:
debug_return_bool(ret); debug_return_bool(ret);
} }
@@ -150,7 +168,6 @@ log_server_alert(struct eventlog *evlog, struct timespec *now,
const char *message, const char *errstr, const char *message, const char *errstr,
struct sudo_plugin_event * (*event_alloc)(void)) struct sudo_plugin_event * (*event_alloc)(void))
{ {
struct client_closure *client_closure;
struct log_details details; struct log_details details;
char *emessage = NULL; char *emessage = NULL;
bool ret = false; bool ret = false;
@@ -159,9 +176,6 @@ log_server_alert(struct eventlog *evlog, struct timespec *now,
if (SLIST_EMPTY(&def_log_servers)) if (SLIST_EMPTY(&def_log_servers))
debug_return_bool(true); debug_return_bool(true);
if (!init_log_details(&details, evlog))
goto done;
if (errstr != NULL) { if (errstr != NULL) {
if (asprintf(&emessage, _("%s: %s"), message, errstr) == -1) { if (asprintf(&emessage, _("%s: %s"), message, errstr) == -1) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
@@ -169,6 +183,24 @@ log_server_alert(struct eventlog *evlog, struct timespec *now,
} }
} }
if (client_closure != NULL) {
/* Older servers don't support multiple commands per session. */
if (!client_closure->subcommands)
debug_return_bool(true);
/* Use existing client closure. */
if (fmt_reject_message(client_closure, evlog)) {
if (client_closure->write_ev->add(client_closure->write_ev,
&client_closure->log_details->server_timeout) == -1) {
sudo_warn("%s", U_("unable to add event to queue"));
goto done;
}
ret = true;
}
} else {
if (!init_log_details(&details, evlog))
goto done;
/* Open connection to log server, send hello and alert messages. */ /* Open connection to log server, send hello and alert messages. */
client_closure = log_server_open(&details, now, false, client_closure = log_server_open(&details, now, false,
SEND_ALERT, emessage ? emessage : message, event_alloc); SEND_ALERT, emessage ? emessage : message, event_alloc);
@@ -177,10 +209,12 @@ log_server_alert(struct eventlog *evlog, struct timespec *now,
ret = true; ret = true;
} }
done:
/* Only the log_servers string list is dynamically allocated. */ /* Only the log_servers string list is dynamically allocated. */
free(emessage);
str_list_free(details.log_servers); str_list_free(details.log_servers);
}
done:
free(emessage);
debug_return_bool(ret); debug_return_bool(ret);
} }
#else #else