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/>.
33 #include <sys/ioctl.h>
36 #include <systemd/sd-journal.h>
40 #include "path-util.h"
43 #include "logs-show.h"
45 #include "journal-internal.h"
46 #include "journal-def.h"
47 #include "journal-verify.h"
48 #include "journal-authenticate.h"
49 #include "journal-qrcode.h"
52 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
54 static OutputMode arg_output = OUTPUT_SHORT;
55 static bool arg_follow = false;
56 static bool arg_show_all = false;
57 static bool arg_no_pager = false;
58 static int arg_lines = -1;
59 static bool arg_no_tail = false;
60 static bool arg_quiet = false;
61 static bool arg_merge = false;
62 static bool arg_this_boot = false;
63 static const char *arg_directory = NULL;
64 static int arg_priorities = 0xFF;
65 static const char *arg_verify_key = NULL;
67 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
77 } arg_action = ACTION_SHOW;
79 static int help(void) {
81 printf("%s [OPTIONS...] [MATCH]\n\n"
82 "Send control commands to or query the journal.\n\n"
83 " -h --help Show this help\n"
84 " --version Show package version\n"
85 " --no-pager Do not pipe output into a pager\n"
86 " -a --all Show all fields, including long and unprintable\n"
87 " -f --follow Follow journal\n"
88 " -n --lines=INTEGER Journal entries to show\n"
89 " --no-tail Show all lines, even in follow mode\n"
90 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
91 " verbose, export, json, json-pretty, cat)\n"
92 " -q --quiet Don't show privilege warning\n"
93 " -m --merge Show entries from all available journals\n"
94 " -b --this-boot Show data only from current boot\n"
95 " -D --directory=PATH Show journal files from directory\n"
96 " -p --priority=RANGE Show only messages within the specified priority range\n\n"
98 " --new-id128 Generate a new 128 Bit ID\n"
99 " --header Show journal header information\n"
100 " --disk-usage Show total disk usage\n"
102 " --setup-keys Generate new FSS key pair\n"
103 " --interval=TIME Time interval for changing the FSS sealing key\n"
104 " --verify Verify journal file consistency\n"
105 " --verify-key=KEY Specify FSS verification key\n"
107 , program_invocation_short_name);
112 static int parse_argv(int argc, char *argv[]) {
127 static const struct option options[] = {
128 { "help", no_argument, NULL, 'h' },
129 { "version" , no_argument, NULL, ARG_VERSION },
130 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
131 { "follow", no_argument, NULL, 'f' },
132 { "output", required_argument, NULL, 'o' },
133 { "all", no_argument, NULL, 'a' },
134 { "lines", required_argument, NULL, 'n' },
135 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
136 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
137 { "quiet", no_argument, NULL, 'q' },
138 { "merge", no_argument, NULL, 'm' },
139 { "this-boot", no_argument, NULL, 'b' },
140 { "directory", required_argument, NULL, 'D' },
141 { "header", no_argument, NULL, ARG_HEADER },
142 { "priority", no_argument, NULL, 'p' },
143 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
144 { "interval", required_argument, NULL, ARG_INTERVAL },
145 { "verify", no_argument, NULL, ARG_VERIFY },
146 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
147 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
156 while ((c = getopt_long(argc, argv, "hfo:an:qmbD:p:", options, NULL)) >= 0) {
165 puts(PACKAGE_STRING);
167 puts(SYSTEMD_FEATURES);
179 arg_output = output_mode_from_string(optarg);
180 if (arg_output < 0) {
181 log_error("Unknown output '%s'.", optarg);
192 r = safe_atoi(optarg, &arg_lines);
193 if (r < 0 || arg_lines < 0) {
194 log_error("Failed to parse lines '%s'", optarg);
204 arg_action = ACTION_NEW_ID128;
216 arg_this_boot = true;
220 arg_directory = optarg;
224 arg_action = ACTION_PRINT_HEADER;
228 arg_action = ACTION_VERIFY;
232 arg_action = ACTION_DISK_USAGE;
237 arg_action = ACTION_SETUP_KEYS;
242 arg_action = ACTION_VERIFY;
243 arg_verify_key = optarg;
248 r = parse_usec(optarg, &arg_interval);
249 if (r < 0 || arg_interval <= 0) {
250 log_error("Failed to parse sealing key change interval: %s", optarg);
258 log_error("Forward-secure sealing not available.");
265 dots = strstr(optarg, "..");
271 a = strndup(optarg, dots - optarg);
275 from = log_level_from_string(a);
276 to = log_level_from_string(dots + 2);
279 if (from < 0 || to < 0) {
280 log_error("Failed to parse log level range %s", optarg);
287 for (i = from; i <= to; i++)
288 arg_priorities |= 1 << i;
290 for (i = to; i <= from; i++)
291 arg_priorities |= 1 << i;
297 p = log_level_from_string(optarg);
299 log_error("Unknown log level %s", optarg);
305 for (i = 0; i <= p; i++)
306 arg_priorities |= 1 << i;
316 log_error("Unknown option code %c", c);
321 if (arg_follow && !arg_no_tail && arg_lines < 0)
327 static bool on_tty(void) {
330 /* Note that this is invoked relatively early, before we start
331 * the pager. That means the value we return reflects whether
332 * we originally were started on a tty, not if we currently
333 * are. But this is intended, since we want colour and so on
334 * when run in our own pager. */
336 if (_unlikely_(t < 0))
337 t = isatty(STDOUT_FILENO) > 0;
342 static int generate_new_id128(void) {
347 r = sd_id128_randomize(&id);
349 log_error("Failed to generate ID: %s", strerror(-r));
353 printf("As string:\n"
354 SD_ID128_FORMAT_STR "\n\n"
356 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
358 "#define MESSAGE_XYZ SD_ID128_MAKE(",
359 SD_ID128_FORMAT_VAL(id),
360 SD_ID128_FORMAT_VAL(id));
362 for (i = 0; i < 16; i++)
363 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
365 fputs(")\n", stdout);
370 static int add_matches(sd_journal *j, char **args) {
376 STRV_FOREACH(i, args) {
379 r = sd_journal_add_disjunction(j);
380 else if (path_is_absolute(*i)) {
385 p = canonicalize_file_name(*i);
388 if (stat(path, &st) < 0) {
390 log_error("Couldn't stat file: %m");
394 if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
395 t = strappend("_EXE=", path);
396 else if (S_ISCHR(st.st_mode))
397 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
398 else if (S_ISBLK(st.st_mode))
399 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
402 log_error("File is not a device node, regular file or is not executable: %s", *i);
411 r = sd_journal_add_match(j, t, 0);
414 r = sd_journal_add_match(j, *i, 0);
417 log_error("Failed to add match '%s': %s", *i, strerror(-r));
425 static int add_this_boot(sd_journal *j) {
426 char match[9+32+1] = "_BOOT_ID=";
435 r = sd_id128_get_boot(&boot_id);
437 log_error("Failed to get boot id: %s", strerror(-r));
441 sd_id128_to_string(boot_id, match + 9);
442 r = sd_journal_add_match(j, match, strlen(match));
444 log_error("Failed to add match: %s", strerror(-r));
451 static int add_priorities(sd_journal *j) {
452 char match[] = "PRIORITY=0";
457 if (arg_priorities == 0xFF)
460 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
461 if (arg_priorities & (1 << i)) {
462 match[sizeof(match)-2] = '0' + i;
464 log_info("adding match %s", match);
466 r = sd_journal_add_match(j, match, strlen(match));
468 log_error("Failed to add match: %s", strerror(-r));
476 static int setup_keys(void) {
478 size_t mpk_size, seed_size, state_size, i;
479 uint8_t *mpk, *seed, *state;
481 int fd = -1, r, attr = 0;
482 sd_id128_t machine, boot;
483 char *p = NULL, *k = NULL;
487 r = sd_id128_get_machine(&machine);
489 log_error("Failed to get machine ID: %s", strerror(-r));
493 r = sd_id128_get_boot(&boot);
495 log_error("Failed to get boot ID: %s", strerror(-r));
499 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
500 SD_ID128_FORMAT_VAL(machine)) < 0)
503 if (access(p, F_OK) >= 0) {
504 log_error("Sealing key file %s exists already.", p);
509 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
510 SD_ID128_FORMAT_VAL(machine)) < 0) {
515 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
516 mpk = alloca(mpk_size);
518 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
519 seed = alloca(seed_size);
521 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
522 state = alloca(state_size);
524 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
526 log_error("Failed to open /dev/random: %m");
531 log_info("Generating seed...");
532 l = loop_read(fd, seed, seed_size, true);
533 if (l < 0 || (size_t) l != seed_size) {
534 log_error("Failed to read random seed: %s", strerror(EIO));
539 log_info("Generating key pair...");
540 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
542 log_info("Generating sealing key...");
543 FSPRG_GenState0(state, mpk, seed, seed_size);
545 assert(arg_interval > 0);
547 n = now(CLOCK_REALTIME);
550 close_nointr_nofail(fd);
551 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
553 log_error("Failed to open %s: %m", k);
558 /* Enable secure remove, exclusion from dump, synchronous
559 * writing and in-place updating */
560 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
561 log_warning("FS_IOC_GETFLAGS failed: %m");
563 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
565 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
566 log_warning("FS_IOC_SETFLAGS failed: %m");
569 memcpy(h.signature, "KSHHRHLP", 8);
570 h.machine_id = machine;
572 h.header_size = htole64(sizeof(h));
573 h.start_usec = htole64(n * arg_interval);
574 h.interval_usec = htole64(arg_interval);
575 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
576 h.fsprg_state_size = htole64(state_size);
578 l = loop_write(fd, &h, sizeof(h), false);
579 if (l < 0 || (size_t) l != sizeof(h)) {
580 log_error("Failed to write header: %s", strerror(EIO));
585 l = loop_write(fd, state, state_size, false);
586 if (l < 0 || (size_t) l != state_size) {
587 log_error("Failed to write state: %s", strerror(EIO));
592 if (link(k, p) < 0) {
593 log_error("Failed to link file: %m");
598 if (isatty(STDOUT_FILENO)) {
601 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
602 "the following local file. This key file is automatically updated when the\n"
603 "sealing key is advanced. It should not be used on multiple hosts.\n"
607 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
608 "at a safe location and should not be saved locally on disk.\n"
609 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
612 for (i = 0; i < seed_size; i++) {
613 if (i > 0 && i % 3 == 0)
615 printf("%02x", ((uint8_t*) seed)[i]);
618 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
620 if (isatty(STDOUT_FILENO)) {
621 char tsb[FORMAT_TIMESPAN_MAX], *hn;
624 ANSI_HIGHLIGHT_OFF "\n"
625 "The sealing key is automatically changed every %s.\n",
626 format_timespan(tsb, sizeof(tsb), arg_interval));
628 hn = gethostname_malloc();
631 hostname_cleanup(hn);
632 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
634 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
637 fprintf(stderr, "\nTo transfer the verification key to your phone please scan the QR code below:\n\n");
638 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
647 close_nointr_nofail(fd);
658 log_error("Forward-secure sealing not available.");
663 static int verify(sd_journal *j) {
670 log_show_color(true);
672 HASHMAP_FOREACH(f, j->files, i) {
674 usec_t from, to, total;
677 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
678 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
681 k = journal_file_verify(f, arg_verify_key, &from, &to, &total, true);
683 /* If the key was invalid give up right-away. */
686 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
689 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
690 log_info("PASS: %s", f->path);
692 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
694 log_info("=> Validated from %s to %s, final %s entries not sealed.",
695 format_timestamp(a, sizeof(a), from),
696 format_timestamp(b, sizeof(b), to),
697 format_timespan(c, sizeof(c), total > to ? total - to : 0));
698 } else if (total > 0)
699 log_info("=> No sealing yet, %s of entries not sealed.",
700 format_timespan(c, sizeof(c), total));
702 log_info("=> No sealing yet, no entries in file.");
710 int main(int argc, char *argv[]) {
712 sd_journal *j = NULL;
714 bool need_seek = false;
715 sd_id128_t previous_boot_id;
716 bool previous_boot_id_valid = false;
719 log_parse_environment();
722 r = parse_argv(argc, argv);
726 if (arg_action == ACTION_NEW_ID128) {
727 r = generate_new_id128();
731 if (arg_action == ACTION_SETUP_KEYS) {
737 r = sd_journal_open_directory(&j, arg_directory, 0);
739 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
742 log_error("Failed to open journal: %s", strerror(-r));
746 if (arg_action == ACTION_VERIFY) {
751 if (arg_action == ACTION_PRINT_HEADER) {
752 journal_print_header(j);
757 if (arg_action == ACTION_DISK_USAGE) {
759 char sbytes[FORMAT_BYTES_MAX];
761 r = sd_journal_get_usage(j, &bytes);
765 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
771 if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
772 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
777 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
778 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
780 if (geteuid() != 0 && in_group("adm") <= 0) {
781 log_error("No access to messages. Only users in the group 'adm' can see messages.");
787 r = add_this_boot(j);
791 r = add_matches(j, argv + optind);
795 r = add_priorities(j);
801 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
803 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
805 log_error("Failed to get cutoff: %s", strerror(-r));
811 printf("Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start));
813 printf("Logs begin at %s, end at %s.\n",
814 format_timestamp(start_buf, sizeof(start_buf), start),
815 format_timestamp(end_buf, sizeof(end_buf), end));
819 if (arg_lines >= 0) {
820 r = sd_journal_seek_tail(j);
822 log_error("Failed to seek to tail: %s", strerror(-r));
826 r = sd_journal_previous_skip(j, arg_lines);
828 r = sd_journal_seek_head(j);
830 log_error("Failed to seek to head: %s", strerror(-r));
834 r = sd_journal_next(j);
838 log_error("Failed to iterate through journal: %s", strerror(-r));
843 have_pager = !arg_no_pager && !arg_follow && pager_open();
848 arg_show_all * OUTPUT_SHOW_ALL |
849 have_pager * OUTPUT_FULL_WIDTH |
850 on_tty() * OUTPUT_COLOR;
853 r = sd_journal_next(j);
855 log_error("Failed to iterate through journal: %s", strerror(-r));
866 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
868 if (previous_boot_id_valid &&
869 !sd_id128_equal(boot_id, previous_boot_id))
870 printf(ANSI_HIGHLIGHT_ON "----- Reboot -----" ANSI_HIGHLIGHT_OFF "\n");
872 previous_boot_id = boot_id;
873 previous_boot_id_valid = true;
879 r = output_journal(j, arg_output, line, 0, flags);
889 r = sd_journal_wait(j, (uint64_t) -1);
891 log_error("Couldn't wait for log event: %s", strerror(-r));
902 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;