Skip to content

Commit

Permalink
Add json_compact log type for compact/minified JSON.
Browse files Browse the repository at this point in the history
The "json_compact" log type logs one event per line in compact/minified
JSON format.  GitHub issue #357.
  • Loading branch information
millert committed Mar 8, 2024
1 parent b3ade1c commit 1debad3
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 46 deletions.
45 changes: 39 additions & 6 deletions docs/sudo_logsrvd.conf.man.in
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
39 changes: 33 additions & 6 deletions docs/sudo_logsrvd.conf.mdoc.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
27 changes: 22 additions & 5 deletions docs/sudoers.man.in
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down
24 changes: 20 additions & 4 deletions docs/sudoers.mdoc.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion include/sudo_eventlog.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
52 changes: 31 additions & 21 deletions lib/eventlog/eventlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -1205,11 +1206,12 @@ do_logfile_sudo(const char *logline, const struct eventlog *evlog,
}

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;
Expand All @@ -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;

Expand All @@ -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 */

Expand Down Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions logsrvd/logsrvd_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions plugins/sudoers/def_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
};

Expand Down
1 change: 1 addition & 0 deletions plugins/sudoers/def_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ enum def_tuple {
kernel,
sudo,
json,
json_compact,
dso,
trace
};
2 changes: 1 addition & 1 deletion plugins/sudoers/def_data.in
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
15 changes: 14 additions & 1 deletion plugins/sudoers/logging.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 1debad3

Please sign in to comment.