Table *overview_table,
AnalyzeSecurityFlags flags,
unsigned threshold,
- JsonVariant *policy) {
+ JsonVariant *policy,
+ PagerFlags pager_flags,
+ JsonFormatFlags json_format_flags) {
static const struct {
uint64_t exposure;
int r;
if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT)) {
- details_table = table_new(" ", "name", "description", "weight", "badness", "range", "exposure");
+ details_table = table_new(" ", "name", "json_field", "description", "weight", "badness", "range", "exposure");
if (!details_table)
return log_oom();
+ r = table_set_json_field_name(details_table, 0, "set");
+ if (r < 0)
+ return log_error_errno(r, "Failed to set JSON field name of column 0: %m");
+
(void) table_set_sort(details_table, (size_t) 3, (size_t) 1);
(void) table_set_reverse(details_table, 3, true);
if (getenv_bool("SYSTEMD_ANALYZE_DEBUG") <= 0)
- (void) table_set_display(details_table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 6);
+ (void) table_set_display(details_table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 7);
}
for (i = 0; i < ELEMENTSOF(security_assessor_table); i++) {
}
if (details_table) {
- const char *checkmark, *description, *color = NULL;
- const char *id = a->id;
+ const char *description, *color = NULL;
+ int checkmark;
if (badness == UINT64_MAX) {
- checkmark = " ";
+ checkmark = -1;
description = access_description_na(a, policy);
color = NULL;
} else if (badness == a->range) {
- checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
+ checkmark = 0;
description = access_description_bad(a, policy);
color = ansi_highlight_red();
} else if (badness == 0) {
- checkmark = special_glyph(SPECIAL_GLYPH_CHECK_MARK);
+ checkmark = 1;
description = access_description_good(a, policy);
color = ansi_highlight_green();
} else {
- checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
+ checkmark = 0;
description = NULL;
color = ansi_highlight_red();
}
if (d)
description = d;
- if (json_variant_by_key(policy, a->json_field) != NULL)
- id = a->json_field;
+ if (checkmark < 0) {
+ r = table_add_many(details_table, TABLE_EMPTY);
+ if (r < 0)
+ return table_log_add_error(r);
+ } else {
+ r = table_add_many(details_table,
+ TABLE_BOOLEAN_CHECKMARK, checkmark > 0,
+ TABLE_SET_MINIMUM_WIDTH, 1,
+ TABLE_SET_MAXIMUM_WIDTH, 1,
+ TABLE_SET_ELLIPSIZE_PERCENT, 0,
+ TABLE_SET_COLOR, color);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
r = table_add_many(details_table,
- TABLE_STRING, checkmark,
- TABLE_SET_MINIMUM_WIDTH, 1,
- TABLE_SET_MAXIMUM_WIDTH, 1,
- TABLE_SET_ELLIPSIZE_PERCENT, 0,
- TABLE_SET_COLOR, color,
- TABLE_STRING, id, TABLE_SET_URL, a->url,
+ TABLE_STRING, a->id, TABLE_SET_URL, a->url,
+ TABLE_STRING, a->json_field,
TABLE_STRING, description,
TABLE_UINT64, weight, TABLE_SET_ALIGN_PERCENT, 100,
TABLE_UINT64, badness, TABLE_SET_ALIGN_PERCENT, 100,
TableCell *cell;
uint64_t x;
- assert_se(weight = table_get_at(details_table, row, 3));
- assert_se(badness = table_get_at(details_table, row, 4));
- assert_se(range = table_get_at(details_table, row, 5));
+ assert_se(weight = table_get_at(details_table, row, 4));
+ assert_se(badness = table_get_at(details_table, row, 5));
+ assert_se(range = table_get_at(details_table, row, 6));
if (*badness == UINT64_MAX || *badness == 0)
continue;
- assert_se(cell = table_get_cell(details_table, row, 6));
+ assert_se(cell = table_get_cell(details_table, row, 7));
x = DIV_ROUND_UP(DIV_ROUND_UP(*badness * *weight * 100U, *range), weight_sum);
xsprintf(buf, "%" PRIu64 ".%" PRIu64, x / 10, x % 10);
return log_error_errno(r, "Failed to update cell in table: %m");
}
- r = table_print(details_table, stdout);
+ if (json_format_flags & JSON_FORMAT_OFF) {
+ r = table_hide_column_from_display(details_table, (size_t) 2);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set columns to display: %m");
+ }
+
+ r = table_print_with_pager(details_table, json_format_flags, pager_flags, /* show_header= */true);
if (r < 0)
return log_error_errno(r, "Failed to output table: %m");
}
assert(i < ELEMENTSOF(badness_table));
- if (details_table) {
+ if (details_table && (json_format_flags & JSON_FORMAT_OFF)) {
_cleanup_free_ char *clickable = NULL;
const char *name;
Table *overview_table,
AnalyzeSecurityFlags flags,
unsigned threshold,
- JsonVariant *policy) {
+ JsonVariant *policy,
+ PagerFlags pager_flags,
+ JsonFormatFlags json_format_flags) {
_cleanup_(security_info_freep) SecurityInfo *info = security_info_new();
if (!info)
if (r < 0)
return r;
- r = assess(info, overview_table, flags, threshold, policy);
+ r = assess(info, overview_table, flags, threshold, policy, pager_flags, json_format_flags);
if (r < 0)
return r;
return 0;
}
-static int offline_security_check(Unit *u, unsigned threshold, JsonVariant *policy) {
+static int offline_security_check(Unit *u,
+ unsigned threshold,
+ JsonVariant *policy,
+ PagerFlags pager_flags,
+ JsonFormatFlags json_format_flags) {
+
_cleanup_(table_unrefp) Table *overview_table = NULL;
AnalyzeSecurityFlags flags = 0;
_cleanup_(security_info_freep) SecurityInfo *info = NULL;
if (r < 0)
return r;
- return assess(info, overview_table, flags, threshold, policy);
+ return assess(info, overview_table, flags, threshold, policy, pager_flags, json_format_flags);
}
static int offline_security_checks(char **filenames,
bool check_man,
bool run_generators,
unsigned threshold,
- const char *root) {
+ const char *root,
+ PagerFlags pager_flags,
+ JsonFormatFlags json_format_flags) {
const ManagerTestRunFlags flags =
MANAGER_TEST_RUN_MINIMAL |
}
for (size_t i = 0; i < count; i++) {
- k = offline_security_check(units[i], threshold, policy);
+ k = offline_security_check(units[i], threshold, policy, pager_flags, json_format_flags);
if (k < 0 && r == 0)
r = k;
}
bool offline,
unsigned threshold,
const char *root,
+ JsonFormatFlags json_format_flags,
+ PagerFlags pager_flags,
AnalyzeSecurityFlags flags) {
_cleanup_(table_unrefp) Table *overview_table = NULL;
assert(bus);
if (offline)
- return offline_security_checks(units, policy, scope, check_man, run_generators, threshold, root);
+ return offline_security_checks(units, policy, scope, check_man, run_generators, threshold, root, pager_flags, json_format_flags);
if (strv_length(units) != 1) {
overview_table = table_new("unit", "exposure", "predicate", "happy");
flags |= ANALYZE_SECURITY_SHORT|ANALYZE_SECURITY_ONLY_LOADED|ANALYZE_SECURITY_ONLY_LONG_RUNNING;
STRV_FOREACH(i, list) {
- r = analyze_security_one(bus, *i, overview_table, flags, threshold, policy);
+ r = analyze_security_one(bus, *i, overview_table, flags, threshold, policy, pager_flags, json_format_flags);
if (r < 0 && ret >= 0)
ret = r;
}
} else
name = mangled;
- r = analyze_security_one(bus, name, overview_table, flags, threshold, policy);
+ r = analyze_security_one(bus, name, overview_table, flags, threshold, policy, pager_flags, json_format_flags);
if (r < 0 && ret >= 0)
ret = r;
}
fflush(stdout);
}
- r = table_print(overview_table, stdout);
+ r = table_print_with_pager(overview_table, json_format_flags, pager_flags, /* show_header= */true);
if (r < 0)
return log_error_errno(r, "Failed to output table: %m");
}
-
return ret;
}
static unsigned arg_iterations = 1;
static usec_t arg_base_time = USEC_INFINITY;
static char *arg_unit = NULL;
+static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
arg_offline,
arg_threshold,
arg_root,
+ arg_json_format_flags,
+ arg_pager_flags,
/*flags=*/ 0);
}
" --version Show package version\n"
" --security-policy=PATH Use custom JSON security policy instead\n"
" of built-in one\n"
+ " --json=pretty|short|off Generate JSON output of the security\n"
+ " analysis table\n"
" --no-pager Do not pipe output into a pager\n"
" --system Operate on system systemd instance\n"
" --user Operate on user systemd instance\n"
ARG_OFFLINE,
ARG_THRESHOLD,
ARG_SECURITY_POLICY,
+ ARG_JSON,
};
static const struct option options[] = {
{ "iterations", required_argument, NULL, ARG_ITERATIONS },
{ "base-time", required_argument, NULL, ARG_BASE_TIME },
{ "unit", required_argument, NULL, 'U' },
+ { "json", required_argument, NULL, ARG_JSON },
{}
};
return r;
break;
+ case ARG_JSON:
+ r = parse_json_argument(optarg, &arg_json_format_flags);
+ if (r <= 0)
+ return r;
+ break;
+
case ARG_ITERATIONS:
r = safe_atou(optarg, &arg_iterations);
if (r < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --offline= is only supported for security right now.");
+ if (arg_json_format_flags != JSON_FORMAT_OFF && !streq_ptr(argv[optind], "security"))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Option --json= is only supported for security right now.");
+
if (arg_threshold != 100 && !streq_ptr(argv[optind], "security"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --threshold= is only supported for security right now.");