diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c index f2a105bc4..1ea0a3bca 100644 --- a/plugins/sudoers/def_data.c +++ b/plugins/sudoers/def_data.c @@ -513,6 +513,10 @@ struct sudo_defs_types sudo_defs_table[] = { "log_server_timeout", T_TIMEOUT|T_BOOL, N_("Sudo log server timeout in seconds: %u"), NULL, + }, { + "log_server_keepalive", T_FLAG, + N_("Enable SO_KEEPALIVE socket option on the socket connected to the logserver"), + NULL, }, { "log_server_cabundle", T_STR|T_BOOL|T_PATH, N_("Path to the audit server's CA bundle file: %s"), diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h index ad0ebde42..f130e13ab 100644 --- a/plugins/sudoers/def_data.h +++ b/plugins/sudoers/def_data.h @@ -236,15 +236,17 @@ #define def_log_servers (sudo_defs_table[I_LOG_SERVERS].sd_un.list) #define I_LOG_SERVER_TIMEOUT 118 #define def_log_server_timeout (sudo_defs_table[I_LOG_SERVER_TIMEOUT].sd_un.ival) -#define I_LOG_SERVER_CABUNDLE 119 +#define I_LOG_SERVER_KEEPALIVE 119 +#define def_log_server_keepalive (sudo_defs_table[I_LOG_SERVER_KEEPALIVE].sd_un.flag) +#define I_LOG_SERVER_CABUNDLE 120 #define def_log_server_cabundle (sudo_defs_table[I_LOG_SERVER_CABUNDLE].sd_un.str) -#define I_LOG_SERVER_PEER_CERT 120 +#define I_LOG_SERVER_PEER_CERT 121 #define def_log_server_peer_cert (sudo_defs_table[I_LOG_SERVER_PEER_CERT].sd_un.str) -#define I_LOG_SERVER_PEER_KEY 121 +#define I_LOG_SERVER_PEER_KEY 122 #define def_log_server_peer_key (sudo_defs_table[I_LOG_SERVER_PEER_KEY].sd_un.str) -#define I_RUNAS_ALLOW_UNKNOWN_ID 122 +#define I_RUNAS_ALLOW_UNKNOWN_ID 123 #define def_runas_allow_unknown_id (sudo_defs_table[I_RUNAS_ALLOW_UNKNOWN_ID].sd_un.flag) -#define I_RUNAS_CHECK_SHELL 123 +#define I_RUNAS_CHECK_SHELL 124 #define def_runas_check_shell (sudo_defs_table[I_RUNAS_CHECK_SHELL].sd_un.flag) enum def_tuple { diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in index 35fd4fb65..f6a1dd8d4 100644 --- a/plugins/sudoers/def_data.in +++ b/plugins/sudoers/def_data.in @@ -372,6 +372,9 @@ log_servers log_server_timeout T_TIMEOUT|T_BOOL "Sudo log server timeout in seconds: %u" +log_server_keepalive + T_FLAG + "Enable SO_KEEPALIVE socket option on the socket connected to the logserver" log_server_cabundle T_STR|T_BOOL|T_PATH "Path to the audit server's CA bundle file: %s" diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c index a1063bfe9..5a3f5e37e 100644 --- a/plugins/sudoers/defaults.c +++ b/plugins/sudoers/defaults.c @@ -564,6 +564,7 @@ init_defaults(void) def_compress_io = true; #endif def_log_server_timeout = 30; + def_log_server_keepalive = true; def_ignore_audit_errors = true; def_ignore_iolog_errors = false; def_ignore_logfile_errors = true; diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c index 6edf41260..6de440e2b 100644 --- a/plugins/sudoers/iolog.c +++ b/plugins/sudoers/iolog.c @@ -366,6 +366,15 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[], TIME_T_MAX, NULL); continue; } + if (strncmp(*cur, "log_server_keepalive=", sizeof("log_server_keepalive=") - 1) == 0) { + int val = sudo_strtobool(*cur + sizeof("log_server_keepalive=") - 1); + if (val != -1) { + details->tcp_keepalive = val; + } else { + details->tcp_keepalive = true; + } + continue; + } #if defined(HAVE_OPENSSL) if (strncmp(*cur, "log_server_cabundle=", sizeof("log_server_cabundle=") - 1) == 0) { details->ca_bundle = *cur + sizeof("log_server_cabundle=") - 1; @@ -594,7 +603,7 @@ sudoers_io_open_remote(void) debug_decl(sudoers_io_open_remote, SUDOERS_DEBUG_PLUGIN); /* Connect to log server. */ - sock = log_server_connect(iolog_details.log_servers, + sock = log_server_connect(iolog_details.log_servers, iolog_details.tcp_keepalive, &iolog_details.server_timeout, &connected_server); if (sock == -1) { /* TODO: support offline logs if server unreachable */ diff --git a/plugins/sudoers/iolog_client.c b/plugins/sudoers/iolog_client.c index e1b77d447..2528978e0 100644 --- a/plugins/sudoers/iolog_client.c +++ b/plugins/sudoers/iolog_client.c @@ -131,8 +131,8 @@ done: * Returns open socket or -1 on error. */ static int -connect_server(const char *host, const char *port, struct timespec *timo, - const char **reason) +connect_server(const char *host, const char *port, bool tcp_keepalive, + struct timespec *timo, const char **reason) { struct addrinfo hints, *res, *res0; const char *cause = NULL; @@ -166,6 +166,20 @@ connect_server(const char *host, const char *port, struct timespec *timo, sock = -1; continue; } + + if (tcp_keepalive) { + int keepalive = 1; + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive, + sizeof(keepalive)) == -1) { + cause = "setsockopt(SO_KEEPALIVE)"; + save_errno = errno; + close(sock); + errno = save_errno; + sock = -1; + continue; + } + } + if (timed_connect(sock, res->ai_addr, res->ai_addrlen, timo) == -1) { cause = "connect"; save_errno = errno; @@ -189,8 +203,8 @@ connect_server(const char *host, const char *port, struct timespec *timo, * Returns a socket with O_NONBLOCK and close-on-exec flags set. */ int -log_server_connect(struct sudoers_str_list *servers, struct timespec *timo, - struct sudoers_string **connected_server) +log_server_connect(struct sudoers_str_list *servers, bool tcp_keepalive, + struct timespec *timo, struct sudoers_string **connected_server) { struct sudoers_string *server; char *copy, *host, *port; @@ -204,7 +218,7 @@ log_server_connect(struct sudoers_str_list *servers, struct timespec *timo, free(copy); continue; } - sock = connect_server(host, port, timo, &cause); + sock = connect_server(host, port, tcp_keepalive, timo, &cause); free(copy); if (sock != -1) { int flags = fcntl(sock, F_GETFL, 0); diff --git a/plugins/sudoers/iolog_plugin.h b/plugins/sudoers/iolog_plugin.h index 52aa26265..279049a76 100644 --- a/plugins/sudoers/iolog_plugin.h +++ b/plugins/sudoers/iolog_plugin.h @@ -61,6 +61,7 @@ struct iolog_details { char **user_env; struct sudoers_str_list *log_servers; struct timespec server_timeout; + bool tcp_keepalive; #if defined(HAVE_OPENSSL) char *ca_bundle; char *cert_file; @@ -156,7 +157,7 @@ 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_suspend(struct client_closure *closure, const char *signame, struct timespec *delay); bool fmt_winsize(struct client_closure *closure, unsigned int lines, unsigned int cols, struct timespec *delay); -int log_server_connect(struct sudoers_str_list *servers, struct timespec *timo, struct sudoers_string **connected_server); +int log_server_connect(struct sudoers_str_list *servers, bool tcp_keepalive, struct timespec *timo, struct sudoers_string **connected_server); void client_closure_free(struct client_closure *closure); #endif /* SUDOERS_IOLOG_CLIENT_H */ diff --git a/plugins/sudoers/policy.c b/plugins/sudoers/policy.c index fe7e9cfc1..ec92d2e9d 100644 --- a/plugins/sudoers/policy.c +++ b/plugins/sudoers/policy.c @@ -735,6 +735,10 @@ sudoers_policy_exec_setup(char *argv[], char *envp[], mode_t cmnd_umask, goto oom; } + if ((command_info[info_len++] = sudo_new_key_val("log_server_keepalive", + def_log_server_keepalive ? "true" : "false")) == NULL) + goto oom; + if (def_log_server_cabundle != NULL) { if ((command_info[info_len++] = sudo_new_key_val("log_server_cabundle", def_log_server_cabundle)) == NULL) goto oom;