diff --git a/meson.build b/meson.build index c0b5b3cccb..e4c95c9c32 100644 --- a/meson.build +++ b/meson.build @@ -1799,7 +1799,7 @@ public_programs += executable( include_directories : includes, link_with : [libshared], dependencies : [threads, - libqrencode, + libdl, libxz, liblz4, libpcre2, diff --git a/src/basic/dlfcn-util.c b/src/basic/dlfcn-util.c new file mode 100644 index 0000000000..08ded96965 --- /dev/null +++ b/src/basic/dlfcn-util.c @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "dlfcn-util.h" + +int dlsym_many_and_warn(void *dl, int level, ...) { + va_list ap; + int r; + + /* Tries to resolve a bunch of function symbols, and logs errors about the ones it cannot + * resolve. Note that this function possibly modifies the supplied function pointers if the whole + * operation fails */ + + va_start(ap, level); + + for (;;) { + void (**fn)(void); + void (*tfn)(void); + const char *symbol; + + fn = va_arg(ap, typeof(fn)); + if (!fn) + break; + + symbol = va_arg(ap, typeof(symbol)); + + tfn = (typeof(tfn)) dlsym(dl, symbol); + if (!tfn) { + r = log_full_errno(level, + SYNTHETIC_ERRNO(ELIBBAD), + "Can't find symbol %s: %s", symbol, dlerror()); + va_end(ap); + return r; + } + + *fn = tfn; + } + + va_end(ap); + return 0; +} diff --git a/src/basic/dlfcn-util.h b/src/basic/dlfcn-util.h index d254afb68b..df66cdfd38 100644 --- a/src/basic/dlfcn-util.h +++ b/src/basic/dlfcn-util.h @@ -6,3 +6,5 @@ #include "macro.h" DEFINE_TRIVIAL_CLEANUP_FUNC(void*, dlclose); + +int dlsym_many_and_warn(void *dl, int level, ...); diff --git a/src/basic/meson.build b/src/basic/meson.build index 90924d6cb8..42d0754d6d 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -39,6 +39,7 @@ basic_sources = files(''' device-nodes.h dirent-util.c dirent-util.h + dlfcn-util.c dlfcn-util.h efivars.c efivars.h diff --git a/src/journal/journal-qrcode.c b/src/journal/journal-qrcode.c index 678654f773..dddbd7b381 100644 --- a/src/journal/journal-qrcode.c +++ b/src/journal/journal-qrcode.c @@ -6,29 +6,34 @@ #include #include +#include "alloc-util.h" +#include "dlfcn-util.h" +#include "fd-util.h" #include "fileio.h" #include "journal-qrcode.h" +#include "locale-util.h" #include "macro.h" +#include "terminal-util.h" -#define WHITE_ON_BLACK "\033[40;37;1m" -#define NORMAL "\033[0m" +#define ANSI_WHITE_ON_BLACK "\033[40;37;1m" static void print_border(FILE *output, unsigned width) { unsigned x, y; /* Four rows of border */ for (y = 0; y < 4; y += 2) { - fputs(WHITE_ON_BLACK, output); + fputs(ANSI_WHITE_ON_BLACK, output); for (x = 0; x < 4 + width + 4; x++) fputs("\342\226\210", output); - fputs(NORMAL "\n", output); + fputs(ANSI_NORMAL "\n", output); } } int print_qr_code( FILE *output, + const char *prefix_text, const void *seed, size_t seed_size, uint64_t start, @@ -36,15 +41,38 @@ int print_qr_code( const char *hn, sd_id128_t machine) { - FILE *f; - char *url = NULL; + QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + void (*sym_QRcode_free)(QRcode *qrcode); + _cleanup_(dlclosep) void *dl = NULL; + _cleanup_free_ char *url = NULL; + _cleanup_fclose_ FILE *f = NULL; size_t url_size = 0, i; - QRcode* qr; unsigned x, y; + QRcode* qr; + int r; assert(seed); assert(seed_size > 0); + /* If this is not an UTF-8 system or ANSI colors aren't supported/disabled don't print any QR + * codes */ + if (!is_locale_utf8() || !colors_enabled()) + return -EOPNOTSUPP; + + dl = dlopen("libqrencode.so.4", RTLD_LAZY); + if (!dl) + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "QRCODE support is not installed: %s", dlerror()); + + r = dlsym_many_and_warn( + dl, + LOG_DEBUG, + &sym_QRcode_encodeString, "QRcode_encodeString", + &sym_QRcode_free, "QRcode_free", + NULL); + if (r < 0) + return r; + f = open_memstream_unlocked(&url, &url_size); if (!f) return -ENOMEM; @@ -65,20 +93,19 @@ int print_qr_code( if (hn) fprintf(f, ";hostname=%s", hn); - if (ferror(f)) { - fclose(f); - free(url); - return -ENOMEM; - } + r = fflush_and_check(f); + if (r < 0) + return r; - fclose(f); - - qr = QRcode_encodeString(url, 0, QR_ECLEVEL_L, QR_MODE_8, 1); - free(url); + f = safe_fclose(f); + qr = sym_QRcode_encodeString(url, 0, QR_ECLEVEL_L, QR_MODE_8, 1); if (!qr) return -ENOMEM; + if (prefix_text) + fputs(prefix_text, output); + print_border(output, qr->width); for (y = 0; y < (unsigned) qr->width; y += 2) { @@ -87,7 +114,7 @@ int print_qr_code( row1 = qr->data + qr->width * y; row2 = row1 + qr->width; - fputs(WHITE_ON_BLACK, output); + fputs(ANSI_WHITE_ON_BLACK, output); for (x = 0; x < 4; x++) fputs("\342\226\210", output); @@ -109,11 +136,11 @@ int print_qr_code( for (x = 0; x < 4; x++) fputs("\342\226\210", output); - fputs(NORMAL "\n", output); + fputs(ANSI_NORMAL "\n", output); } print_border(output, qr->width); - QRcode_free(qr); + sym_QRcode_free(qr); return 0; } diff --git a/src/journal/journal-qrcode.h b/src/journal/journal-qrcode.h index 0774608edf..24ae9d32ee 100644 --- a/src/journal/journal-qrcode.h +++ b/src/journal/journal-qrcode.h @@ -6,4 +6,4 @@ #include "sd-id128.h" -int print_qr_code(FILE *f, const void *seed, size_t seed_size, uint64_t start, uint64_t interval, const char *hn, sd_id128_t machine); +int print_qr_code(FILE *f, const char *prefix_text, const void *seed, size_t seed_size, uint64_t start, uint64_t interval, const char *hn, sd_id128_t machine); diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 8d4897b942..5a56a990f9 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -57,12 +57,13 @@ #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" +#include "random-util.h" #include "rlimit-util.h" #include "set.h" #include "sigbus.h" +#include "stdio-util.h" #include "string-table.h" #include "strv.h" -#include "stdio-util.h" #include "syslog-util.h" #include "terminal-util.h" #include "tmpfile-util.h" @@ -1774,12 +1775,14 @@ static int add_syslog_identifier(sd_journal *j) { static int setup_keys(void) { #if HAVE_GCRYPT size_t mpk_size, seed_size, state_size, i; + _cleanup_(unlink_and_freep) char *k = NULL; + _cleanup_free_ char *p = NULL; uint8_t *mpk, *seed, *state; - int fd = -1, r; + _cleanup_close_ int fd = -1; sd_id128_t machine, boot; - char *p = NULL, *k = NULL; - uint64_t n; struct stat st; + uint64_t n; + int r; r = stat("/var/log/journal", &st); if (r < 0 && !IN_SET(errno, ENOENT, ENOTDIR)) @@ -1805,21 +1808,15 @@ static int setup_keys(void) { if (arg_force) { r = unlink(p); - if (r < 0 && errno != ENOENT) { - r = log_error_errno(errno, "unlink(\"%s\") failed: %m", p); - goto finish; - } - } else if (access(p, F_OK) >= 0) { - log_error("Sealing key file %s exists already. Use --force to recreate.", p); - r = -EEXIST; - goto finish; - } + if (r < 0 && errno != ENOENT) + return log_error_errno(errno, "unlink(\"%s\") failed: %m", p); + } else if (access(p, F_OK) >= 0) + return log_error_errno(SYNTHETIC_ERRNO(EEXIST), + "Sealing key file %s exists already. Use --force to recreate.", p); if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX", - SD_ID128_FORMAT_VAL(machine)) < 0) { - r = log_oom(); - goto finish; - } + SD_ID128_FORMAT_VAL(machine)) < 0) + return log_oom(); mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR); mpk = alloca(mpk_size); @@ -1830,18 +1827,10 @@ static int setup_keys(void) { state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR); state = alloca(state_size); - fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) { - r = log_error_errno(errno, "Failed to open /dev/random: %m"); - goto finish; - } - log_info("Generating seed..."); - r = loop_read_exact(fd, seed, seed_size, true); - if (r < 0) { - log_error_errno(r, "Failed to read random seed: %m"); - goto finish; - } + r = genuine_random_bytes(seed, seed_size, RANDOM_BLOCK); + if (r < 0) + return log_error_errno(r, "Failed to acquire random seed: %m"); log_info("Generating key pair..."); FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR); @@ -1856,18 +1845,25 @@ static int setup_keys(void) { safe_close(fd); fd = mkostemp_safe(k); - if (fd < 0) { - r = log_error_errno(fd, "Failed to open %s: %m", k); - goto finish; + if (fd < 0) + return log_error_errno(fd, "Failed to open %s: %m", k); + + /* Enable secure remove, exclusion from dump, synchronous writing and in-place updating */ + static const unsigned chattr_flags[] = { + FS_SECRM_FL, + FS_NODUMP_FL, + FS_SYNC_FL, + FS_NOCOW_FL, + }; + for (size_t j = 0; j < ELEMENTSOF(chattr_flags); j++) { + r = chattr_fd(fd, chattr_flags[j], chattr_flags[j], NULL); + if (r < 0) + log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set file attribute 0x%x: %m", chattr_flags[j]); } - /* Enable secure remove, exclusion from dump, synchronous - * writing and in-place updating */ - r = chattr_fd(fd, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL, NULL); - if (r < 0) - log_warning_errno(r, "Failed to set file attributes: %m"); - struct FSSHeader h = { + .signature = { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' }, .machine_id = machine, .boot_id = boot, .header_size = htole64(sizeof(h)), @@ -1877,24 +1873,18 @@ static int setup_keys(void) { .fsprg_state_size = htole64(state_size), }; - memcpy(h.signature, "KSHHRHLP", 8); - r = loop_write(fd, &h, sizeof(h), false); - if (r < 0) { - log_error_errno(r, "Failed to write header: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to write header: %m"); r = loop_write(fd, state, state_size, false); - if (r < 0) { - log_error_errno(r, "Failed to write state: %m"); - goto finish; - } + if (r < 0) + return log_error_errno(r, "Failed to write state: %m"); - if (link(k, p) < 0) { - r = log_error_errno(errno, "Failed to link file: %m"); - goto finish; - } + if (rename(k, p) < 0) + return log_error_errno(errno, "Failed to link file: %m"); + + k = mfree(k); if (on_tty()) { fprintf(stderr, @@ -1923,7 +1913,8 @@ static int setup_keys(void) { printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval); if (on_tty()) { - char tsb[FORMAT_TIMESPAN_MAX], *hn; + _cleanup_free_ char *hn = NULL; + char tsb[FORMAT_TIMESPAN_MAX]; fprintf(stderr, "%s\n" @@ -1932,7 +1923,6 @@ static int setup_keys(void) { format_timespan(tsb, sizeof(tsb), arg_interval, 0)); hn = gethostname_malloc(); - if (hn) { hostname_cleanup(hn); fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine)); @@ -1940,28 +1930,15 @@ static int setup_keys(void) { fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine)); #if HAVE_QRENCODE - /* If this is not an UTF-8 system don't print any QR codes */ - if (is_locale_utf8()) { - fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr); - print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine); - } + (void) print_qr_code(stderr, + "\nTo transfer the verification key to your phone please scan the QR code below:\n\n", + seed, seed_size, + n, arg_interval, + hn, machine); #endif - free(hn); } - r = 0; - -finish: - safe_close(fd); - - if (k) { - (void) unlink(k); - free(k); - } - - free(p); - - return r; + return 0; #else return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Forward-secure sealing not available.");