diff --git a/meson.build b/meson.build index 1abcac27f4..5cfc24c2d6 100644 --- a/meson.build +++ b/meson.build @@ -1561,21 +1561,11 @@ meson_apply_m4 = find_program('tools/meson-apply-m4.sh') includes = include_directories('src/basic', 'src/boot', + 'src/core', 'src/home', - 'src/shared', - 'src/systemd', 'src/journal', 'src/journal-remote', - 'src/nspawn', - 'src/resolve', - 'src/timesync', - 'src/time-wait-sync', - 'src/login', - 'src/udev', - 'src/libudev', - 'src/core', - 'src/shutdown', - 'src/xdg-autostart-generator', + 'src/libsystemd-network', 'src/libsystemd/sd-bus', 'src/libsystemd/sd-device', 'src/libsystemd/sd-event', @@ -1584,7 +1574,17 @@ includes = include_directories('src/basic', 'src/libsystemd/sd-netlink', 'src/libsystemd/sd-network', 'src/libsystemd/sd-resolve', - 'src/libsystemd-network', + 'src/libudev', + 'src/login', + 'src/nspawn', + 'src/resolve', + 'src/shared', + 'src/shutdown', + 'src/systemd', + 'src/time-wait-sync', + 'src/timesync', + 'src/udev', + 'src/xdg-autostart-generator', '.') add_project_arguments('-include', 'config.h', language : 'c') diff --git a/src/home/homectl-recovery-key.c b/src/home/homectl-recovery-key.c index c63d3415f4..3311205db5 100644 --- a/src/home/homectl-recovery-key.c +++ b/src/home/homectl-recovery-key.c @@ -1,17 +1,12 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -#if HAVE_QRENCODE -#include -#include "qrcode-util.h" -#endif - -#include "dlfcn-util.h" #include "errno-util.h" #include "homectl-recovery-key.h" #include "libcrypt-util.h" #include "locale-util.h" #include "memory-util.h" #include "modhex.h" +#include "qrcode-util.h" #include "random-util.h" #include "strv.h" #include "terminal-util.h" @@ -140,48 +135,6 @@ static int add_secret(JsonVariant **v, const char *password) { return 0; } -static int print_qr_code(const char *secret) { -#if HAVE_QRENCODE - 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; - QRcode* qr; - int r; - - /* 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; - - qr = sym_QRcode_encodeString(secret, 0, QR_ECLEVEL_L, QR_MODE_8, 0); - if (!qr) - return -ENOMEM; - - fprintf(stderr, "\nYou may optionally scan the recovery key off screen:\n\n"); - - write_qrcode(stderr, qr); - - fputc('\n', stderr); - - sym_QRcode_free(qr); -#endif - return 0; -} - int identity_add_recovery_key(JsonVariant **v) { _cleanup_(erase_and_freep) char *password = NULL, *hashed = NULL; int r; @@ -240,7 +193,7 @@ int identity_add_recovery_key(JsonVariant **v) { "whenever authentication is requested.\n", stderr); fflush(stderr); - print_qr_code(password); + (void) print_qrcode(stderr, "You may optionally scan the recovery key off screen", password); return 0; } diff --git a/src/journal/journal-qrcode.c b/src/journal/journal-qrcode.c deleted file mode 100644 index e8a7655316..0000000000 --- a/src/journal/journal-qrcode.c +++ /dev/null @@ -1,97 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ - -#include -#include -#include -#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 "qrcode-util.h" -#include "terminal-util.h" - -int print_qr_code( - FILE *output, - const char *prefix_text, - const void *seed, - size_t seed_size, - uint64_t start, - uint64_t interval, - const char *hn, - sd_id128_t machine) { - - 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; - 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; - - fputs("fss://", f); - - for (size_t i = 0; i < seed_size; i++) { - if (i > 0 && i % 3 == 0) - fputc('-', f); - fprintf(f, "%02x", ((uint8_t*) seed)[i]); - } - - fprintf(f, "/%"PRIx64"-%"PRIx64"?machine=" SD_ID128_FORMAT_STR, - start, - interval, - SD_ID128_FORMAT_VAL(machine)); - - if (hn) - fprintf(f, ";hostname=%s", hn); - - r = fflush_and_check(f); - if (r < 0) - return r; - - 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); - - write_qrcode(output, qr); - - sym_QRcode_free(qr); - return 0; -} diff --git a/src/journal/journal-qrcode.h b/src/journal/journal-qrcode.h deleted file mode 100644 index 24ae9d32ee..0000000000 --- a/src/journal/journal-qrcode.h +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -#pragma once - -#include -#include - -#include "sd-id128.h" - -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 e43e9d1afa..4014b8aad2 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -43,7 +43,6 @@ #include "io-util.h" #include "journal-def.h" #include "journal-internal.h" -#include "journal-qrcode.h" #include "journal-util.h" #include "journal-vacuum.h" #include "journal-verify.h" @@ -60,6 +59,7 @@ #include "path-util.h" #include "pcre2-dlopen.h" #include "pretty-print.h" +#include "qrcode-util.h" #include "random-util.h" #include "rlimit-util.h" #include "set.h" @@ -1779,6 +1779,53 @@ static int add_syslog_identifier(sd_journal *j) { return 0; } +static int format_journal_url( + const void *seed, + size_t seed_size, + uint64_t start, + uint64_t interval, + const char *hn, + sd_id128_t machine, + bool full, + char **ret_url) { + _cleanup_free_ char *url = NULL; + _cleanup_fclose_ FILE *f = NULL; + size_t url_size = 0; + int r; + + assert(seed); + assert(seed_size > 0); + + f = open_memstream_unlocked(&url, &url_size); + if (!f) + return -ENOMEM; + + if (full) + fputs("fss://", f); + + for (size_t i = 0; i < seed_size; i++) { + if (i > 0 && i % 3 == 0) + fputc('-', f); + fprintf(f, "%02x", ((uint8_t*) seed)[i]); + } + + fprintf(f, "/%"PRIx64"-%"PRIx64, start, interval); + + if (full) { + fprintf(f, "?machine=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(machine)); + if (hn) + fprintf(f, ";hostname=%s", hn); + } + + r = fflush_and_check(f); + if (r < 0) + return r; + + f = safe_fclose(f); + *ret_url = TAKE_PTR(url); + return 0; +} + static int setup_keys(void) { #if HAVE_GCRYPT size_t mpk_size, seed_size, state_size; @@ -1893,7 +1940,11 @@ static int setup_keys(void) { k = mfree(k); - _cleanup_free_ char *hn = NULL; + _cleanup_free_ char *hn = NULL, *key = NULL; + + r = format_journal_url(seed, seed_size, n, arg_interval, hn, machine, false, &key); + if (r < 0) + return r; if (on_tty()) { hn = gethostname_malloc(); @@ -1925,21 +1976,19 @@ static int setup_keys(void) { fflush(stderr); } - for (size_t i = 0; i < seed_size; i++) { - if (i > 0 && i % 3 == 0) - putchar('-'); - printf("%02x", ((uint8_t*) seed)[i]); - } - printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval); + puts(key); if (on_tty()) { fprintf(stderr, "%s", ansi_normal()); #if HAVE_QRENCODE - (void) print_qr_code(stderr, - "\nTo transfer the verification key to your phone scan the QR code below:\n", - seed, seed_size, - n, arg_interval, - hn, machine); + _cleanup_free_ char *url = NULL; + r = format_journal_url(seed, seed_size, n, arg_interval, hn, machine, true, &url); + if (r < 0) + return r; + + (void) print_qrcode(stderr, + "To transfer the verification key to your phone scan the QR code below", + url); #endif } diff --git a/src/journal/meson.build b/src/journal/meson.build index 3a590bdc6c..215ba949e7 100644 --- a/src/journal/meson.build +++ b/src/journal/meson.build @@ -107,11 +107,6 @@ journalctl_sources = files(''' pcre2-dlopen.h '''.split()) -if conf.get('HAVE_QRENCODE') == 1 - journalctl_sources += files('journal-qrcode.c', - 'journal-qrcode.h') -endif - install_data('journald.conf', install_dir : pkgsysconfdir) diff --git a/src/shared/meson.build b/src/shared/meson.build index 0ed216f1aa..260ee5a8b6 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -195,6 +195,8 @@ shared_sources = files(''' ptyfwd.h pwquality-util.c pwquality-util.h + qrcode-util.c + qrcode-util.h reboot-util.c reboot-util.h resize-fs.c @@ -304,13 +306,6 @@ if conf.get('HAVE_PAM') == 1 '''.split()) endif -if conf.get('HAVE_QRENCODE') == 1 - shared_sources += files(''' - qrcode-util.c - qrcode-util.h -'''.split()) -endif - generate_ip_protocol_list = find_program('generate-ip-protocol-list.sh') ip_protocol_list_txt = custom_target( 'ip-protocol-list.txt', diff --git a/src/shared/qrcode-util.c b/src/shared/qrcode-util.c index a545daaef3..4094c4ff3b 100644 --- a/src/shared/qrcode-util.c +++ b/src/shared/qrcode-util.c @@ -1,25 +1,27 @@ #include "qrcode-util.h" + +#if HAVE_QRENCODE +#include + +#include "dlfcn-util.h" +#include "locale-util.h" #include "terminal-util.h" #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) { + for (unsigned y = 0; y < 4; y += 2) { fputs(ANSI_WHITE_ON_BLACK, output); - for (x = 0; x < 4 + width + 4; x++) + for (unsigned x = 0; x < 4 + width + 4; x++) fputs("\342\226\210", output); fputs(ANSI_NORMAL "\n", output); } } -void write_qrcode(FILE *output, QRcode *qr) { - unsigned x, y; - +static void write_qrcode(FILE *output, QRcode *qr) { assert(qr); if (!output) @@ -27,17 +29,15 @@ void write_qrcode(FILE *output, QRcode *qr) { print_border(output, qr->width); - for (y = 0; y < (unsigned) qr->width; y += 2) { - const uint8_t *row1, *row2; - - row1 = qr->data + qr->width * y; - row2 = row1 + qr->width; + for (unsigned y = 0; y < (unsigned) qr->width; y += 2) { + const uint8_t *row1 = qr->data + qr->width * y; + const uint8_t *row2 = row1 + qr->width; fputs(ANSI_WHITE_ON_BLACK, output); - for (x = 0; x < 4; x++) + for (unsigned x = 0; x < 4; x++) fputs("\342\226\210", output); - for (x = 0; x < (unsigned) qr->width; x ++) { + for (unsigned x = 0; x < (unsigned) qr->width; x++) { bool a, b; a = row1[x] & 1; @@ -53,7 +53,7 @@ void write_qrcode(FILE *output, QRcode *qr) { fputs("\342\226\210", output); } - for (x = 0; x < 4; x++) + for (unsigned x = 0; x < 4; x++) fputs("\342\226\210", output); fputs(ANSI_NORMAL "\n", output); } @@ -61,3 +61,45 @@ void write_qrcode(FILE *output, QRcode *qr) { print_border(output, qr->width); fflush(output); } + +int print_qrcode(FILE *out, const char *header, const char *string) { + 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; + QRcode* qr; + int r; + + /* 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; + + qr = sym_QRcode_encodeString(string, 0, QR_ECLEVEL_L, QR_MODE_8, 0); + if (!qr) + return -ENOMEM; + + if (header) + fprintf(out, "\n%s:\n\n", header); + + write_qrcode(out, qr); + + fputc('\n', out); + + sym_QRcode_free(qr); + return 0; +} +#endif diff --git a/src/shared/qrcode-util.h b/src/shared/qrcode-util.h index 9a21ffd7fe..036c3f7f90 100644 --- a/src/shared/qrcode-util.h +++ b/src/shared/qrcode-util.h @@ -1,9 +1,13 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ + #pragma once +#include +#include #if HAVE_QRENCODE -#include -#include - -void write_qrcode(FILE *output, QRcode *qr); +int print_qrcode(FILE *out, const char *header, const char *string); +#else +static inline int print_qrcode(FILE *out, const char *header, const char *string) { + return -EOPNOTSUPP; +} #endif diff --git a/src/test/meson.build b/src/test/meson.build index daf62eb539..e4ce8ac51a 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -819,6 +819,10 @@ tests += [ [['src/test/test-psi-util.c'], [], []], + + [['src/test/test-qrcode-util.c'], + [libshared], + [libdl]], ] ############################################################ diff --git a/src/test/test-qrcode-util.c b/src/test/test-qrcode-util.c new file mode 100644 index 0000000000..c4e2894eb7 --- /dev/null +++ b/src/test/test-qrcode-util.c @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "locale-util.h" +#include "main-func.h" +#include "qrcode-util.h" +#include "tests.h" + +static int run(int argc, char **argv) { + int r; + + test_setup_logging(LOG_DEBUG); + + assert_se(setenv("SYSTEMD_COLORS", "1", 1) == 0); /* Force the qrcode to be printed */ + + r = print_qrcode(stdout, "This should say \"TEST\"", "TEST"); + if (r == -EOPNOTSUPP) + return log_tests_skipped("not supported"); + if (r < 0) + return log_error_errno(r, "Failed to print QR code: %m"); + return 0; +} + +DEFINE_MAIN_FUNCTION(run);