1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
34 #include <sys/ioctl.h>
39 #include <systemd/sd-journal.h>
43 #include "path-util.h"
46 #include "logs-show.h"
48 #include "journal-internal.h"
49 #include "journal-def.h"
50 #include "journal-verify.h"
51 #include "journal-authenticate.h"
52 #include "journal-qrcode.h"
55 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
57 static OutputMode arg_output = OUTPUT_SHORT;
58 static bool arg_follow = false;
59 static bool arg_show_all = false;
60 static bool arg_no_pager = false;
61 static int arg_lines = -1;
62 static bool arg_no_tail = false;
63 static bool arg_quiet = false;
64 static bool arg_merge = false;
65 static bool arg_this_boot = false;
66 static const char *arg_directory = NULL;
67 static int arg_priorities = 0xFF;
68 static const char *arg_verify_key = NULL;
70 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
80 } arg_action = ACTION_SHOW;
82 static int help(void) {
84 printf("%s [OPTIONS...] [MATCH]\n\n"
85 "Send control commands to or query the journal.\n\n"
86 " -h --help Show this help\n"
87 " --version Show package version\n"
88 " --no-pager Do not pipe output into a pager\n"
89 " -a --all Show all fields, including long and unprintable\n"
90 " -f --follow Follow journal\n"
91 " -n --lines[=INTEGER] Number of journal entries to show\n"
92 " --no-tail Show all lines, even in follow mode\n"
93 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
94 " verbose, export, json, json-pretty, cat)\n"
95 " -q --quiet Don't show privilege warning\n"
96 " -m --merge Show entries from all available journals\n"
97 " -b --this-boot Show data only from current boot\n"
98 " -D --directory=PATH Show journal files from directory\n"
99 " -p --priority=RANGE Show only messages within the specified priority range\n\n"
101 " --new-id128 Generate a new 128 Bit ID\n"
102 " --header Show journal header information\n"
103 " --disk-usage Show total disk usage\n"
105 " --setup-keys Generate new FSS key pair\n"
106 " --interval=TIME Time interval for changing the FSS sealing key\n"
107 " --verify Verify journal file consistency\n"
108 " --verify-key=KEY Specify FSS verification key\n"
110 , program_invocation_short_name);
115 static int parse_argv(int argc, char *argv[]) {
130 static const struct option options[] = {
131 { "help", no_argument, NULL, 'h' },
132 { "version" , no_argument, NULL, ARG_VERSION },
133 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
134 { "follow", no_argument, NULL, 'f' },
135 { "output", required_argument, NULL, 'o' },
136 { "all", no_argument, NULL, 'a' },
137 { "lines", optional_argument, NULL, 'n' },
138 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
139 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
140 { "quiet", no_argument, NULL, 'q' },
141 { "merge", no_argument, NULL, 'm' },
142 { "this-boot", no_argument, NULL, 'b' },
143 { "directory", required_argument, NULL, 'D' },
144 { "header", no_argument, NULL, ARG_HEADER },
145 { "priority", no_argument, NULL, 'p' },
146 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
147 { "interval", required_argument, NULL, ARG_INTERVAL },
148 { "verify", no_argument, NULL, ARG_VERIFY },
149 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
150 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
159 while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:", options, NULL)) >= 0) {
168 puts(PACKAGE_STRING);
170 puts(SYSTEMD_FEATURES);
179 signal(SIGWINCH, columns_cache_reset);
183 arg_output = output_mode_from_string(optarg);
184 if (arg_output < 0) {
185 log_error("Unknown output '%s'.", optarg);
197 r = safe_atoi(optarg, &arg_lines);
198 if (r < 0 || arg_lines < 0) {
199 log_error("Failed to parse lines '%s'", optarg);
212 arg_action = ACTION_NEW_ID128;
224 arg_this_boot = true;
228 arg_directory = optarg;
232 arg_action = ACTION_PRINT_HEADER;
236 arg_action = ACTION_VERIFY;
240 arg_action = ACTION_DISK_USAGE;
245 arg_action = ACTION_SETUP_KEYS;
250 arg_action = ACTION_VERIFY;
251 arg_verify_key = optarg;
256 r = parse_usec(optarg, &arg_interval);
257 if (r < 0 || arg_interval <= 0) {
258 log_error("Failed to parse sealing key change interval: %s", optarg);
266 log_error("Forward-secure sealing not available.");
273 dots = strstr(optarg, "..");
279 a = strndup(optarg, dots - optarg);
283 from = log_level_from_string(a);
284 to = log_level_from_string(dots + 2);
287 if (from < 0 || to < 0) {
288 log_error("Failed to parse log level range %s", optarg);
295 for (i = from; i <= to; i++)
296 arg_priorities |= 1 << i;
298 for (i = to; i <= from; i++)
299 arg_priorities |= 1 << i;
305 p = log_level_from_string(optarg);
307 log_error("Unknown log level %s", optarg);
313 for (i = 0; i <= p; i++)
314 arg_priorities |= 1 << i;
324 log_error("Unknown option code %c", c);
329 if (arg_follow && !arg_no_tail && arg_lines < 0)
335 static bool on_tty(void) {
338 /* Note that this is invoked relatively early, before we start
339 * the pager. That means the value we return reflects whether
340 * we originally were started on a tty, not if we currently
341 * are. But this is intended, since we want colour and so on
342 * when run in our own pager. */
344 if (_unlikely_(t < 0))
345 t = isatty(STDOUT_FILENO) > 0;
350 static int generate_new_id128(void) {
355 r = sd_id128_randomize(&id);
357 log_error("Failed to generate ID: %s", strerror(-r));
361 printf("As string:\n"
362 SD_ID128_FORMAT_STR "\n\n"
364 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
366 "#define MESSAGE_XYZ SD_ID128_MAKE(",
367 SD_ID128_FORMAT_VAL(id),
368 SD_ID128_FORMAT_VAL(id));
370 for (i = 0; i < 16; i++)
371 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
373 fputs(")\n", stdout);
378 static int add_matches(sd_journal *j, char **args) {
384 STRV_FOREACH(i, args) {
387 r = sd_journal_add_disjunction(j);
388 else if (path_is_absolute(*i)) {
393 p = canonicalize_file_name(*i);
396 if (stat(path, &st) < 0) {
398 log_error("Couldn't stat file: %m");
402 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
403 t = strappend("_EXE=", path);
404 else if (S_ISCHR(st.st_mode))
405 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
406 else if (S_ISBLK(st.st_mode))
407 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
410 log_error("File is not a device node, regular file or is not executable: %s", *i);
419 r = sd_journal_add_match(j, t, 0);
422 r = sd_journal_add_match(j, *i, 0);
425 log_error("Failed to add match '%s': %s", *i, strerror(-r));
433 static int add_this_boot(sd_journal *j) {
434 char match[9+32+1] = "_BOOT_ID=";
443 r = sd_id128_get_boot(&boot_id);
445 log_error("Failed to get boot id: %s", strerror(-r));
449 sd_id128_to_string(boot_id, match + 9);
450 r = sd_journal_add_match(j, match, strlen(match));
452 log_error("Failed to add match: %s", strerror(-r));
459 static int add_priorities(sd_journal *j) {
460 char match[] = "PRIORITY=0";
465 if (arg_priorities == 0xFF)
468 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
469 if (arg_priorities & (1 << i)) {
470 match[sizeof(match)-2] = '0' + i;
472 log_info("adding match %s", match);
474 r = sd_journal_add_match(j, match, strlen(match));
476 log_error("Failed to add match: %s", strerror(-r));
484 static int setup_keys(void) {
486 size_t mpk_size, seed_size, state_size, i;
487 uint8_t *mpk, *seed, *state;
489 int fd = -1, r, attr = 0;
490 sd_id128_t machine, boot;
491 char *p = NULL, *k = NULL;
495 r = sd_id128_get_machine(&machine);
497 log_error("Failed to get machine ID: %s", strerror(-r));
501 r = sd_id128_get_boot(&boot);
503 log_error("Failed to get boot ID: %s", strerror(-r));
507 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
508 SD_ID128_FORMAT_VAL(machine)) < 0)
511 if (access(p, F_OK) >= 0) {
512 log_error("Sealing key file %s exists already.", p);
517 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
518 SD_ID128_FORMAT_VAL(machine)) < 0) {
523 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
524 mpk = alloca(mpk_size);
526 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
527 seed = alloca(seed_size);
529 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
530 state = alloca(state_size);
532 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
534 log_error("Failed to open /dev/random: %m");
539 log_info("Generating seed...");
540 l = loop_read(fd, seed, seed_size, true);
541 if (l < 0 || (size_t) l != seed_size) {
542 log_error("Failed to read random seed: %s", strerror(EIO));
547 log_info("Generating key pair...");
548 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
550 log_info("Generating sealing key...");
551 FSPRG_GenState0(state, mpk, seed, seed_size);
553 assert(arg_interval > 0);
555 n = now(CLOCK_REALTIME);
558 close_nointr_nofail(fd);
559 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
561 log_error("Failed to open %s: %m", k);
566 /* Enable secure remove, exclusion from dump, synchronous
567 * writing and in-place updating */
568 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
569 log_warning("FS_IOC_GETFLAGS failed: %m");
571 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
573 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
574 log_warning("FS_IOC_SETFLAGS failed: %m");
577 memcpy(h.signature, "KSHHRHLP", 8);
578 h.machine_id = machine;
580 h.header_size = htole64(sizeof(h));
581 h.start_usec = htole64(n * arg_interval);
582 h.interval_usec = htole64(arg_interval);
583 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
584 h.fsprg_state_size = htole64(state_size);
586 l = loop_write(fd, &h, sizeof(h), false);
587 if (l < 0 || (size_t) l != sizeof(h)) {
588 log_error("Failed to write header: %s", strerror(EIO));
593 l = loop_write(fd, state, state_size, false);
594 if (l < 0 || (size_t) l != state_size) {
595 log_error("Failed to write state: %s", strerror(EIO));
600 if (link(k, p) < 0) {
601 log_error("Failed to link file: %m");
606 if (isatty(STDOUT_FILENO)) {
609 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
610 "the following local file. This key file is automatically updated when the\n"
611 "sealing key is advanced. It should not be used on multiple hosts.\n"
615 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
616 "at a safe location and should not be saved locally on disk.\n"
617 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
620 for (i = 0; i < seed_size; i++) {
621 if (i > 0 && i % 3 == 0)
623 printf("%02x", ((uint8_t*) seed)[i]);
626 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
628 if (isatty(STDOUT_FILENO)) {
629 char tsb[FORMAT_TIMESPAN_MAX], *hn;
632 ANSI_HIGHLIGHT_OFF "\n"
633 "The sealing key is automatically changed every %s.\n",
634 format_timespan(tsb, sizeof(tsb), arg_interval));
636 hn = gethostname_malloc();
639 hostname_cleanup(hn);
640 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
642 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
645 /* If this is not an UTF-8 system don't print any QR codes */
646 setlocale(LC_CTYPE, "");
648 if (streq_ptr(nl_langinfo(CODESET), "UTF-8")) {
649 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
650 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
660 close_nointr_nofail(fd);
671 log_error("Forward-secure sealing not available.");
676 static int verify(sd_journal *j) {
683 log_show_color(true);
685 HASHMAP_FOREACH(f, j->files, i) {
687 usec_t from, to, total;
690 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
691 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
694 k = journal_file_verify(f, arg_verify_key, &from, &to, &total, true);
696 /* If the key was invalid give up right-away. */
699 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
702 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
703 log_info("PASS: %s", f->path);
705 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
707 log_info("=> Validated from %s to %s, final %s entries not sealed.",
708 format_timestamp(a, sizeof(a), from),
709 format_timestamp(b, sizeof(b), to),
710 format_timespan(c, sizeof(c), total > to ? total - to : 0));
711 } else if (total > 0)
712 log_info("=> No sealing yet, %s of entries not sealed.",
713 format_timespan(c, sizeof(c), total));
715 log_info("=> No sealing yet, no entries in file.");
723 int main(int argc, char *argv[]) {
725 sd_journal *j = NULL;
727 bool need_seek = false;
728 sd_id128_t previous_boot_id;
729 bool previous_boot_id_valid = false;
732 log_parse_environment();
735 r = parse_argv(argc, argv);
739 if (arg_action == ACTION_NEW_ID128) {
740 r = generate_new_id128();
744 if (arg_action == ACTION_SETUP_KEYS) {
750 r = sd_journal_open_directory(&j, arg_directory, 0);
752 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
755 log_error("Failed to open journal: %s", strerror(-r));
759 if (arg_action == ACTION_VERIFY) {
764 if (arg_action == ACTION_PRINT_HEADER) {
765 journal_print_header(j);
770 if (arg_action == ACTION_DISK_USAGE) {
772 char sbytes[FORMAT_BYTES_MAX];
774 r = sd_journal_get_usage(j, &bytes);
778 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
784 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
785 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
790 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
791 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
793 if (geteuid() != 0 && in_group("adm") <= 0) {
794 log_error("No access to messages. Only users in the group 'adm' can see messages.");
800 r = add_this_boot(j);
804 r = add_matches(j, argv + optind);
808 r = add_priorities(j);
814 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
816 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
818 log_error("Failed to get cutoff: %s", strerror(-r));
824 printf("Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start));
826 printf("Logs begin at %s, end at %s.\n",
827 format_timestamp(start_buf, sizeof(start_buf), start),
828 format_timestamp(end_buf, sizeof(end_buf), end));
832 if (arg_lines >= 0) {
833 r = sd_journal_seek_tail(j);
835 log_error("Failed to seek to tail: %s", strerror(-r));
839 r = sd_journal_previous_skip(j, arg_lines);
841 r = sd_journal_seek_head(j);
843 log_error("Failed to seek to head: %s", strerror(-r));
847 r = sd_journal_next(j);
851 log_error("Failed to iterate through journal: %s", strerror(-r));
856 have_pager = !arg_no_pager && !arg_follow && pager_open();
861 arg_show_all * OUTPUT_SHOW_ALL |
862 have_pager * OUTPUT_FULL_WIDTH |
863 on_tty() * OUTPUT_COLOR;
866 r = sd_journal_next(j);
868 log_error("Failed to iterate through journal: %s", strerror(-r));
879 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
881 if (previous_boot_id_valid &&
882 !sd_id128_equal(boot_id, previous_boot_id))
883 printf(ANSI_HIGHLIGHT_ON "----- Reboot -----" ANSI_HIGHLIGHT_OFF "\n");
885 previous_boot_id = boot_id;
886 previous_boot_id_valid = true;
892 r = output_journal(j, arg_output, line, 0, flags);
902 r = sd_journal_wait(j, (uint64_t) -1);
904 log_error("Couldn't wait for log event: %s", strerror(-r));
915 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;