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

Add a relay mode to sudo_logsrvd where it forwards instead of stores.

Relay hosts are be specified in the server section of sudo_logsrvd.conf.
This commit is contained in:
Todd C. Miller 2021-04-06 14:44:19 -06:00
parent 343100307d
commit d60b8a791c
6 changed files with 1212 additions and 25 deletions

View File

@ -348,6 +348,7 @@ logsrvd/logsrv_util.h
logsrvd/logsrvd.c
logsrvd/logsrvd.h
logsrvd/logsrvd_conf.c
logsrvd/logsrvd_relay.c
logsrvd/regress/corpus/seed/logsrvd_conf/logsrvd.conf.1
logsrvd/regress/corpus/seed/logsrvd_conf/logsrvd.conf.2
logsrvd/regress/corpus/seed/logsrvd_conf/logsrvd.conf.3

View File

@ -120,7 +120,7 @@ SHELL = @SHELL@
PROGS = sudo_logsrvd sudo_sendlog
LOGSRVD_OBJS = logsrv_util.o iolog_writer.o logsrvd.o logsrvd_conf.o \
tls_init.o
logsrvd_relay.o tls_init.o
SENDLOG_OBJS = logsrv_util.o sendlog.o tls_client.o tls_init.o
@ -383,6 +383,30 @@ logsrvd_conf.i: $(srcdir)/logsrvd_conf.c $(incdir)/compat/getaddrinfo.h \
$(CC) -E -o $@ $(CPPFLAGS) $<
logsrvd_conf.plog: logsrvd_conf.i
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/logsrvd_conf.c --i-file $< --output-file $@
logsrvd_relay.o: $(srcdir)/logsrvd_relay.c $(incdir)/compat/getopt.h \
$(incdir)/compat/stdbool.h $(incdir)/log_server.pb-c.h \
$(incdir)/protobuf-c/protobuf-c.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
$(incdir)/sudo_event.h $(incdir)/sudo_eventlog.h \
$(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \
$(incdir)/sudo_json.h $(incdir)/sudo_queue.h \
$(incdir)/sudo_util.h $(srcdir)/logsrv_util.h \
$(srcdir)/logsrvd.h $(srcdir)/tls_common.h \
$(top_builddir)/config.h $(top_builddir)/pathnames.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/logsrvd_relay.c
logsrvd_relay.i: $(srcdir)/logsrvd_relay.c $(incdir)/compat/getopt.h \
$(incdir)/compat/stdbool.h $(incdir)/log_server.pb-c.h \
$(incdir)/protobuf-c/protobuf-c.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
$(incdir)/sudo_event.h $(incdir)/sudo_eventlog.h \
$(incdir)/sudo_gettext.h $(incdir)/sudo_iolog.h \
$(incdir)/sudo_json.h $(incdir)/sudo_queue.h \
$(incdir)/sudo_util.h $(srcdir)/logsrv_util.h \
$(srcdir)/logsrvd.h $(srcdir)/tls_common.h \
$(top_builddir)/config.h $(top_builddir)/pathnames.h
$(CC) -E -o $@ $(CPPFLAGS) $<
logsrvd_relay.plog: logsrvd_relay.i
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/logsrvd_relay.c --i-file $< --output-file $@
sendlog.o: $(srcdir)/sendlog.c $(incdir)/compat/getaddrinfo.h \
$(incdir)/compat/getopt.h $(incdir)/compat/stdbool.h \
$(incdir)/hostcheck.h $(incdir)/log_server.pb-c.h \

View File

@ -95,7 +95,7 @@ static void client_msg_cb(int fd, int what, void *v);
/*
* Free a struct connection_closure container and its contents.
*/
static void
void
connection_closure_free(struct connection_closure *closure)
{
debug_decl(connection_closure_free, SUDO_DEBUG_UTIL);
@ -106,12 +106,8 @@ connection_closure_free(struct connection_closure *closure)
struct connection_buffer *buf;
TAILQ_REMOVE(&connections, closure, entries);
#if defined(HAVE_OPENSSL)
if (closure->ssl != NULL) {
SSL_shutdown(closure->ssl);
SSL_free(closure->ssl);
}
#endif
if (closure->relay_closure != NULL)
relay_closure_free(closure->relay_closure);
close(closure->sock);
iolog_close_all(closure);
sudo_ev_free(closure->commit_ev);
@ -119,6 +115,10 @@ connection_closure_free(struct connection_closure *closure)
sudo_ev_free(closure->write_ev);
#if defined(HAVE_OPENSSL)
sudo_ev_free(closure->ssl_accept_ev);
if (closure->ssl != NULL) {
SSL_shutdown(closure->ssl);
SSL_free(closure->ssl);
}
#endif
eventlog_free(closure->evlog);
free(closure->read_buf.data);
@ -141,7 +141,7 @@ connection_closure_free(struct connection_closure *closure)
debug_return;
}
static struct connection_buffer *
struct connection_buffer *
get_free_buf(struct connection_closure *closure)
{
struct connection_buffer *buf;
@ -156,7 +156,7 @@ get_free_buf(struct connection_closure *closure)
debug_return_ptr(buf);
}
static bool
bool
fmt_server_message(struct connection_closure *closure, ServerMessage *msg)
{
struct connection_buffer *buf;
@ -227,7 +227,7 @@ fmt_hello_message(struct connection_closure *closure)
debug_return_bool(fmt_server_message(closure, &msg));
}
static bool
bool
fmt_log_id_message(const char *id, struct connection_closure *closure)
{
ServerMessage msg = SERVER_MESSAGE__INIT;
@ -239,7 +239,7 @@ fmt_log_id_message(const char *id, struct connection_closure *closure)
debug_return_bool(fmt_server_message(closure, &msg));
}
static bool
bool
fmt_error_message(const char *errstr, struct connection_closure *closure)
{
ServerMessage msg = SERVER_MESSAGE__INIT;
@ -333,6 +333,11 @@ handle_accept(AcceptMessage *msg, struct connection_closure *closure)
}
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received AcceptMessage", __func__);
if (closure->relay_closure != NULL) {
/* Forward AcceptMessage to connected relay. */
debug_return_bool(relay_accept(msg, closure));
}
closure->evlog = evlog_new(msg->submit_time, msg->info_msgs,
msg->n_info_msgs, closure);
if (closure->evlog == NULL) {
@ -396,6 +401,11 @@ handle_reject(RejectMessage *msg, struct connection_closure *closure)
}
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received RejectMessage", __func__);
if (closure->relay_closure != NULL) {
/* Forward RejectMessage to connected relay. */
debug_return_bool(relay_reject(msg, closure));
}
closure->evlog = evlog_new(msg->submit_time, msg->info_msgs,
msg->n_info_msgs, closure);
if (closure->evlog == NULL) {
@ -429,6 +439,11 @@ handle_exit(ExitMessage *msg, struct connection_closure *closure)
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received ExitMessage", __func__);
if (closure->relay_closure != NULL) {
/* Forward ExitMessage to connected relay. */
debug_return_bool(relay_exit(msg, closure));
}
/* Sudo I/O logs don't store this info. */
if (msg->signal != NULL && msg->signal[0] != '\0') {
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
@ -484,6 +499,11 @@ handle_restart(RestartMessage *msg, struct connection_closure *closure)
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received RestartMessage for %s",
__func__, msg->log_id);
if (closure->relay_closure != NULL) {
/* Forward RestartMessage to connected relay. */
debug_return_bool(relay_restart(msg, closure));
}
if (!iolog_restart(msg, closure)) {
sudo_debug_printf(SUDO_DEBUG_WARN, "%s: unable to restart I/O log", __func__);
/* XXX - structured error message so client can send from beginning */
@ -520,6 +540,11 @@ handle_alert(AlertMessage *msg, struct connection_closure *closure)
}
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received AlertMessage", __func__);
if (closure->relay_closure != NULL) {
/* Forward AlertMessage to connected relay. */
debug_return_bool(relay_alert(msg, closure));
}
if (msg->info_msgs != NULL && msg->n_info_msgs != 0) {
closure->evlog = evlog_new(NULL, msg->info_msgs,
msg->n_info_msgs, closure);
@ -540,7 +565,7 @@ handle_alert(AlertMessage *msg, struct connection_closure *closure)
}
static bool
handle_iobuf(int iofd, IoBuffer *msg, struct connection_closure *closure)
handle_iobuf(int iofd, IoBuffer *iobuf, struct connection_closure *closure)
{
debug_decl(handle_iobuf, SUDO_DEBUG_UTIL);
@ -559,8 +584,13 @@ handle_iobuf(int iofd, IoBuffer *msg, struct connection_closure *closure)
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received IoBuffer", __func__);
if (closure->relay_closure != NULL) {
/* Forward IoBuffer to connected relay. */
debug_return_bool(relay_iobuf(iofd, iobuf, closure));
}
/* Store IoBuffer in log. */
if (store_iobuf(iofd, msg, closure) == -1) {
if (store_iobuf(iofd, iobuf, closure) == -1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"failed to store IoBuffer");
closure->errstr = _("error writing IoBuffer");
@ -682,6 +712,7 @@ handle_client_message(uint8_t *buf, size_t len,
bool ret = false;
debug_decl(handle_client_message, SUDO_DEBUG_UTIL);
/* TODO: can we extract type_case without unpacking for relay case? */
msg = client_message__unpack(NULL, len, buf);
if (msg == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
@ -777,7 +808,10 @@ server_shutdown(struct sudo_event_base *base)
TAILQ_FOREACH_SAFE(closure, &connections, entries, next) {
closure->state = SHUTDOWN;
sudo_ev_del(base, closure->read_ev);
if (closure->log_io) {
if (closure->relay_closure != NULL) {
/* Connection being relayed, check for pending I/O. */
relay_shutdown(closure);
} else if (closure->log_io) {
/* Schedule final commit point for the connection. */
if (sudo_ev_add(base, closure->commit_ev, &tv, false) == -1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
@ -1072,7 +1106,7 @@ close_connection:
/*
* Format and schedule a commit_point message.
*/
static bool
bool
schedule_commit_point(TimeSpec *commit_point,
struct connection_closure *closure)
{
@ -1130,12 +1164,19 @@ server_commit_cb(int unused, int what, void *v)
* When we enter the event loop the ServerHello message will be written
* and any pending ClientMessage will be read.
*/
static bool
bool
start_protocol(struct connection_closure *closure)
{
const struct timespec *timeout = logsrvd_conf_get_sock_timeout();
debug_decl(start_protocol, SUDO_DEBUG_UTIL);
if (closure->relay_closure != NULL && closure->relay_closure->relays != NULL) {
/* No longer need the stashed relays list. */
address_list_delref(closure->relay_closure->relays);
closure->relay_closure->relays = NULL;
closure->relay_closure->relay_addr = NULL;
}
if (!fmt_hello_message(closure))
debug_return_bool(false);
@ -1296,8 +1337,13 @@ tls_handshake_cb(int fd, int what, void *v)
SSL_get_cipher(closure->ssl));
/* Start the actual protocol now that the TLS handshake is complete. */
if (!start_protocol(closure))
goto bad;
if (logsrvd_conf_relay() != NULL) {
if (!connect_relay(closure))
goto bad;
} else {
if (!start_protocol(closure))
goto bad;
}
debug_return;
bad:
@ -1387,7 +1433,8 @@ new_connection(int sock, bool tls, const struct sockaddr *sa,
sizeof(closure->ipaddr));
#endif /* HAVE_STRUCT_IN6_ADDR */
} else {
sudo_fatal("%s", U_("unable to get remote IP addr"));
errno = EAFNOSUPPORT;
sudo_warn("%s", U_("unable to get remote IP addr"));
goto bad;
}
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
@ -1430,8 +1477,13 @@ new_connection(int sock, bool tls, const struct sockaddr *sa,
#endif
/* If no TLS handshake, start the protocol immediately. */
if (!tls) {
if (!start_protocol(closure))
goto bad;
if (logsrvd_conf_relay() != NULL) {
if (!connect_relay(closure))
goto bad;
} else {
if (!start_protocol(closure))
goto bad;
}
}
debug_return_bool(true);

View File

@ -47,6 +47,7 @@
*/
enum connection_status {
INITIAL,
CONNECTING,
RUNNING,
EXITED,
SHUTDOWN,
@ -54,11 +55,31 @@ enum connection_status {
ERROR
};
/*
* Per-connection relay state.
*/
struct relay_closure {
struct server_address_list *relays;
struct server_address *relay_addr;
struct sudo_event *read_ev;
struct sudo_event *write_ev;
struct sudo_event *connect_ev;
struct connection_buffer read_buf;
struct connection_buffer_list write_bufs;
int sock;
#ifdef HAVE_STRUCT_IN6_ADDR
char ipaddr[INET6_ADDRSTRLEN];
#else
char ipaddr[INET_ADDRSTRLEN];
#endif
};
/*
* Per-connection state.
*/
struct connection_closure {
TAILQ_ENTRY(connection_closure) entries;
struct relay_closure *relay_closure;
struct eventlog *evlog;
struct timespec elapsed_time;
struct connection_buffer read_buf;
@ -74,19 +95,19 @@ struct connection_closure {
#endif
const char *errstr;
struct iolog_file iolog_files[IOFD_MAX];
int iolog_dir_fd;
int sock;
enum connection_status state;
bool tls;
bool log_io;
bool read_instead_of_write;
bool write_instead_of_read;
bool temporary_write_event;
int iolog_dir_fd;
int sock;
#ifdef HAVE_STRUCT_IN6_ADDR
char ipaddr[INET6_ADDRSTRLEN];
#else
char ipaddr[INET_ADDRSTRLEN];
#endif
enum connection_status state;
};
union sockaddr_union {
@ -147,14 +168,24 @@ int store_suspend(CommandSuspend *msg, struct connection_closure *closure);
int store_winsize(ChangeWindowSize *msg, struct connection_closure *closure);
void iolog_close_all(struct connection_closure *closure);
/* logsrvd.c */
bool start_protocol(struct connection_closure *closure);
void connection_closure_free(struct connection_closure *closure);
bool schedule_commit_point(TimeSpec *commit_point, struct connection_closure *closure);
bool fmt_log_id_message(const char *id, struct connection_closure *closure);
bool fmt_error_message(const char *errstr, struct connection_closure *closure);
struct connection_buffer *get_free_buf(struct connection_closure *closure);
/* logsrvd_conf.c */
bool logsrvd_conf_read(const char *path);
const char *logsrvd_conf_iolog_dir(void);
const char *logsrvd_conf_iolog_file(void);
struct server_address_list *logsrvd_conf_listen_address(void);
struct server_address_list *logsrvd_conf_relay(void);
bool logsrvd_conf_tcp_keepalive(void);
const char *logsrvd_conf_pid_file(void);
struct timespec *logsrvd_conf_get_sock_timeout(void);
struct timespec *logsrvd_conf_get_connect_timeout(void);
#if defined(HAVE_OPENSSL)
const struct logsrvd_tls_config *logsrvd_get_tls_config(void);
struct logsrvd_tls_runtime *logsrvd_get_tls_runtime(void);
@ -163,4 +194,15 @@ mode_t logsrvd_conf_iolog_mode(void);
void address_list_addref(struct server_address_list *);
void address_list_delref(struct server_address_list *);
/* logsrvd_relay.c */
void relay_closure_free(struct relay_closure *relay_closure);
bool connect_relay(struct connection_closure *closure);
bool relay_accept(AcceptMessage *msg, struct connection_closure *closure);
bool relay_reject(RejectMessage *msg, struct connection_closure *closure);
bool relay_exit(ExitMessage *msg, struct connection_closure *closure);
bool relay_restart(RestartMessage *msg, struct connection_closure *closure);
bool relay_alert(AlertMessage *msg, struct connection_closure *closure);
bool relay_iobuf(int iofd, IoBuffer *iobuf, struct connection_closure *closure);
bool relay_shutdown(struct connection_closure *closure);
#endif /* SUDO_LOGSRVD_H */

View File

@ -84,7 +84,9 @@ struct address_list_container {
static struct logsrvd_config {
struct logsrvd_config_server {
struct address_list_container addresses;
struct address_list_container relays;
struct timespec timeout;
struct timespec connect_timeout;
bool tcp_keepalive;
char *pid_file;
#if defined(HAVE_OPENSSL)
@ -147,6 +149,12 @@ logsrvd_conf_listen_address(void)
return &logsrvd_config->server.addresses.addrs;
}
struct server_address_list *
logsrvd_conf_relay(void)
{
return &logsrvd_config->server.relays.addrs;
}
bool
logsrvd_conf_tcp_keepalive(void)
{
@ -169,6 +177,16 @@ logsrvd_conf_get_sock_timeout(void)
return NULL;
}
struct timespec *
logsrvd_conf_get_connect_timeout(void)
{
if (sudo_timespecisset(&logsrvd_config->server.connect_timeout)) {
return &(logsrvd_config->server.connect_timeout);
}
return NULL;
}
#if defined(HAVE_OPENSSL)
const struct logsrvd_tls_config *
logsrvd_get_tls_config(void)
@ -380,6 +398,12 @@ cb_listen_address(struct logsrvd_config *config, const char *str)
return append_address(&config->server.addresses.addrs, str);
}
static bool
cb_relay(struct logsrvd_config *config, const char *str)
{
return append_address(&config->server.relays.addrs, str);
}
static bool
cb_timeout(struct logsrvd_config *config, const char *str)
{
@ -396,6 +420,22 @@ cb_timeout(struct logsrvd_config *config, const char *str)
debug_return_bool(true);
}
static bool
cb_connect_timeout(struct logsrvd_config *config, const char *str)
{
int timeout;
const char* errstr;
debug_decl(cb_connect_timeout, SUDO_DEBUG_UTIL);
timeout = sudo_strtonum(str, 0, UINT_MAX, &errstr);
if (errstr != NULL)
debug_return_bool(false);
config->server.connect_timeout.tv_sec = timeout;
debug_return_bool(true);
}
static bool
cb_keepalive(struct logsrvd_config *config, const char *str)
{
@ -719,7 +759,9 @@ address_list_delref(struct server_address_list *al)
static struct logsrvd_config_entry server_conf_entries[] = {
{ "listen_address", cb_listen_address },
{ "relay", cb_relay },
{ "timeout", cb_timeout },
{ "connect_timeout", cb_connect_timeout },
{ "tcp_keepalive", cb_keepalive },
{ "pid_file", cb_pid_file },
#if defined(HAVE_OPENSSL)
@ -932,6 +974,7 @@ logsrvd_conf_free(struct logsrvd_config *config)
/* struct logsrvd_config_server */
address_list_delref(&config->server.addresses.addrs);
address_list_delref(&config->server.relays.addrs);
free(config->server.pid_file);
/* struct logsrvd_config_iolog */
@ -976,6 +1019,8 @@ logsrvd_conf_alloc(void)
/* Server defaults */
TAILQ_INIT(&config->server.addresses.addrs);
config->server.addresses.refcnt = 1;
TAILQ_INIT(&config->server.relays.addrs);
config->server.relays.refcnt = 1;
config->server.timeout.tv_sec = DEFAULT_SOCKET_TIMEOUT_SEC;
config->server.tcp_keepalive = true;
config->server.pid_file = strdup(_PATH_SUDO_LOGSRVD_PID);

1023
logsrvd/logsrvd_relay.c Normal file

File diff suppressed because it is too large Load Diff