2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-22 09:57:41 +00:00

Add json_compact log type for compact/minified JSON.

The "json_compact" log type logs one event per line in compact/minified
JSON format.  GitHub issue #357.
This commit is contained in:
Todd C. Miller 2024-03-08 16:31:39 -07:00
parent b3ade1c5f9
commit 1debad3bec
12 changed files with 180 additions and 46 deletions

View File

@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" 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 .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@ -682,15 +682,48 @@ Defaults to
.TP 6n .TP 6n
log_format = string log_format = string
The event log format. The event log format.
Supported log formats are Supported log formats are:
\(lqsudo\(rq .PP
for traditional sudo-style logs and .RS 6n
\(lqjson\(rq .PD 0
for JSON-format logs. .TP 6n
json
Log events in JSON format.
The JSON log entries contain the full contents of the accept, reject, exit The JSON log entries contain the full contents of the accept, reject, exit
and alert messages. 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 The default value is
\fIsudo\fR. \fIsudo\fR.
.RE
.SS "syslog" .SS "syslog"
The The
\fIsyslog\fR \fIsyslog\fR

View File

@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd January 16, 2023 .Dd March 8, 2024
.Dt SUDO_LOGSRVD.CONF @mansectform@ .Dt SUDO_LOGSRVD.CONF @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@ -611,13 +611,40 @@ Defaults to
.Em false . .Em false .
.It log_format = string .It log_format = string
The event log format. The event log format.
Supported log formats are Supported log formats are:
.Dq sudo .Bl -tag -width 4n
for traditional sudo-style logs and .It json
.Dq json Log events in JSON format.
for JSON-format logs.
The JSON log entries contain the full contents of the accept, reject, exit The JSON log entries contain the full contents of the accept, reject, exit
and alert messages. 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 The default value is
.Em sudo . .Em sudo .
.El .El

View File

@ -25,7 +25,7 @@
.nr BA @BAMAN@ .nr BA @BAMAN@
.nr LC @LCMAN@ .nr LC @LCMAN@
.nr PS @PSMAN@ .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 .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@ -5381,18 +5381,35 @@ Supported log formats are:
.PD 0 .PD 0
.TP 6n .TP 6n
json json
Logs in JSON format. Log events in JSON format.
JSON log entries contain the full user details as well as the execution JSON log entries contain the full user details as well as the execution
environment if the command was allowed. 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 Due to limitations of the protocol, JSON events sent via
\fIsyslog\fR \fIsyslog\fR
may be truncated. may be truncated.
.PD
.TP 6n .TP 6n
sudo sudo
Traditional sudo-style logs, see Log events in traditional sudo-style format, see
\fIEVENT LOGGING\fR \fIEVENT LOGGING\fR
for a description of the log file format. for details.
.PP .PP
This setting affects logs sent via This setting affects logs sent via
syslog(3) syslog(3)

View File

@ -25,7 +25,7 @@
.nr BA @BAMAN@ .nr BA @BAMAN@
.nr LC @LCMAN@ .nr LC @LCMAN@
.nr PS @PSMAN@ .nr PS @PSMAN@
.Dd December 19, 2023 .Dd March 8, 2024
.Dt SUDOERS @mansectform@ .Dt SUDOERS @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@ -5054,16 +5054,32 @@ The event log format.
Supported log formats are: Supported log formats are:
.Bl -tag -width 4n .Bl -tag -width 4n
.It json .It json
Logs in JSON format. Log events in JSON format.
JSON log entries contain the full user details as well as the execution JSON log entries contain the full user details as well as the execution
environment if the command was allowed. 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 Due to limitations of the protocol, JSON events sent via
.Em syslog .Em syslog
may be truncated. may be truncated.
.It sudo .It sudo
Traditional sudo-style logs, see Log events in traditional sudo-style format, see
.Sx "EVENT LOGGING" .Sx "EVENT LOGGING"
for a description of the log file format. for details.
.El .El
.Pp .Pp
This setting affects logs sent via This setting affects logs sent via

View File

@ -43,7 +43,8 @@ enum event_type {
/* Supported eventlog formats. */ /* Supported eventlog formats. */
enum eventlog_format { enum eventlog_format {
EVLOG_SUDO, EVLOG_SUDO,
EVLOG_JSON EVLOG_JSON,
EVLOG_JSON_COMPACT
}; };
/* Eventlog flag values. */ /* Eventlog flag values. */

View File

@ -1131,6 +1131,7 @@ do_syslog(int event_type, int flags, struct eventlog_args *args,
ret = do_syslog_sudo(pri, lbuf.buf, evlog); ret = do_syslog_sudo(pri, lbuf.buf, evlog);
break; break;
case EVLOG_JSON: case EVLOG_JSON:
case EVLOG_JSON_COMPACT:
ret = do_syslog_json(pri, event_type, args, evlog); ret = do_syslog_json(pri, event_type, args, evlog);
break; break;
default: default:
@ -1205,11 +1206,12 @@ done:
} }
static bool static bool
do_logfile_json(int event_type, struct eventlog_args *args, do_logfile_json(enum eventlog_format format, int event_type,
const struct eventlog *evlog) struct eventlog_args *args, const struct eventlog *evlog)
{ {
const struct eventlog_config *evl_conf = eventlog_getconf(); const struct eventlog_config *evl_conf = eventlog_getconf();
const char *logfile = evl_conf->logpath; const char *logfile = evl_conf->logpath;
const bool compact = format == EVLOG_JSON_COMPACT;
struct stat sb; struct stat sb;
char *json_str; char *json_str;
int ret = false; 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) if ((fp = evl_conf->open_log(EVLOG_FILE, logfile)) == NULL)
debug_return_bool(false); 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) if (json_str == NULL)
goto done; goto done;
@ -1229,25 +1231,32 @@ do_logfile_json(int event_type, struct eventlog_args *args,
goto done; goto done;
} }
/* Note: assumes file ends in "\n}\n" */ if (!compact) {
if (fstat(fileno(fp), &sb) == -1) { /* Note: assumes file ends in "\n}\n" */
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, if (fstat(fileno(fp), &sb) == -1) {
"unable to stat %s", logfile); sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
goto done; "unable to stat %s", logfile);
} goto done;
if (sb.st_size == 0) { }
/* New file */ if (sb.st_size == 0) {
putc('{', fp); /* New file */
} else if (fseeko(fp, -3, SEEK_END) == 0) { putc('{', fp);
/* Continue file, overwrite the final "\n}\n" */ } else if (fseeko(fp, -3, SEEK_END) == 0) {
putc(',', fp); /* 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 { } else {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO, /* Compact (minified) JSON records, one per line. */
"unable to seek %s", logfile); putc('{', fp);
goto done; fputs(json_str, fp);
fputs("}\n", fp);
} }
fputs(json_str, fp);
fputs("\n}\n", fp); /* close JSON */
fflush(fp); fflush(fp);
/* XXX - check for file error and recover */ /* 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); args->event_time);
break; break;
case EVLOG_JSON: 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; break;
default: default:
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,

View File

@ -903,6 +903,8 @@ cb_eventlog_format(struct logsrvd_config *config, const char *str, size_t offset
if (strcmp(str, "json") == 0) if (strcmp(str, "json") == 0)
config->eventlog.log_format = EVLOG_JSON; 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) else if (strcmp(str, "sudo") == 0)
config->eventlog.log_format = EVLOG_SUDO; config->eventlog.log_format = EVLOG_SUDO;
else else

View File

@ -41,6 +41,7 @@ static struct def_values def_data_timestamp_type[] = {
static struct def_values def_data_log_format[] = { static struct def_values def_data_log_format[] = {
{ "sudo", sudo }, { "sudo", sudo },
{ "json", json }, { "json", json },
{ "json_compact", json_compact },
{ NULL, 0 }, { NULL, 0 },
}; };

View File

@ -338,6 +338,7 @@ enum def_tuple {
kernel, kernel,
sudo, sudo,
json, json,
json_compact,
dso, dso,
trace trace
}; };

View File

@ -426,7 +426,7 @@ runchroot
log_format log_format
T_TUPLE T_TUPLE
"The format of logs to produce: %s" "The format of logs to produce: %s"
sudo json sudo json json_compact
selinux selinux
T_FLAG T_FLAG
"Enable SELinux RBAC support" "Enable SELinux RBAC support"

View File

@ -1132,16 +1132,29 @@ sudoers_log_close(int type, FILE *fp)
void void
init_eventlog_config(void) init_eventlog_config(void)
{ {
enum eventlog_format format;
int logtype = 0; int logtype = 0;
debug_decl(init_eventlog_config, SUDOERS_DEBUG_LOGGING); 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) if (def_syslog)
logtype |= EVLOG_SYSLOG; logtype |= EVLOG_SYSLOG;
if (def_logfile) if (def_logfile)
logtype |= EVLOG_FILE; logtype |= EVLOG_FILE;
eventlog_set_type(logtype); 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_acceptpri(def_syslog_goodpri);
eventlog_set_syslog_rejectpri(def_syslog_badpri); eventlog_set_syslog_rejectpri(def_syslog_badpri);
eventlog_set_syslog_alertpri(def_syslog_badpri); eventlog_set_syslog_alertpri(def_syslog_badpri);

View File

@ -228,9 +228,22 @@ static bool
cb_log_format(struct sudoers_context *ctx, const char *file, cb_log_format(struct sudoers_context *ctx, const char *file,
int line, int column, const union sudo_defs_val *sd_un, int op) 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); 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); debug_return_bool(true);
} }