From 28d6771d248dc80137ce17261fc913a19a4c34d7 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Tue, 27 Oct 2020 15:26:02 -0600 Subject: [PATCH] Add log_format sudoers setting to select sudo or json format logs. Defaults to sudo-format logs. --- doc/sudoers.man.in | 45 +++++++++++++++++++++++++++++++++---- doc/sudoers.mdoc.in | 42 ++++++++++++++++++++++++++++++---- plugins/sudoers/def_data.c | 10 +++++++++ plugins/sudoers/def_data.h | 6 ++++- plugins/sudoers/def_data.in | 4 ++++ plugins/sudoers/logging.c | 33 ++++++++++++++++++--------- plugins/sudoers/sudoers.c | 11 +++++++++ 7 files changed, 132 insertions(+), 19 deletions(-) diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in index c8c409a3e..9760c13ee 100644 --- a/doc/sudoers.man.in +++ b/doc/sudoers.man.in @@ -25,7 +25,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.TH "SUDOERS" "@mansectform@" "September 25, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDOERS" "@mansectform@" "October 27, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -4416,6 +4416,33 @@ The default value is \fIany\fR. .RE .TP 14n +log_format +The event log format. +Supported log formats are: +.PP +.RS 14n +.PD 0 +.TP 10n +json +Logs in JSON format. +JSON log entries contain the full user details as well as the execution +environment if the command was allowed. +.PD +.TP 10n +sudo +Traditional sudo-style logs, see +\fILOG FORMAT\fR +for a description of the log file format. +.PP +This setting affects logs sent via +syslog(3) +as well as the file specified by the +\fIlogfile\fR +setting, if any. +The default value is +\fIsudo\fR. +.RE +.TP 14n logfile Path to the \fBsudo\fR @@ -4896,9 +4923,19 @@ The group provider plugin API is described in detail in sudo_plugin(@mansectform@). .SH "LOG FORMAT" \fBsudoers\fR -can log events using either -syslog(3) -or a simple log file. +can log events in either JSON or +\fIsudo\fR +format, +this section describes the +\fIsudo\fR +log format. +Depending on +\fIsudoers\fR +configuration, +\fBsudoers\fR +can log events via +syslog(3), +to a local log file, or both. The log format is almost identical in both cases. .SS "Accepted command log entries" Commands that sudo runs are logged using the following format (split diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in index 0a05d7ee9..29886a4d5 100644 --- a/doc/sudoers.mdoc.in +++ b/doc/sudoers.mdoc.in @@ -24,7 +24,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.Dd September 25, 2020 +.Dd October 27, 2020 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -4129,6 +4129,30 @@ Negating the option results in a value of being used. The default value is .Em any . +.It log_format +The event log format. +Supported log formats are: +.Bl -tag -width 8n +.It json +Logs in JSON format. +JSON log entries contain the full user details as well as the execution +environment if the command was allowed. +Due to limitations of the protocol, JSON events sent via +.Em syslog +may be truncated. +.It sudo +Traditional sudo-style logs, see +.Sx "LOG FORMAT" +for a description of the log file format. +.El +.Pp +This setting affects logs sent via +.Xr syslog 3 +as well as the file specified by the +.Em logfile +setting, if any. +The default value is +.Em sudo . .It logfile Path to the .Nm sudo @@ -4574,9 +4598,19 @@ The group provider plugin API is described in detail in .Xr sudo_plugin @mansectform@ . .Sh LOG FORMAT .Nm -can log events using either -.Xr syslog 3 -or a simple log file. +can log events in either JSON or +.Em sudo +format, +this section describes the +.Em sudo +log format. +Depending on +.Em sudoers +configuration, +.Nm +can log events via +.Xr syslog 3 , +to a local log file, or both. The log format is almost identical in both cases. .Ss Accepted command log entries Commands that sudo runs are logged using the following format (split diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c index 3eab739ec..0f7de2c42 100644 --- a/plugins/sudoers/def_data.c +++ b/plugins/sudoers/def_data.c @@ -38,6 +38,12 @@ static struct def_values def_data_timestamp_type[] = { { NULL, 0 }, }; +static struct def_values def_data_log_format[] = { + { "sudo", sudo }, + { "json", json }, + { NULL, 0 }, +}; + struct sudo_defs_types sudo_defs_table[] = { { "syslog", T_LOGFAC|T_BOOL, @@ -559,6 +565,10 @@ struct sudo_defs_types sudo_defs_table[] = { "runchroot", T_STR|T_BOOL|T_CHPATH, N_("Root directory to change to before executing the command: %s"), NULL, + }, { + "log_format", T_TUPLE, + N_("The format of logs to produce: %s"), + def_data_log_format, }, { NULL, 0, NULL } diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h index f3958e764..3c6a66815 100644 --- a/plugins/sudoers/def_data.h +++ b/plugins/sudoers/def_data.h @@ -260,6 +260,8 @@ #define def_runcwd (sudo_defs_table[I_RUNCWD].sd_un.str) #define I_RUNCHROOT 129 #define def_runchroot (sudo_defs_table[I_RUNCHROOT].sd_un.str) +#define I_LOG_FORMAT 130 +#define def_log_format (sudo_defs_table[I_LOG_FORMAT].sd_un.tuple) enum def_tuple { never, @@ -271,5 +273,7 @@ enum def_tuple { global, ppid, tty, - kernel + kernel, + sudo, + json }; diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in index e730aee4d..52cd4443a 100644 --- a/plugins/sudoers/def_data.in +++ b/plugins/sudoers/def_data.in @@ -405,3 +405,7 @@ runcwd runchroot T_STR|T_BOOL|T_CHPATH "Root directory to change to before executing the command: %s" +log_format + T_TUPLE + "The format of logs to produce: %s" + sudo json diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c index f30e1e371..e93cefd74 100644 --- a/plugins/sudoers/logging.c +++ b/plugins/sudoers/logging.c @@ -510,6 +510,8 @@ sudoers_log_open(int type, const char *log_file) bool uid_changed; FILE *fp = NULL; mode_t oldmask; + int fd, flags; + char *omode; debug_decl(sudoers_log_open, SUDOERS_DEBUG_DEFAULTS); switch (type) { @@ -517,21 +519,32 @@ sudoers_log_open(int type, const char *log_file) openlog("sudo", def_syslog_pid ? LOG_PID : 0, def_syslog); break; case EVLOG_FILE: - /* Open log file as root, mode 0600. */ + /* Open log file as root, mode 0600 (cannot append to JSON). */ + if (def_log_format == json) { + flags = O_RDWR|O_CREAT; + omode = "w"; + } else { + flags = O_WRONLY|O_APPEND|O_CREAT; + omode = "a"; + } oldmask = umask(S_IRWXG|S_IRWXO); uid_changed = set_perms(PERM_ROOT); - fp = fopen(log_file, "a"); + fd = open(log_file, flags, S_IRUSR|S_IWUSR); if (uid_changed && !restore_perms()) { - if (fp != NULL) { - fclose(fp); - fp = NULL; + if (fd != -1) { + close(fd); + fd = -1; } } (void) umask(oldmask); - if (fp == NULL && !warned) { - warned = true; - log_warning(SLOG_SEND_MAIL|SLOG_NO_LOG, - N_("unable to open log file: %s"), log_file); + if (fd == -1 || (fp = fdopen(fd, omode)) == NULL) { + if (!warned) { + warned = true; + log_warning(SLOG_SEND_MAIL|SLOG_NO_LOG, + N_("unable to open log file: %s"), log_file); + } + if (fd != -1) + close(fd); } break; default: @@ -591,7 +604,7 @@ init_eventlog_config(void) logtype |= EVLOG_FILE; eventlog_set_type(logtype); - eventlog_set_format(EVLOG_SUDO); + eventlog_set_format(def_log_format == sudo ? EVLOG_SUDO : EVLOG_JSON); eventlog_set_syslog_acceptpri(def_syslog_goodpri); eventlog_set_syslog_rejectpri(def_syslog_badpri); eventlog_set_syslog_alertpri(def_syslog_badpri); diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 7323a3ea5..b32c40b03 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -1426,6 +1426,16 @@ cb_logfile(const union sudo_defs_val *sd_un) debug_return_bool(true); } +static bool +cb_log_format(const union sudo_defs_val *sd_un) +{ + debug_decl(cb_log_format, SUDOERS_DEBUG_PLUGIN); + + eventlog_set_format(sd_un->tuple == sudo ? EVLOG_SUDO : EVLOG_JSON); + + debug_return_bool(true); +} + static bool cb_syslog(const union sudo_defs_val *sd_un) { @@ -1601,6 +1611,7 @@ set_callbacks(void) sudo_defs_table[I_LOGLINELEN].callback = cb_loglinelen; sudo_defs_table[I_LOG_HOST].callback = cb_log_host; sudo_defs_table[I_LOGFILE].callback = cb_logfile; + sudo_defs_table[I_LOG_FORMAT].callback = cb_log_format; sudo_defs_table[I_LOG_YEAR].callback = cb_log_year; sudo_defs_table[I_MAILERPATH].callback = cb_mailerpath; sudo_defs_table[I_MAILERFLAGS].callback = cb_mailerflags;