diff --git a/TODO b/TODO
index f848b9741e..0079b35963 100644
--- a/TODO
+++ b/TODO
@@ -181,10 +181,6 @@ Features:
* add bpf-based implementation of devices cgroup controller logic for compat
with cgroupsv2 as supported by newest kernel
-* introduce sd_id128_get_boot_app_specific() which is like
- sd_id128_get_machine_app_specific(). After all on long-running systems both
- IDs have similar properties.
-
* sd-bus: add vtable flag, that may be used to request client creds implicitly
and asynchronously before dispatching the operation
diff --git a/man/rules/meson.build b/man/rules/meson.build
index 99915c5e9f..303b584654 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -438,6 +438,7 @@ manpages = [
['sd_id128_get_machine',
'3',
['sd_id128_get_boot',
+ 'sd_id128_get_boot_app_specific',
'sd_id128_get_invocation',
'sd_id128_get_machine_app_specific'],
''],
@@ -658,6 +659,7 @@ manpages = [
'ENABLE_HIBERNATE'],
['systemd-hostnamed.service', '8', ['systemd-hostnamed'], 'ENABLE_HOSTNAMED'],
['systemd-hwdb', '8', [], 'ENABLE_HWDB'],
+ ['systemd-id128', '1', [], ''],
['systemd-importd.service', '8', ['systemd-importd'], 'ENABLE_IMPORTD'],
['systemd-inhibit', '1', [], ''],
['systemd-initctl.service',
diff --git a/man/sd_id128_get_machine.xml b/man/sd_id128_get_machine.xml
index 9587aa7d66..0884838324 100644
--- a/man/sd_id128_get_machine.xml
+++ b/man/sd_id128_get_machine.xml
@@ -22,6 +22,7 @@
sd_id128_get_machinesd_id128_get_machine_app_specificsd_id128_get_boot
+ sd_id128_get_boot_app_specificsd_id128_get_invocationRetrieve 128-bit IDs
@@ -46,6 +47,12 @@
sd_id128_t *ret
+
+ int sd_id128_get_boot_app_specific
+ sd_id128_t app_id
+ sd_id128_t *ret
+
+
int sd_id128_get_invocationsd_id128_t *ret
@@ -69,19 +76,25 @@
sd_id128_get_machine(), but retrieves a machine ID that is specific to the application that is
identified by the indicated application ID. It is recommended to use this function instead of
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. The application-specific ID should be generated via
- a tool like journalctl --new-id128, 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.
+ 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 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.
- sd_id128_get_boot() returns the boot ID
- of the executing kernel. This reads and parses the
- /proc/sys/kernel/random/boot_id file exposed
- by the kernel. It is randomly generated early at boot and is
- unique for every running kernel instance. See
- random4
- for more information. This function also internally caches the
- returned ID to make this call a cheap operation.
+ sd_id128_get_boot() returns the boot ID of the executing kernel. This reads and parses
+ the /proc/sys/kernel/random/boot_id file exposed by the kernel. It is randomly generated early
+ at boot and is unique for every running kernel instance. See random4 for more
+ information. This function also internally caches the returned ID to make this call a cheap operation. It is
+ recommended to use this ID as-is only in trusted environments. In untrusted environments it is recommended to
+ derive an application specific ID using sd_id128_get_machine_app_specific(), see below.
+
+ sd_id128_get_boot_app_specific() is analogous to
+ sd_id128_get_machine_app_specific() but returns an ID that changes between boots. Some
+ machines may be used for a long time without rebooting, hence the boot ID may remain constant for a long time, and
+ has properties similar to the machine ID during that time.sd_id128_get_invocation() returns the invocation ID of the currently executed
service. In its current implementation, this reads and parses the $INVOCATION_ID environment
@@ -89,10 +102,11 @@
systemd.exec5 for details. The
ID is cached internally. In future a different mechanism to determine the invocation ID may be added.
- Note that sd_id128_get_machine_app_specific(), sd_id128_get_boot()
- and sd_id128_get_invocation() always return UUID v4 compatible IDs.
- sd_id128_get_machine() will also return a UUID v4-compatible ID on new installations but might
- not on older. It is possible to convert the machine ID into a UUID v4-compatible one. For more information, see
+ Note that sd_id128_get_machine_app_specific(), sd_id128_get_boot(),
+ sd_id128_get_boot_app_specific(), and sd_id128_get_invocation() always
+ return UUID v4 compatible IDs. sd_id128_get_machine() will also return a UUID v4-compatible
+ ID on new installations but might not on older. It is possible to convert the machine ID into a UUID v4-compatible
+ one. For more information, see
machine-id5.For more information about the sd_id128_t
@@ -104,10 +118,12 @@
Return ValueThose calls return 0 on success (in which case ret is filled in),
- or a negative errno-style error code. In particular, sd_id128_get_machine()
- and sd_id128_get_machine_app_specific() return -ENOENT
- if /etc/machine-id is missing, and -ENOMEDIUM if is
- empty or all zeros.
+ or a negative errno-style error code. In particular,
+ sd_id128_get_machine(),
+ sd_id128_get_machine_app_specific(), and
+ sd_id128_get_boot_app_specific() return -ENOENT if
+ /etc/machine-id is missing, and -ENOMEDIUM if is empty
+ or all zeros.
@@ -118,7 +134,20 @@
Application-specific machine ID
- Here's a simple example for an application specific machine ID:
+ First, generate the application ID:
+ $ systemd-id128 -p new
+As string:
+c273277323db454ea63bb96e79b53e97
+
+As UUID:
+c2732773-23db-454e-a63b-b96e79b53e97
+
+As man:sd-id128(3) macro:
+#define MESSAGE_XYZ SD_ID128_MAKE(c2,73,27,73,23,db,45,4e,a6,3b,b9,6e,79,b5,3e,97)
+...
+
+
+ Then use the new identifier in an example application:
@@ -129,6 +158,7 @@
systemd1,
+ systemd-id1281,
sd-id1283,
machine-id5,
systemd.exec5,
diff --git a/man/systemd-id128.xml b/man/systemd-id128.xml
new file mode 100644
index 0000000000..8a76cccd86
--- /dev/null
+++ b/man/systemd-id128.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+ systemd-id128
+ systemd
+
+
+
+ systemd-id128
+ 1
+
+
+
+ systemd-id128
+ Generate and print sd-128 identifiers
+
+
+
+
+ systemd-id128
+ OPTIONS
+ new
+
+
+
+ systemd-id128
+ OPTIONS
+ machine-id
+
+
+
+ systemd-id128
+ OPTIONS
+ boot-id
+
+
+
+ systemd-id128
+ OPTIONS
+ invocation-id
+
+
+
+
+ Description
+
+ id128 may be used to conveniently print
+ sd-id1283
+ UUIDs. What identifier is printed depends on the specific verb.
+
+ With new, a new random identifier will be generated.
+
+ With machine-id, the identifier of the current machine will be
+ printed. See
+ machine-id5.
+
+
+ With boot-id, the identifier of the current boot will be
+ printed.
+
+ Both machine-id and boot-id may be combined
+ with the switch to
+ generate application-specific IDs. See
+ sd_id128_get_machine3
+ for the discussion when this is useful.
+
+ With invocation-id, the identifier of the current service invocation
+ will be printed. This is available in systemd services. See
+ systemd.exec5.
+
+
+
+
+ Options
+
+ The following options are understood:
+
+
+
+
+
+
+ Generate output as programming language snippets.
+
+
+
+
+
+
+ With this option, an identifier that is the result of hashing the
+ application identifier app-id and the machine identifier will be
+ printed. The app-id argument must be a valid sd-id128 string
+ identifying the application.
+
+
+
+
+
+
+
+
+
+ Exit status
+
+ On success, 0 is returned, a non-zero failure code otherwise.
+
+
+
+ See Also
+
+ systemd1,
+ sd-id1283,
+ sd_id128_get_machine3
+
+
+
+
diff --git a/meson.build b/meson.build
index 02e230415d..554e67e5dd 100644
--- a/meson.build
+++ b/meson.build
@@ -2324,6 +2324,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 a9e4af1dd8..b42f676bae 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -38,6 +38,7 @@
#include "fsprg.h"
#include "glob-util.h"
#include "hostname-util.h"
+#include "id128-print.h"
#include "io-util.h"
#include "journal-def.h"
#include "journal-internal.h"
@@ -1007,35 +1008,6 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
-static int generate_new_id128(void) {
- sd_id128_t id;
- int r;
- unsigned i;
-
- r = sd_id128_randomize(&id);
- if (r < 0)
- return log_error_errno(r, "Failed to generate ID: %m");
-
- printf("As string:\n"
- SD_ID128_FORMAT_STR "\n\n"
- "As UUID:\n"
- "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
- "As man:sd-id128(3) macro:\n"
- "#define MESSAGE_XYZ SD_ID128_MAKE(",
- SD_ID128_FORMAT_VAL(id),
- SD_ID128_FORMAT_VAL(id));
- for (i = 0; i < 16; i++)
- printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
- fputs(")\n\n", stdout);
-
- printf("As Python constant:\n"
- ">>> import uuid\n"
- ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
- SD_ID128_FORMAT_VAL(id));
-
- return 0;
-}
-
static int add_matches(sd_journal *j, char **args) {
char **i;
bool have_term = false;
@@ -2092,7 +2064,7 @@ int main(int argc, char *argv[]) {
switch (arg_action) {
case ACTION_NEW_ID128:
- r = generate_new_id128();
+ r = id128_print_new(true);
goto finish;
case ACTION_SETUP_KEYS:
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index d06e95638e..480ef39c7a 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -648,4 +648,6 @@ global:
sd_hwdb_enumerate;
sd_hwdb_unrefp;
+
+ sd_id128_get_boot_app_specific;
} LIBSYSTEMD_239;
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index 9d93732d7e..b7cca832d8 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -284,19 +284,15 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
return 0;
}
-_public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
+static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret) {
_cleanup_(khash_unrefp) khash *h = NULL;
- sd_id128_t m, result;
+ sd_id128_t result;
const void *p;
int r;
- assert_return(ret, -EINVAL);
+ assert(ret);
- r = sd_id128_get_machine(&m);
- if (r < 0)
- return r;
-
- r = khash_new_with_key(&h, "hmac(sha256)", &m, sizeof(m));
+ r = khash_new_with_key(&h, "hmac(sha256)", &base, sizeof(base));
if (r < 0)
return r;
@@ -314,3 +310,29 @@ _public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *re
*ret = make_v4_uuid(result);
return 0;
}
+
+_public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
+ sd_id128_t id;
+ int r;
+
+ assert_return(ret, -EINVAL);
+
+ r = sd_id128_get_machine(&id);
+ if (r < 0)
+ return r;
+
+ return get_app_specific(id, app_id, ret);
+}
+
+_public_ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
+ sd_id128_t id;
+ int r;
+
+ assert_return(ret, -EINVAL);
+
+ r = sd_id128_get_boot(&id);
+ if (r < 0)
+ return r;
+
+ return get_app_specific(id, app_id, ret);
+}
diff --git a/src/shared/id128-print.c b/src/shared/id128-print.c
new file mode 100644
index 0000000000..eea3ee5ca8
--- /dev/null
+++ b/src/shared/id128-print.c
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include
+
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "id128-print.h"
+#include "log.h"
+#include "terminal-util.h"
+
+int id128_pretty_print(sd_id128_t id, bool pretty) {
+ unsigned i;
+ _cleanup_free_ char *man_link = NULL, *mod_link = NULL;
+ const char *on, *off;
+
+ if (!pretty) {
+ printf(SD_ID128_FORMAT_STR "\n",
+ SD_ID128_FORMAT_VAL(id));
+ return 0;
+ }
+
+ on = ansi_highlight();
+ off = ansi_normal();
+
+ if (terminal_urlify("man:systemd-id128(1)", "systemd-id128(1)", &man_link) < 0)
+ return log_oom();
+
+ if (terminal_urlify("https://docs.python.org/3/library/uuid.html", "uuid", &mod_link) < 0)
+ return log_oom();
+
+ printf("As string:\n"
+ "%s" SD_ID128_FORMAT_STR "%s\n\n"
+ "As UUID:\n"
+ "%s%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%s\n\n"
+ "As %s macro:\n"
+ "%s#define MESSAGE_XYZ SD_ID128_MAKE(",
+ on, SD_ID128_FORMAT_VAL(id), off,
+ on, SD_ID128_FORMAT_VAL(id), off,
+ man_link,
+ on);
+ for (i = 0; i < 16; i++)
+ printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
+ printf(")%s\n\n", off);
+
+ printf("As Python constant:\n"
+ ">>> import %s\n"
+ ">>> %sMESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')%s\n",
+ mod_link,
+ on, SD_ID128_FORMAT_VAL(id), off);
+
+ 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
new file mode 100644
index 0000000000..5d50de0fc8
--- /dev/null
+++ b/src/shared/id128-print.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#pragma once
+
+#include
+
+#include "sd-id128.h"
+
+int id128_pretty_print(sd_id128_t id, bool pretty);
+int id128_print_new(bool pretty);
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 17370f4048..498b73c750 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -44,6 +44,8 @@ shared_sources = files('''
generator.c
generator.h
gpt.h
+ id128-print.c
+ id128-print.h
ima-util.c
ima-util.h
import-util.c
diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h
index 143a0ffb5e..78cf9462b0 100644
--- a/src/systemd/sd-id128.h
+++ b/src/systemd/sd-id128.h
@@ -42,6 +42,7 @@ int sd_id128_randomize(sd_id128_t *ret);
int sd_id128_get_machine(sd_id128_t *ret);
int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret);
+int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
int sd_id128_get_boot(sd_id128_t *ret);
int sd_id128_get_invocation(sd_id128_t *ret);