diff --git a/docs/sudo_logsrvd.conf.man.in b/docs/sudo_logsrvd.conf.man.in index 2b5826adf..5faf05722 100644 --- a/docs/sudo_logsrvd.conf.man.in +++ b/docs/sudo_logsrvd.conf.man.in @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.TH "SUDO_LOGSRVD.CONF" "@mansectform@" "January 16, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDO_LOGSRVD.CONF" "@mansectform@" "March 8, 2024" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -682,15 +682,48 @@ Defaults to .TP 6n log_format = string The event log format. -Supported log formats are -\(lqsudo\(rq -for traditional sudo-style logs and -\(lqjson\(rq -for JSON-format logs. +Supported log formats are: +.PP +.RS 6n +.PD 0 +.TP 6n +json +Log events in JSON format. The JSON log entries contain the full contents of the accept, reject, exit and alert messages. +When logging to a file, the entire file is treated as a single JSON +object consisting of multiple events, each event spanning multiple lines. +When logging via +\fIsyslog\fR, +events are stored in compact (minified) format, described below. +.PD +.TP 6n +json_compact +Log events in compact (minified) JSON format. +Each event is written as a separate JSON object on single line without +extraneous white space. +When logging via +\fIsyslog\fR, +there is no difference between the +\fIjson\fR +and +\fIjson_compact\fR +formats. +Due to limitations of the protocol, JSON events sent via +\fIsyslog\fR +may be truncated. +.TP 6n +sudo +Log events in traditional sudo-style log format. +See the +\fIEVENT LOGGING\fR +section in +sudoers(@mansectform@) +for details. +.PP The default value is \fIsudo\fR. +.RE .SS "syslog" The \fIsyslog\fR diff --git a/docs/sudo_logsrvd.conf.mdoc.in b/docs/sudo_logsrvd.conf.mdoc.in index 8fee88c34..64b6de567 100644 --- a/docs/sudo_logsrvd.conf.mdoc.in +++ b/docs/sudo_logsrvd.conf.mdoc.in @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd January 16, 2023 +.Dd March 8, 2024 .Dt SUDO_LOGSRVD.CONF @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -611,13 +611,40 @@ Defaults to .Em false . .It log_format = string The event log format. -Supported log formats are -.Dq sudo -for traditional sudo-style logs and -.Dq json -for JSON-format logs. +Supported log formats are: +.Bl -tag -width 4n +.It json +Log events in JSON format. The JSON log entries contain the full contents of the accept, reject, exit and alert messages. +When logging to a file, the entire file is treated as a single JSON +object consisting of multiple events, each event spanning multiple lines. +When logging via +.Em syslog , +events are stored in compact (minified) format, described below. +.It json_compact +Log events in compact (minified) JSON format. +Each event is written as a separate JSON object on single line without +extraneous white space. +When logging via +.Em syslog , +there is no difference between the +.Em json +and +.Em json_compact +formats. +Due to limitations of the protocol, JSON events sent via +.Em syslog +may be truncated. +.It sudo +Log events in traditional sudo-style log format. +See the +.Em "EVENT LOGGING" +section in +.Xr sudoers @mansectform@ +for details. +.El +.Pp The default value is .Em sudo . .El diff --git a/docs/sudoers.man.in b/docs/sudoers.man.in index f229d1faf..9d5abf0ec 100644 --- a/docs/sudoers.man.in +++ b/docs/sudoers.man.in @@ -25,7 +25,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.TH "SUDOERS" "@mansectform@" "December 19, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDOERS" "@mansectform@" "March 8, 2024" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -5381,18 +5381,35 @@ Supported log formats are: .PD 0 .TP 6n json -Logs in JSON format. +Log events in JSON format. JSON log entries contain the full user details as well as the execution environment if the command was allowed. +When logging to a file, the entire file is treated as a single JSON +object consisting of multiple events, each event spanning multiple lines. +When logging via +\fIsyslog\fR, +events are stored in compact (minified) format, described below. +.PD +.TP 6n +json_compact +Log events in compact (minified) JSON format. +Each event is written as a separate JSON object on single line without +extraneous white space. +When logging via +\fIsyslog\fR, +there is no difference between the +\fIjson\fR +and +\fIjson_compact\fR +formats. Due to limitations of the protocol, JSON events sent via \fIsyslog\fR may be truncated. -.PD .TP 6n sudo -Traditional sudo-style logs, see +Log events in traditional sudo-style format, see \fIEVENT LOGGING\fR -for a description of the log file format. +for details. .PP This setting affects logs sent via syslog(3) diff --git a/docs/sudoers.mdoc.in b/docs/sudoers.mdoc.in index 67d61b032..278c53517 100644 --- a/docs/sudoers.mdoc.in +++ b/docs/sudoers.mdoc.in @@ -25,7 +25,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.Dd December 19, 2023 +.Dd March 8, 2024 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -5054,16 +5054,32 @@ The event log format. Supported log formats are: .Bl -tag -width 4n .It json -Logs in JSON format. +Log events in JSON format. JSON log entries contain the full user details as well as the execution environment if the command was allowed. +When logging to a file, the entire file is treated as a single JSON +object consisting of multiple events, each event spanning multiple lines. +When logging via +.Em syslog , +events are stored in compact (minified) format, described below. +.It json_compact +Log events in compact (minified) JSON format. +Each event is written as a separate JSON object on single line without +extraneous white space. +When logging via +.Em syslog , +there is no difference between the +.Em json +and +.Em json_compact +formats. Due to limitations of the protocol, JSON events sent via .Em syslog may be truncated. .It sudo -Traditional sudo-style logs, see +Log events in traditional sudo-style format, see .Sx "EVENT LOGGING" -for a description of the log file format. +for details. .El .Pp This setting affects logs sent via diff --git a/include/sudo_eventlog.h b/include/sudo_eventlog.h index 8f5a40f69..48e3a122f 100644 --- a/include/sudo_eventlog.h +++ b/include/sudo_eventlog.h @@ -43,7 +43,8 @@ enum event_type { /* Supported eventlog formats. */ enum eventlog_format { EVLOG_SUDO, - EVLOG_JSON + EVLOG_JSON, + EVLOG_JSON_COMPACT }; /* Eventlog flag values. */ diff --git a/lib/eventlog/eventlog.c b/lib/eventlog/eventlog.c index 75b1e297d..92747ea13 100644 --- a/lib/eventlog/eventlog.c +++ b/lib/eventlog/eventlog.c @@ -1131,6 +1131,7 @@ do_syslog(int event_type, int flags, struct eventlog_args *args, ret = do_syslog_sudo(pri, lbuf.buf, evlog); break; case EVLOG_JSON: + case EVLOG_JSON_COMPACT: ret = do_syslog_json(pri, event_type, args, evlog); break; default: @@ -1205,11 +1206,12 @@ done: } static bool -do_logfile_json(int event_type, struct eventlog_args *args, - const struct eventlog *evlog) +do_logfile_json(enum eventlog_format format, int event_type, + struct eventlog_args *args, const struct eventlog *evlog) { const struct eventlog_config *evl_conf = eventlog_getconf(); const char *logfile = evl_conf->logpath; + const bool compact = format == EVLOG_JSON_COMPACT; struct stat sb; char *json_str; int ret = false; @@ -1219,7 +1221,7 @@ do_logfile_json(int event_type, struct eventlog_args *args, if ((fp = evl_conf->open_log(EVLOG_FILE, logfile)) == NULL) debug_return_bool(false); - json_str = format_json(event_type, args, evlog, false); + json_str = format_json(event_type, args, evlog, compact); if (json_str == NULL) goto done; @@ -1229,25 +1231,32 @@ do_logfile_json(int event_type, struct eventlog_args *args, goto done; } - /* Note: assumes file ends in "\n}\n" */ - if (fstat(fileno(fp), &sb) == -1) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, - "unable to stat %s", logfile); - goto done; - } - if (sb.st_size == 0) { - /* New file */ - putc('{', fp); - } else if (fseeko(fp, -3, SEEK_END) == 0) { - /* Continue file, overwrite the final "\n}\n" */ - putc(',', fp); + if (!compact) { + /* Note: assumes file ends in "\n}\n" */ + if (fstat(fileno(fp), &sb) == -1) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, + "unable to stat %s", logfile); + goto done; + } + if (sb.st_size == 0) { + /* New file */ + putc('{', fp); + } else if (fseeko(fp, -3, SEEK_END) == 0) { + /* Continue file, overwrite the final "\n}\n" */ + putc(',', fp); + } else { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, + "unable to seek %s", logfile); + goto done; + } + fputs(json_str, fp); + fputs("\n}\n", fp); /* close JSON */ } else { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, - "unable to seek %s", logfile); - goto done; + /* Compact (minified) JSON records, one per line. */ + putc('{', fp); + fputs(json_str, fp); + fputs("}\n", fp); } - fputs(json_str, fp); - fputs("\n}\n", fp); /* close JSON */ fflush(fp); /* XXX - check for file error and recover */ @@ -1294,7 +1303,8 @@ do_logfile(int event_type, int flags, struct eventlog_args *args, args->event_time); break; case EVLOG_JSON: - ret = do_logfile_json(event_type, args, evlog); + case EVLOG_JSON_COMPACT: + ret = do_logfile_json(evl_conf->format, event_type, args, evlog); break; default: sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, diff --git a/logsrvd/logsrvd_conf.c b/logsrvd/logsrvd_conf.c index ed125cd5c..92cc44ac9 100644 --- a/logsrvd/logsrvd_conf.c +++ b/logsrvd/logsrvd_conf.c @@ -903,6 +903,8 @@ cb_eventlog_format(struct logsrvd_config *config, const char *str, size_t offset if (strcmp(str, "json") == 0) config->eventlog.log_format = EVLOG_JSON; + else if (strcmp(str, "json_compact") == 0) + config->eventlog.log_format = EVLOG_JSON_COMPACT; else if (strcmp(str, "sudo") == 0) config->eventlog.log_format = EVLOG_SUDO; else diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c index f7ee4c80d..538e7bd79 100644 --- a/plugins/sudoers/def_data.c +++ b/plugins/sudoers/def_data.c @@ -41,6 +41,7 @@ static struct def_values def_data_timestamp_type[] = { static struct def_values def_data_log_format[] = { { "sudo", sudo }, { "json", json }, + { "json_compact", json_compact }, { NULL, 0 }, }; diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h index f6ecdc3a4..b03363b6d 100644 --- a/plugins/sudoers/def_data.h +++ b/plugins/sudoers/def_data.h @@ -338,6 +338,7 @@ enum def_tuple { kernel, sudo, json, + json_compact, dso, trace }; diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in index 7c284f994..16c71d96c 100644 --- a/plugins/sudoers/def_data.in +++ b/plugins/sudoers/def_data.in @@ -426,7 +426,7 @@ runchroot log_format T_TUPLE "The format of logs to produce: %s" - sudo json + sudo json json_compact selinux T_FLAG "Enable SELinux RBAC support" diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c index e18cb6b6d..17e9cf002 100644 --- a/plugins/sudoers/logging.c +++ b/plugins/sudoers/logging.c @@ -1132,16 +1132,29 @@ sudoers_log_close(int type, FILE *fp) void init_eventlog_config(void) { + enum eventlog_format format; int logtype = 0; debug_decl(init_eventlog_config, SUDOERS_DEBUG_LOGGING); + switch (def_log_format) { + case json: + format = EVLOG_JSON; + break; + case json_compact: + format = EVLOG_JSON_COMPACT; + break; + default: + format = EVLOG_SUDO; + break; + } + if (def_syslog) logtype |= EVLOG_SYSLOG; if (def_logfile) logtype |= EVLOG_FILE; eventlog_set_type(logtype); - eventlog_set_format(def_log_format == sudo ? EVLOG_SUDO : EVLOG_JSON); + eventlog_set_format(format); 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_cb.c b/plugins/sudoers/sudoers_cb.c index 4fc4c54b1..3d46a7a15 100644 --- a/plugins/sudoers/sudoers_cb.c +++ b/plugins/sudoers/sudoers_cb.c @@ -228,9 +228,22 @@ static bool cb_log_format(struct sudoers_context *ctx, const char *file, int line, int column, const union sudo_defs_val *sd_un, int op) { + enum eventlog_format format; debug_decl(cb_log_format, SUDOERS_DEBUG_PLUGIN); - eventlog_set_format(sd_un->tuple == sudo ? EVLOG_SUDO : EVLOG_JSON); + switch (sd_un->tuple) { + case json: + format = EVLOG_JSON; + break; + case json_compact: + format = EVLOG_JSON_COMPACT; + break; + default: + format = EVLOG_SUDO; + break; + } + + eventlog_set_format(format); debug_return_bool(true); }