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_cursor = NULL;
67 static const char *arg_directory = NULL;
68 static int arg_priorities = 0xFF;
69 static const char *arg_verify_key = NULL;
71 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
81 } arg_action = ACTION_SHOW;
83 static int help(void) {
85 printf("%s [OPTIONS...] [MATCH]\n\n"
86 "Send control commands to or query the journal.\n\n"
87 " -h --help Show this help\n"
88 " --version Show package version\n"
89 " --no-pager Do not pipe output into a pager\n"
90 " -a --all Show all fields, including long and unprintable\n"
91 " -c --cursor=CURSOR Jump to the specified cursor\n"
92 " -f --follow Follow journal\n"
93 " -n --lines[=INTEGER] Number of journal entries to show\n"
94 " --no-tail Show all lines, even in follow mode\n"
95 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
96 " verbose, export, json, json-pretty, cat)\n"
97 " -q --quiet Don't show privilege warning\n"
98 " -m --merge Show entries from all available journals\n"
99 " -b --this-boot Show data only from current boot\n"
100 " -D --directory=PATH Show journal files from directory\n"
101 " -p --priority=RANGE Show only messages within the specified priority range\n\n"
103 " --new-id128 Generate a new 128 Bit ID\n"
104 " --header Show journal header information\n"
105 " --disk-usage Show total disk usage\n"
107 " --setup-keys Generate new FSS key pair\n"
108 " --interval=TIME Time interval for changing the FSS sealing key\n"
109 " --verify Verify journal file consistency\n"
110 " --verify-key=KEY Specify FSS verification key\n"
112 , program_invocation_short_name);
117 static int parse_argv(int argc, char *argv[]) {
132 static const struct option options[] = {
133 { "help", no_argument, NULL, 'h' },
134 { "version" , no_argument, NULL, ARG_VERSION },
135 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
136 { "follow", no_argument, NULL, 'f' },
137 { "output", required_argument, NULL, 'o' },
138 { "all", no_argument, NULL, 'a' },
139 { "lines", optional_argument, NULL, 'n' },
140 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
141 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
142 { "quiet", no_argument, NULL, 'q' },
143 { "merge", no_argument, NULL, 'm' },
144 { "this-boot", no_argument, NULL, 'b' },
145 { "directory", required_argument, NULL, 'D' },
146 { "header", no_argument, NULL, ARG_HEADER },
147 { "priority", no_argument, NULL, 'p' },
148 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
149 { "interval", required_argument, NULL, ARG_INTERVAL },
150 { "verify", no_argument, NULL, ARG_VERIFY },
151 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
152 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
153 { "cursor", required_argument, NULL, 'c' },
162 while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:", options, NULL)) >= 0) {
171 puts(PACKAGE_STRING);
173 puts(SYSTEMD_FEATURES);
182 signal(SIGWINCH, columns_cache_reset);
186 arg_output = output_mode_from_string(optarg);
187 if (arg_output < 0) {
188 log_error("Unknown output '%s'.", optarg);
200 r = safe_atoi(optarg, &arg_lines);
201 if (r < 0 || arg_lines < 0) {
202 log_error("Failed to parse lines '%s'", optarg);
215 arg_action = ACTION_NEW_ID128;
227 arg_this_boot = true;
231 arg_directory = optarg;
239 arg_action = ACTION_PRINT_HEADER;
243 arg_action = ACTION_VERIFY;
247 arg_action = ACTION_DISK_USAGE;
252 arg_action = ACTION_SETUP_KEYS;
257 arg_action = ACTION_VERIFY;
258 arg_verify_key = optarg;
263 r = parse_usec(optarg, &arg_interval);
264 if (r < 0 || arg_interval <= 0) {
265 log_error("Failed to parse sealing key change interval: %s", optarg);
273 log_error("Forward-secure sealing not available.");
280 dots = strstr(optarg, "..");
286 a = strndup(optarg, dots - optarg);
290 from = log_level_from_string(a);
291 to = log_level_from_string(dots + 2);
294 if (from < 0 || to < 0) {
295 log_error("Failed to parse log level range %s", optarg);
302 for (i = from; i <= to; i++)
303 arg_priorities |= 1 << i;
305 for (i = to; i <= from; i++)
306 arg_priorities |= 1 << i;
312 p = log_level_from_string(optarg);
314 log_error("Unknown log level %s", optarg);
320 for (i = 0; i <= p; i++)
321 arg_priorities |= 1 << i;
331 log_error("Unknown option code %c", c);
336 if (arg_follow && !arg_no_tail && arg_lines < 0)
342 static bool on_tty(void) {
345 /* Note that this is invoked relatively early, before we start
346 * the pager. That means the value we return reflects whether
347 * we originally were started on a tty, not if we currently
348 * are. But this is intended, since we want colour and so on
349 * when run in our own pager. */
351 if (_unlikely_(t < 0))
352 t = isatty(STDOUT_FILENO) > 0;
357 static int generate_new_id128(void) {
362 r = sd_id128_randomize(&id);
364 log_error("Failed to generate ID: %s", strerror(-r));
368 printf("As string:\n"
369 SD_ID128_FORMAT_STR "\n\n"
371 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
373 "#define MESSAGE_XYZ SD_ID128_MAKE(",
374 SD_ID128_FORMAT_VAL(id),
375 SD_ID128_FORMAT_VAL(id));
377 for (i = 0; i < 16; i++)
378 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
380 fputs(")\n", stdout);
385 static int add_matches(sd_journal *j, char **args) {
391 STRV_FOREACH(i, args) {
394 r = sd_journal_add_disjunction(j);
395 else if (path_is_absolute(*i)) {
400 p = canonicalize_file_name(*i);
403 if (stat(path, &st) < 0) {
405 log_error("Couldn't stat file: %m");
409 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
410 t = strappend("_EXE=", path);
411 else if (S_ISCHR(st.st_mode))
412 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
413 else if (S_ISBLK(st.st_mode))
414 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
417 log_error("File is not a device node, regular file or is not executable: %s", *i);
426 r = sd_journal_add_match(j, t, 0);
429 r = sd_journal_add_match(j, *i, 0);
432 log_error("Failed to add match '%s': %s", *i, strerror(-r));
440 static int add_this_boot(sd_journal *j) {
441 char match[9+32+1] = "_BOOT_ID=";
450 r = sd_id128_get_boot(&boot_id);
452 log_error("Failed to get boot id: %s", strerror(-r));
456 sd_id128_to_string(boot_id, match + 9);
457 r = sd_journal_add_match(j, match, strlen(match));
459 log_error("Failed to add match: %s", strerror(-r));
466 static int add_priorities(sd_journal *j) {
467 char match[] = "PRIORITY=0";
472 if (arg_priorities == 0xFF)
475 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
476 if (arg_priorities & (1 << i)) {
477 match[sizeof(match)-2] = '0' + i;
479 log_info("adding match %s", match);
481 r = sd_journal_add_match(j, match, strlen(match));
483 log_error("Failed to add match: %s", strerror(-r));
491 static int setup_keys(void) {
493 size_t mpk_size, seed_size, state_size, i;
494 uint8_t *mpk, *seed, *state;
496 int fd = -1, r, attr = 0;
497 sd_id128_t machine, boot;
498 char *p = NULL, *k = NULL;
502 r = sd_id128_get_machine(&machine);
504 log_error("Failed to get machine ID: %s", strerror(-r));
508 r = sd_id128_get_boot(&boot);
510 log_error("Failed to get boot ID: %s", strerror(-r));
514 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
515 SD_ID128_FORMAT_VAL(machine)) < 0)
518 if (access(p, F_OK) >= 0) {
519 log_error("Sealing key file %s exists already.", p);
524 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
525 SD_ID128_FORMAT_VAL(machine)) < 0) {
530 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
531 mpk = alloca(mpk_size);
533 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
534 seed = alloca(seed_size);
536 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
537 state = alloca(state_size);
539 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
541 log_error("Failed to open /dev/random: %m");
546 log_info("Generating seed...");
547 l = loop_read(fd, seed, seed_size, true);
548 if (l < 0 || (size_t) l != seed_size) {
549 log_error("Failed to read random seed: %s", strerror(EIO));
554 log_info("Generating key pair...");
555 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
557 log_info("Generating sealing key...");
558 FSPRG_GenState0(state, mpk, seed, seed_size);
560 assert(arg_interval > 0);
562 n = now(CLOCK_REALTIME);
565 close_nointr_nofail(fd);
566 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
568 log_error("Failed to open %s: %m", k);
573 /* Enable secure remove, exclusion from dump, synchronous
574 * writing and in-place updating */
575 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
576 log_warning("FS_IOC_GETFLAGS failed: %m");
578 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
580 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
581 log_warning("FS_IOC_SETFLAGS failed: %m");
584 memcpy(h.signature, "KSHHRHLP", 8);
585 h.machine_id = machine;
587 h.header_size = htole64(sizeof(h));
588 h.start_usec = htole64(n * arg_interval);
589 h.interval_usec = htole64(arg_interval);
590 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
591 h.fsprg_state_size = htole64(state_size);
593 l = loop_write(fd, &h, sizeof(h), false);
594 if (l < 0 || (size_t) l != sizeof(h)) {
595 log_error("Failed to write header: %s", strerror(EIO));
600 l = loop_write(fd, state, state_size, false);
601 if (l < 0 || (size_t) l != state_size) {
602 log_error("Failed to write state: %s", strerror(EIO));
607 if (link(k, p) < 0) {
608 log_error("Failed to link file: %m");
613 if (isatty(STDOUT_FILENO)) {
616 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
617 "the following local file. This key file is automatically updated when the\n"
618 "sealing key is advanced. It should not be used on multiple hosts.\n"
622 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
623 "at a safe location and should not be saved locally on disk.\n"
624 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
627 for (i = 0; i < seed_size; i++) {
628 if (i > 0 && i % 3 == 0)
630 printf("%02x", ((uint8_t*) seed)[i]);
633 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
635 if (isatty(STDOUT_FILENO)) {
636 char tsb[FORMAT_TIMESPAN_MAX], *hn;
639 ANSI_HIGHLIGHT_OFF "\n"
640 "The sealing key is automatically changed every %s.\n",
641 format_timespan(tsb, sizeof(tsb), arg_interval));
643 hn = gethostname_malloc();
646 hostname_cleanup(hn);
647 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
649 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
652 /* If this is not an UTF-8 system don't print any QR codes */
653 setlocale(LC_CTYPE, "");
655 if (streq_ptr(nl_langinfo(CODESET), "UTF-8")) {
656 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
657 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
667 close_nointr_nofail(fd);
678 log_error("Forward-secure sealing not available.");
683 static int verify(sd_journal *j) {
690 log_show_color(true);
692 HASHMAP_FOREACH(f, j->files, i) {
694 usec_t first, validated, last;
697 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
698 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
701 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
703 /* If the key was invalid give up right-away. */
706 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
709 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
710 log_info("PASS: %s", f->path);
712 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
714 log_info("=> Validated from %s to %s, final %s entries not sealed.",
715 format_timestamp(a, sizeof(a), first),
716 format_timestamp(b, sizeof(b), validated),
717 format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
719 log_info("=> No sealing yet, %s of entries not sealed.",
720 format_timespan(c, sizeof(c), last - first));
722 log_info("=> No sealing yet, no entries in file.");
730 int main(int argc, char *argv[]) {
732 sd_journal *j = NULL;
733 bool need_seek = false;
734 sd_id128_t previous_boot_id;
735 bool previous_boot_id_valid = false;
738 log_parse_environment();
741 r = parse_argv(argc, argv);
745 if (arg_action == ACTION_NEW_ID128) {
746 r = generate_new_id128();
750 if (arg_action == ACTION_SETUP_KEYS) {
756 r = sd_journal_open_directory(&j, arg_directory, 0);
758 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
761 log_error("Failed to open journal: %s", strerror(-r));
765 if (arg_action == ACTION_VERIFY) {
770 if (arg_action == ACTION_PRINT_HEADER) {
771 journal_print_header(j);
776 if (arg_action == ACTION_DISK_USAGE) {
778 char sbytes[FORMAT_BYTES_MAX];
780 r = sd_journal_get_usage(j, &bytes);
784 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
790 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
791 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
796 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
797 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
799 if (geteuid() != 0 && in_group("adm") <= 0) {
800 log_error("No access to messages. Only users in the group 'adm' can see messages.");
806 r = add_this_boot(j);
810 r = add_matches(j, argv + optind);
814 r = add_priorities(j);
820 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
822 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
824 log_error("Failed to get cutoff: %s", strerror(-r));
830 printf("Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start));
832 printf("Logs begin at %s, end at %s.\n",
833 format_timestamp(start_buf, sizeof(start_buf), start),
834 format_timestamp(end_buf, sizeof(end_buf), end));
839 r = sd_journal_seek_cursor(j, arg_cursor);
841 log_error("Failed to seek to cursor: %s", strerror(-r));
845 r = sd_journal_next(j);
847 } else if (arg_lines >= 0) {
848 r = sd_journal_seek_tail(j);
850 log_error("Failed to seek to tail: %s", strerror(-r));
854 r = sd_journal_previous_skip(j, arg_lines);
857 r = sd_journal_seek_head(j);
859 log_error("Failed to seek to head: %s", strerror(-r));
863 r = sd_journal_next(j);
867 log_error("Failed to iterate through journal: %s", strerror(-r));
872 have_pager = !arg_no_pager && !arg_follow && pager_open();
877 arg_show_all * OUTPUT_SHOW_ALL |
878 have_pager * OUTPUT_FULL_WIDTH |
879 on_tty() * OUTPUT_COLOR;
882 r = sd_journal_next(j);
884 log_error("Failed to iterate through journal: %s", strerror(-r));
895 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
897 if (previous_boot_id_valid &&
898 !sd_id128_equal(boot_id, previous_boot_id))
899 printf(ANSI_HIGHLIGHT_ON "----- Reboot -----" ANSI_HIGHLIGHT_OFF "\n");
901 previous_boot_id = boot_id;
902 previous_boot_id_valid = true;
906 r = output_journal(stdout, j, arg_output, 0, flags);
916 r = sd_journal_wait(j, (uint64_t) -1);
918 log_error("Couldn't wait for journal event: %s", strerror(-r));
929 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;