From 0d1d512f7f42071595f0c950f911f3557fda09ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 21 Aug 2018 16:08:48 +0200 Subject: [PATCH] systemd-id128: a new tool to print machine/boot/invocation/app-specific ids The raison d'etre for this program is printing machine-app-specific IDs. We provide a library function for that, but not a convenient API. We can hardly ask people to quickly hack their own C programs or call libsystemd through CFFI in python or another scripting language if they just want to print an ID. Verb 'new' was already available as 'journalctl --new-id128', but this makes it more discoverable. v2: - rename binary to systemd-id128 - make --app-specific= into a switch that applies to boot-id and machine-id --- man/sd_id128_get_machine.xml | 3 +- meson.build | 8 ++ src/id128/id128.c | 167 +++++++++++++++++++++++++++++++++++ src/journal/journalctl.c | 2 +- src/shared/id128-print.c | 23 +++-- src/shared/id128-print.h | 7 +- 6 files changed, 201 insertions(+), 9 deletions(-) create mode 100644 src/id128/id128.c diff --git a/man/sd_id128_get_machine.xml b/man/sd_id128_get_machine.xml index 8425addd18..f797a8af4e 100644 --- a/man/sd_id128_get_machine.xml +++ b/man/sd_id128_get_machine.xml @@ -78,7 +78,7 @@ sd_id128_get_machine() when passing an ID to untrusted environments, in order to make sure that the original machine ID may not be determined externally. This way, the ID used by the application remains stable on a given machine, but cannot be easily correlated with IDs used in other applications on the same - machine. The application-specific ID should be generated via a tool like journalctl --new-id128, + machine. The application-specific ID should be generated via a tool like systemd-id128 new, and may be compiled into the application. This function will return the same application-specific ID for each combination of machine ID and application ID. Internally, this function calculates HMAC-SHA256 of the application ID, keyed by the machine ID. @@ -145,6 +145,7 @@ systemd1, + systemd-id1281, sd-id1283, machine-id5, systemd.exec5, diff --git a/meson.build b/meson.build index 1c4febfa4b..49da6825e0 100644 --- a/meson.build +++ b/meson.build @@ -2323,6 +2323,14 @@ executable('systemd-cgroups-agent', install : true, install_dir : rootlibexecdir) +exe = executable('systemd-id128', + 'src/id128/id128.c', + include_directories : includes, + link_with : [libshared], + install_rpath : rootlibexecdir, + install : true) +public_programs += exe + exe = executable('systemd-path', 'src/path/path.c', include_directories : includes, diff --git a/src/id128/id128.c b/src/id128/id128.c new file mode 100644 index 0000000000..a6391313be --- /dev/null +++ b/src/id128/id128.c @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include +#include + +#include "alloc-util.h" +#include "id128-print.h" +#include "terminal-util.h" +#include "util.h" +#include "verbs.h" + +static bool arg_pretty = false; +static sd_id128_t arg_app = {}; + +static int verb_new(int argc, char **argv, void *userdata) { + return id128_print_new(arg_pretty); +} + +static int verb_machine_id(int argc, char **argv, void *userdata) { + sd_id128_t id; + int r; + + if (sd_id128_is_null(arg_app)) + r = sd_id128_get_machine(&id); + else + r = sd_id128_get_machine_app_specific(arg_app, &id); + if (r < 0) + return log_error_errno(r, "Failed to get %smachine-ID: %m", + sd_id128_is_null(arg_app) ? "" : "app-specific "); + + return id128_pretty_print(id, arg_pretty); +} + +static int verb_boot_id(int argc, char **argv, void *userdata) { + sd_id128_t id; + int r; + + if (sd_id128_is_null(arg_app)) + r = sd_id128_get_boot(&id); + else + r = sd_id128_get_boot_app_specific(arg_app, &id); + if (r < 0) + return log_error_errno(r, "Failed to get %sboot-ID: %m", + sd_id128_is_null(arg_app) ? "" : "app-specific "); + + return id128_pretty_print(id, arg_pretty); +} + +static int verb_invocation_id(int argc, char **argv, void *userdata) { + sd_id128_t id; + int r; + + if (!sd_id128_is_null(arg_app)) + return log_error_errno(EINVAL, "Verb \"invocation-id\" cannot be combined with --app-specific=."); + + r = sd_id128_get_invocation(&id); + if (r < 0) + return log_error_errno(r, "Failed to get invocation-ID: %m"); + + return id128_pretty_print(id, arg_pretty); +} + +static int help(void) { + _cleanup_free_ char *link = NULL; + int r; + + r = terminal_urlify_man("systemd-id128", "1", &link); + if (r < 0) + return log_oom(); + + printf("%s [OPTIONS...] {COMMAND} ...\n\n" + "Generate and print id128 strings.\n\n" + " -h --help Show this help\n\n" + " -p --pretty Generate samples of program code\n\n" + " -a --app-specific=ID Generate app-specific IDs\n\n" + "Commands:\n" + " new Generate a new id128 string\n" + " machine-id Print the ID of current machine\n" + " boot-id Print the ID of current boot\n" + " invocation-id Print the ID of current invocation\n" + " help Show this help\n" + "\nSee the %s for details.\n" + , program_invocation_short_name + , link + ); + + return 0; +} + +static int verb_help(int argc, char **argv, void *userdata) { + return help(); +} + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "app-specific", required_argument, NULL, 'a' }, + {}, + }; + + int c, r; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hpa:", options, NULL)) >= 0) + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + return version(); + + case 'p': + arg_pretty = true; + break; + + case 'a': + r = sd_id128_from_string(optarg, &arg_app); + if (r < 0) + return log_error_errno(r, "Failed to parse \"%s\" as application-ID: %m", optarg); + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + + return 1; +} + +static int id128_main(int argc, char *argv[]) { + static const Verb verbs[] = { + { "new", VERB_ANY, 1, 0, verb_new }, + { "machine-id", VERB_ANY, 1, 0, verb_machine_id }, + { "boot-id", VERB_ANY, 1, 0, verb_boot_id }, + { "invocation-id", VERB_ANY, 1, 0, verb_invocation_id }, + { "help", VERB_ANY, VERB_ANY, 0, verb_help }, + {} + }; + + return dispatch_verb(argc, argv, verbs, NULL); +} + +int main(int argc, char *argv[]) { + int r; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = id128_main(argc, argv); + + finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 3ff4d29664..b42f676bae 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -2064,7 +2064,7 @@ int main(int argc, char *argv[]) { switch (arg_action) { case ACTION_NEW_ID128: - r = id128_generate_new(); + r = id128_print_new(true); goto finish; case ACTION_SETUP_KEYS: diff --git a/src/shared/id128-print.c b/src/shared/id128-print.c index 212080fbcc..5b5dac605a 100644 --- a/src/shared/id128-print.c +++ b/src/shared/id128-print.c @@ -7,14 +7,14 @@ #include "id128-print.h" #include "log.h" -int id128_generate_new(void) { - sd_id128_t id; - int r; +int id128_pretty_print(sd_id128_t id, bool pretty) { unsigned i; - r = sd_id128_randomize(&id); - if (r < 0) - return log_error_errno(r, "Failed to generate ID: %m"); + if (!pretty) { + printf(SD_ID128_FORMAT_STR "\n", + SD_ID128_FORMAT_VAL(id)); + return 0; + } printf("As string:\n" SD_ID128_FORMAT_STR "\n\n" @@ -35,3 +35,14 @@ int id128_generate_new(void) { return 0; } + +int id128_print_new(bool pretty) { + sd_id128_t id; + int r; + + r = sd_id128_randomize(&id); + if (r < 0) + return log_error_errno(r, "Failed to generate ID: %m"); + + return id128_pretty_print(id, pretty); +} diff --git a/src/shared/id128-print.h b/src/shared/id128-print.h index 6b5b331bbf..5d50de0fc8 100644 --- a/src/shared/id128-print.h +++ b/src/shared/id128-print.h @@ -2,4 +2,9 @@ #pragma once -int id128_generate_new(void); +#include + +#include "sd-id128.h" + +int id128_pretty_print(sd_id128_t id, bool pretty); +int id128_print_new(bool pretty);