|
Packit Service |
87a54e |
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include "nm-sd-adapt-core.h"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include <errno.h>
|
|
Packit |
5756e2 |
#include <fcntl.h>
|
|
Packit |
5756e2 |
#include <unistd.h>
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include "sd-id128.h"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include "alloc-util.h"
|
|
Packit |
5756e2 |
#include "fd-util.h"
|
|
Packit |
5756e2 |
#include "hexdecoct.h"
|
|
Packit |
5756e2 |
#include "id128-util.h"
|
|
Packit |
5756e2 |
#include "io-util.h"
|
|
Packit |
5756e2 |
#include "khash.h"
|
|
Packit |
5756e2 |
#include "macro.h"
|
|
Packit |
5756e2 |
#include "missing_syscall.h"
|
|
Packit |
5756e2 |
#include "random-util.h"
|
|
Packit |
5756e2 |
#include "user-util.h"
|
|
Packit |
5756e2 |
#include "util.h"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#if 0 /* NM_IGNORED */
|
|
Packit |
5756e2 |
_public_ char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]) {
|
|
Packit |
5756e2 |
unsigned n;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
assert_return(s, NULL);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
for (n = 0; n < 16; n++) {
|
|
Packit |
5756e2 |
s[n*2] = hexchar(id.bytes[n] >> 4);
|
|
Packit |
5756e2 |
s[n*2+1] = hexchar(id.bytes[n] & 0xF);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
s[32] = 0;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
return s;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
#endif /* NM_IGNORED */
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
|
|
Packit |
5756e2 |
unsigned n, i;
|
|
Packit |
5756e2 |
sd_id128_t t;
|
|
Packit |
5756e2 |
bool is_guid = false;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
assert_return(s, -EINVAL);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
for (n = 0, i = 0; n < 16;) {
|
|
Packit |
5756e2 |
int a, b;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
if (s[i] == '-') {
|
|
Packit |
5756e2 |
/* Is this a GUID? Then be nice, and skip over
|
|
Packit |
5756e2 |
* the dashes */
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
if (i == 8)
|
|
Packit |
5756e2 |
is_guid = true;
|
|
Packit |
5756e2 |
else if (IN_SET(i, 13, 18, 23)) {
|
|
Packit |
5756e2 |
if (!is_guid)
|
|
Packit |
5756e2 |
return -EINVAL;
|
|
Packit |
5756e2 |
} else
|
|
Packit |
5756e2 |
return -EINVAL;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
i++;
|
|
Packit |
5756e2 |
continue;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
a = unhexchar(s[i++]);
|
|
Packit |
5756e2 |
if (a < 0)
|
|
Packit |
5756e2 |
return -EINVAL;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
b = unhexchar(s[i++]);
|
|
Packit |
5756e2 |
if (b < 0)
|
|
Packit |
5756e2 |
return -EINVAL;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
t.bytes[n++] = (a << 4) | b;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
if (i != (is_guid ? 36 : 32))
|
|
Packit |
5756e2 |
return -EINVAL;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
if (s[i] != 0)
|
|
Packit |
5756e2 |
return -EINVAL;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
if (ret)
|
|
Packit |
5756e2 |
*ret = t;
|
|
Packit |
5756e2 |
return 0;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
_public_ int sd_id128_get_machine(sd_id128_t *ret) {
|
|
Packit |
5756e2 |
static thread_local sd_id128_t saved_machine_id = {};
|
|
Packit |
5756e2 |
int r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
assert_return(ret, -EINVAL);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
if (sd_id128_is_null(saved_machine_id)) {
|
|
Packit |
5756e2 |
r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id);
|
|
Packit |
5756e2 |
if (r < 0)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
if (sd_id128_is_null(saved_machine_id))
|
|
Packit |
5756e2 |
return -ENOMEDIUM;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
*ret = saved_machine_id;
|
|
Packit |
5756e2 |
return 0;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
_public_ int sd_id128_get_boot(sd_id128_t *ret) {
|
|
Packit |
5756e2 |
static thread_local sd_id128_t saved_boot_id = {};
|
|
Packit |
5756e2 |
int r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
assert_return(ret, -EINVAL);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
if (sd_id128_is_null(saved_boot_id)) {
|
|
Packit |
5756e2 |
r = id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID, &saved_boot_id);
|
|
Packit |
5756e2 |
if (r < 0)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
*ret = saved_boot_id;
|
|
Packit |
5756e2 |
return 0;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#if 0 /* NM_IGNORED */
|
|
Packit |
5756e2 |
static int get_invocation_from_keyring(sd_id128_t *ret) {
|
|
Packit |
5756e2 |
_cleanup_free_ char *description = NULL;
|
|
Packit |
5756e2 |
char *d, *p, *g, *u, *e;
|
|
Packit |
5756e2 |
unsigned long perms;
|
|
Packit |
5756e2 |
key_serial_t key;
|
|
Packit |
5756e2 |
size_t sz = 256;
|
|
Packit |
5756e2 |
uid_t uid;
|
|
Packit |
5756e2 |
gid_t gid;
|
|
Packit |
5756e2 |
int r, c;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#define MAX_PERMS ((unsigned long) (KEY_POS_VIEW|KEY_POS_READ|KEY_POS_SEARCH| \
|
|
Packit |
5756e2 |
KEY_USR_VIEW|KEY_USR_READ|KEY_USR_SEARCH))
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
assert(ret);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
key = request_key("user", "invocation_id", NULL, 0);
|
|
Packit |
5756e2 |
if (key == -1) {
|
|
Packit |
5756e2 |
/* Keyring support not available? No invocation key stored? */
|
|
Packit |
5756e2 |
if (IN_SET(errno, ENOSYS, ENOKEY))
|
|
Packit |
5756e2 |
return -ENXIO;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
return -errno;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
for (;;) {
|
|
Packit |
5756e2 |
description = new(char, sz);
|
|
Packit |
5756e2 |
if (!description)
|
|
Packit |
5756e2 |
return -ENOMEM;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
c = keyctl(KEYCTL_DESCRIBE, key, (unsigned long) description, sz, 0);
|
|
Packit |
5756e2 |
if (c < 0)
|
|
Packit |
5756e2 |
return -errno;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
if ((size_t) c <= sz)
|
|
Packit |
5756e2 |
break;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
sz = c;
|
|
Packit |
5756e2 |
free(description);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/* The kernel returns a final NUL in the string, verify that. */
|
|
Packit |
5756e2 |
assert(description[c-1] == 0);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/* Chop off the final description string */
|
|
Packit |
5756e2 |
d = strrchr(description, ';');
|
|
Packit |
5756e2 |
if (!d)
|
|
Packit |
5756e2 |
return -EIO;
|
|
Packit |
5756e2 |
*d = 0;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/* Look for the permissions */
|
|
Packit |
5756e2 |
p = strrchr(description, ';');
|
|
Packit |
5756e2 |
if (!p)
|
|
Packit |
5756e2 |
return -EIO;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
errno = 0;
|
|
Packit |
5756e2 |
perms = strtoul(p + 1, &e, 16);
|
|
Packit |
5756e2 |
if (errno > 0)
|
|
Packit |
5756e2 |
return -errno;
|
|
Packit |
5756e2 |
if (e == p + 1) /* Read at least one character */
|
|
Packit |
5756e2 |
return -EIO;
|
|
Packit |
5756e2 |
if (e != d) /* Must reached the end */
|
|
Packit |
5756e2 |
return -EIO;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
if ((perms & ~MAX_PERMS) != 0)
|
|
Packit |
5756e2 |
return -EPERM;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
*p = 0;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/* Look for the group ID */
|
|
Packit |
5756e2 |
g = strrchr(description, ';');
|
|
Packit |
5756e2 |
if (!g)
|
|
Packit |
5756e2 |
return -EIO;
|
|
Packit |
5756e2 |
r = parse_gid(g + 1, &gid;;
|
|
Packit |
5756e2 |
if (r < 0)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
if (gid != 0)
|
|
Packit |
5756e2 |
return -EPERM;
|
|
Packit |
5756e2 |
*g = 0;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/* Look for the user ID */
|
|
Packit |
5756e2 |
u = strrchr(description, ';');
|
|
Packit |
5756e2 |
if (!u)
|
|
Packit |
5756e2 |
return -EIO;
|
|
Packit |
5756e2 |
r = parse_uid(u + 1, &uid);
|
|
Packit |
5756e2 |
if (r < 0)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
if (uid != 0)
|
|
Packit |
5756e2 |
return -EPERM;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
c = keyctl(KEYCTL_READ, key, (unsigned long) ret, sizeof(sd_id128_t), 0);
|
|
Packit |
5756e2 |
if (c < 0)
|
|
Packit |
5756e2 |
return -errno;
|
|
Packit |
5756e2 |
if (c != sizeof(sd_id128_t))
|
|
Packit |
5756e2 |
return -EIO;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
return 0;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static int get_invocation_from_environment(sd_id128_t *ret) {
|
|
Packit |
5756e2 |
const char *e;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
assert(ret);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
e = secure_getenv("INVOCATION_ID");
|
|
Packit |
5756e2 |
if (!e)
|
|
Packit |
5756e2 |
return -ENXIO;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
return sd_id128_from_string(e, ret);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
_public_ int sd_id128_get_invocation(sd_id128_t *ret) {
|
|
Packit |
5756e2 |
static thread_local sd_id128_t saved_invocation_id = {};
|
|
Packit |
5756e2 |
int r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
assert_return(ret, -EINVAL);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
if (sd_id128_is_null(saved_invocation_id)) {
|
|
Packit |
5756e2 |
/* We first check the environment. The environment variable is primarily relevant for user
|
|
Packit |
5756e2 |
* services, and sufficiently safe as long as no privilege boundary is involved. */
|
|
Packit |
5756e2 |
r = get_invocation_from_environment(&saved_invocation_id);
|
|
Packit |
5756e2 |
if (r < 0 && r != -ENXIO)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/* The kernel keyring is relevant for system services (as for user services we don't store
|
|
Packit |
5756e2 |
* the invocation ID in the keyring, as there'd be no trust benefit in that). */
|
|
Packit |
5756e2 |
r = get_invocation_from_keyring(&saved_invocation_id);
|
|
Packit |
5756e2 |
if (r < 0)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
*ret = saved_invocation_id;
|
|
Packit |
5756e2 |
return 0;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
_public_ int sd_id128_randomize(sd_id128_t *ret) {
|
|
Packit |
5756e2 |
sd_id128_t t;
|
|
Packit |
5756e2 |
int r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
assert_return(ret, -EINVAL);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/* We allow usage if x86-64 RDRAND here. It might not be trusted enough for keeping secrets, but it should be
|
|
Packit |
5756e2 |
* fine for UUIDS. */
|
|
Packit |
5756e2 |
r = genuine_random_bytes(&t, sizeof t, RANDOM_ALLOW_RDRAND);
|
|
Packit |
5756e2 |
if (r < 0)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/* Turn this into a valid v4 UUID, to be nice. Note that we
|
|
Packit |
5756e2 |
* only guarantee this for newly generated UUIDs, not for
|
|
Packit |
5756e2 |
* pre-existing ones. */
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
*ret = id128_make_v4_uuid(t);
|
|
Packit |
5756e2 |
return 0;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret) {
|
|
Packit |
5756e2 |
_cleanup_(khash_unrefp) khash *h = NULL;
|
|
Packit |
5756e2 |
sd_id128_t result;
|
|
Packit |
5756e2 |
const void *p;
|
|
Packit |
5756e2 |
int r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
assert(ret);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
r = khash_new_with_key(&h, "hmac(sha256)", &base, sizeof(base));
|
|
Packit |
5756e2 |
if (r < 0)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
r = khash_put(h, &app_id, sizeof(app_id));
|
|
Packit |
5756e2 |
if (r < 0)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
r = khash_digest_data(h, &p);
|
|
Packit |
5756e2 |
if (r < 0)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/* We chop off the trailing 16 bytes */
|
|
Packit |
5756e2 |
memcpy(&result, p, MIN(khash_get_size(h), sizeof(result)));
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
*ret = id128_make_v4_uuid(result);
|
|
Packit |
5756e2 |
return 0;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
_public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
|
|
Packit |
5756e2 |
sd_id128_t id;
|
|
Packit |
5756e2 |
int r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
assert_return(ret, -EINVAL);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
r = sd_id128_get_machine(&id;;
|
|
Packit |
5756e2 |
if (r < 0)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
return get_app_specific(id, app_id, ret);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
_public_ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
|
|
Packit |
5756e2 |
sd_id128_t id;
|
|
Packit |
5756e2 |
int r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
assert_return(ret, -EINVAL);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
r = sd_id128_get_boot(&id;;
|
|
Packit |
5756e2 |
if (r < 0)
|
|
Packit |
5756e2 |
return r;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
return get_app_specific(id, app_id, ret);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
#endif /* NM_IGNORED */
|