1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "alloc-util.h"
11 #include "hexdecoct.h"
13 #include "id128-util.h"
16 #include "missing_syscall.h"
17 #include "missing_threads.h"
18 #include "random-util.h"
19 #include "user-util.h"
22 _public_
char *sd_id128_to_string(sd_id128_t id
, char s
[_SD_ARRAY_STATIC SD_ID128_STRING_MAX
]) {
25 assert_return(s
, NULL
);
27 for (size_t n
= 0; n
< sizeof(sd_id128_t
); n
++) {
28 s
[k
++] = hexchar(id
.bytes
[n
] >> 4);
29 s
[k
++] = hexchar(id
.bytes
[n
] & 0xF);
32 assert(k
== SD_ID128_STRING_MAX
- 1);
38 _public_
char *sd_id128_to_uuid_string(sd_id128_t id
, char s
[_SD_ARRAY_STATIC SD_ID128_UUID_STRING_MAX
]) {
41 assert_return(s
, NULL
);
43 /* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
45 for (size_t n
= 0; n
< sizeof(sd_id128_t
); n
++) {
47 if (IN_SET(n
, 4, 6, 8, 10))
50 s
[k
++] = hexchar(id
.bytes
[n
] >> 4);
51 s
[k
++] = hexchar(id
.bytes
[n
] & 0xF);
54 assert(k
== SD_ID128_UUID_STRING_MAX
- 1);
60 _public_
int sd_id128_from_string(const char *s
, sd_id128_t
*ret
) {
65 assert_return(s
, -EINVAL
);
67 for (n
= 0, i
= 0; n
< sizeof(sd_id128_t
);) {
71 /* Is this a GUID? Then be nice, and skip over
76 else if (IN_SET(i
, 13, 18, 23)) {
86 a
= unhexchar(s
[i
++]);
90 b
= unhexchar(s
[i
++]);
94 t
.bytes
[n
++] = (a
<< 4) | b
;
97 if (i
!= (is_guid
? SD_ID128_UUID_STRING_MAX
: SD_ID128_STRING_MAX
) - 1)
108 _public_
int sd_id128_string_equal(const char *s
, sd_id128_t id
) {
115 /* Checks if the specified string matches a valid string representation of the specified 128 bit ID/uuid */
117 r
= sd_id128_from_string(s
, &parsed
);
121 return sd_id128_equal(parsed
, id
);
124 _public_
int sd_id128_get_machine(sd_id128_t
*ret
) {
125 static thread_local sd_id128_t saved_machine_id
= {};
128 assert_return(ret
, -EINVAL
);
130 if (sd_id128_is_null(saved_machine_id
)) {
131 r
= id128_read("/etc/machine-id", ID128_FORMAT_PLAIN
, &saved_machine_id
);
135 if (sd_id128_is_null(saved_machine_id
))
139 *ret
= saved_machine_id
;
143 _public_
int sd_id128_get_boot(sd_id128_t
*ret
) {
144 static thread_local sd_id128_t saved_boot_id
= {};
147 assert_return(ret
, -EINVAL
);
149 if (sd_id128_is_null(saved_boot_id
)) {
150 r
= id128_read("/proc/sys/kernel/random/boot_id", ID128_FORMAT_UUID
, &saved_boot_id
);
155 *ret
= saved_boot_id
;
159 static int get_invocation_from_keyring(sd_id128_t
*ret
) {
160 _cleanup_free_
char *description
= NULL
;
161 char *d
, *p
, *g
, *u
, *e
;
169 #define MAX_PERMS ((unsigned long) (KEY_POS_VIEW|KEY_POS_READ|KEY_POS_SEARCH| \
170 KEY_USR_VIEW|KEY_USR_READ|KEY_USR_SEARCH))
174 key
= request_key("user", "invocation_id", NULL
, 0);
176 /* Keyring support not available? No invocation key stored? */
177 if (IN_SET(errno
, ENOSYS
, ENOKEY
))
184 description
= new(char, sz
);
188 c
= keyctl(KEYCTL_DESCRIBE
, key
, (unsigned long) description
, sz
, 0);
192 if ((size_t) c
<= sz
)
199 /* The kernel returns a final NUL in the string, verify that. */
200 assert(description
[c
-1] == 0);
202 /* Chop off the final description string */
203 d
= strrchr(description
, ';');
208 /* Look for the permissions */
209 p
= strrchr(description
, ';');
214 perms
= strtoul(p
+ 1, &e
, 16);
217 if (e
== p
+ 1) /* Read at least one character */
219 if (e
!= d
) /* Must reached the end */
222 if ((perms
& ~MAX_PERMS
) != 0)
227 /* Look for the group ID */
228 g
= strrchr(description
, ';');
231 r
= parse_gid(g
+ 1, &gid
);
238 /* Look for the user ID */
239 u
= strrchr(description
, ';');
242 r
= parse_uid(u
+ 1, &uid
);
248 c
= keyctl(KEYCTL_READ
, key
, (unsigned long) ret
, sizeof(sd_id128_t
), 0);
251 if (c
!= sizeof(sd_id128_t
))
257 static int get_invocation_from_environment(sd_id128_t
*ret
) {
262 e
= secure_getenv("INVOCATION_ID");
266 return sd_id128_from_string(e
, ret
);
269 _public_
int sd_id128_get_invocation(sd_id128_t
*ret
) {
270 static thread_local sd_id128_t saved_invocation_id
= {};
273 assert_return(ret
, -EINVAL
);
275 if (sd_id128_is_null(saved_invocation_id
)) {
276 /* We first check the environment. The environment variable is primarily relevant for user
277 * services, and sufficiently safe as long as no privilege boundary is involved. */
278 r
= get_invocation_from_environment(&saved_invocation_id
);
280 *ret
= saved_invocation_id
;
282 } else if (r
!= -ENXIO
)
285 /* The kernel keyring is relevant for system services (as for user services we don't store
286 * the invocation ID in the keyring, as there'd be no trust benefit in that). */
287 r
= get_invocation_from_keyring(&saved_invocation_id
);
292 *ret
= saved_invocation_id
;
296 _public_
int sd_id128_randomize(sd_id128_t
*ret
) {
299 assert_return(ret
, -EINVAL
);
301 random_bytes(&t
, sizeof(t
));
303 /* Turn this into a valid v4 UUID, to be nice. Note that we
304 * only guarantee this for newly generated UUIDs, not for
305 * pre-existing ones. */
307 *ret
= id128_make_v4_uuid(t
);
311 static int get_app_specific(sd_id128_t base
, sd_id128_t app_id
, sd_id128_t
*ret
) {
312 uint8_t hmac
[SHA256_DIGEST_SIZE
];
317 hmac_sha256(&base
, sizeof(base
), &app_id
, sizeof(app_id
), hmac
);
319 /* Take only the first half. */
320 memcpy(&result
, hmac
, MIN(sizeof(hmac
), sizeof(result
)));
322 *ret
= id128_make_v4_uuid(result
);
326 _public_
int sd_id128_get_machine_app_specific(sd_id128_t app_id
, sd_id128_t
*ret
) {
330 assert_return(ret
, -EINVAL
);
332 r
= sd_id128_get_machine(&id
);
336 return get_app_specific(id
, app_id
, ret
);
339 _public_
int sd_id128_get_boot_app_specific(sd_id128_t app_id
, sd_id128_t
*ret
) {
343 assert_return(ret
, -EINVAL
);
345 r
= sd_id128_get_boot(&id
);
349 return get_app_specific(id
, app_id
, ret
);