1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include "alloc-util.h"
29 #include "hexdecoct.h"
30 #include "id128-util.h"
35 #include "random-util.h"
36 #include "user-util.h"
39 _public_
char *sd_id128_to_string(sd_id128_t id
, char s
[SD_ID128_STRING_MAX
]) {
42 assert_return(s
, NULL
);
44 for (n
= 0; n
< 16; n
++) {
45 s
[n
*2] = hexchar(id
.bytes
[n
] >> 4);
46 s
[n
*2+1] = hexchar(id
.bytes
[n
] & 0xF);
54 _public_
int sd_id128_from_string(const char s
[], sd_id128_t
*ret
) {
59 assert_return(s
, -EINVAL
);
61 for (n
= 0, i
= 0; n
< 16;) {
65 /* Is this a GUID? Then be nice, and skip over
70 else if (IN_SET(i
, 13, 18, 23)) {
80 a
= unhexchar(s
[i
++]);
84 b
= unhexchar(s
[i
++]);
88 t
.bytes
[n
++] = (a
<< 4) | b
;
91 if (i
!= (is_guid
? 36 : 32))
102 _public_
int sd_id128_get_machine(sd_id128_t
*ret
) {
103 static thread_local sd_id128_t saved_machine_id
= {};
106 assert_return(ret
, -EINVAL
);
108 if (sd_id128_is_null(saved_machine_id
)) {
109 r
= id128_read("/etc/machine-id", ID128_PLAIN
, &saved_machine_id
);
113 if (sd_id128_is_null(saved_machine_id
))
117 *ret
= saved_machine_id
;
121 _public_
int sd_id128_get_boot(sd_id128_t
*ret
) {
122 static thread_local sd_id128_t saved_boot_id
= {};
125 assert_return(ret
, -EINVAL
);
127 if (sd_id128_is_null(saved_boot_id
)) {
128 r
= id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID
, &saved_boot_id
);
133 *ret
= saved_boot_id
;
137 static int get_invocation_from_keyring(sd_id128_t
*ret
) {
139 _cleanup_free_
char *description
= NULL
;
140 char *d
, *p
, *g
, *u
, *e
;
148 #define MAX_PERMS ((unsigned long) (KEY_POS_VIEW|KEY_POS_READ|KEY_POS_SEARCH| \
149 KEY_USR_VIEW|KEY_USR_READ|KEY_USR_SEARCH))
153 key
= request_key("user", "invocation_id", NULL
, 0);
155 /* Keyring support not available? No invocation key stored? */
156 if (IN_SET(errno
, ENOSYS
, ENOKEY
))
163 description
= new(char, sz
);
167 c
= keyctl(KEYCTL_DESCRIBE
, key
, (unsigned long) description
, sz
, 0);
171 if ((size_t) c
<= sz
)
178 /* The kernel returns a final NUL in the string, verify that. */
179 assert(description
[c
-1] == 0);
181 /* Chop off the final description string */
182 d
= strrchr(description
, ';');
187 /* Look for the permissions */
188 p
= strrchr(description
, ';');
193 perms
= strtoul(p
+ 1, &e
, 16);
196 if (e
== p
+ 1) /* Read at least one character */
198 if (e
!= d
) /* Must reached the end */
201 if ((perms
& ~MAX_PERMS
) != 0)
206 /* Look for the group ID */
207 g
= strrchr(description
, ';');
210 r
= parse_gid(g
+ 1, &gid
);
217 /* Look for the user ID */
218 u
= strrchr(description
, ';');
221 r
= parse_uid(u
+ 1, &uid
);
227 c
= keyctl(KEYCTL_READ
, key
, (unsigned long) ret
, sizeof(sd_id128_t
), 0);
230 if (c
!= sizeof(sd_id128_t
))
236 _public_
int sd_id128_get_invocation(sd_id128_t
*ret
) {
237 static thread_local sd_id128_t saved_invocation_id
= {};
240 assert_return(ret
, -EINVAL
);
242 if (sd_id128_is_null(saved_invocation_id
)) {
244 /* We first try to read the invocation ID from the kernel keyring. This has the benefit that it is not
245 * fakeable by unprivileged code. If the information is not available in the keyring, we use
246 * $INVOCATION_ID but ignore the data if our process was called by less privileged code
247 * (i.e. secure_getenv() instead of getenv()).
249 * The kernel keyring is only relevant for system services (as for user services we don't store the
250 * invocation ID in the keyring, as there'd be no trust benefit in that). The environment variable is
251 * primarily relevant for user services, and sufficiently safe as no privilege boundary is involved. */
253 r
= get_invocation_from_keyring(&saved_invocation_id
);
260 e
= secure_getenv("INVOCATION_ID");
264 r
= sd_id128_from_string(e
, &saved_invocation_id
);
270 *ret
= saved_invocation_id
;
274 static sd_id128_t
make_v4_uuid(sd_id128_t id
) {
275 /* Stolen from generate_random_uuid() of drivers/char/random.c
276 * in the kernel sources */
278 /* Set UUID version to 4 --- truly random generation */
279 id
.bytes
[6] = (id
.bytes
[6] & 0x0F) | 0x40;
281 /* Set the UUID variant to DCE */
282 id
.bytes
[8] = (id
.bytes
[8] & 0x3F) | 0x80;
287 _public_
int sd_id128_randomize(sd_id128_t
*ret
) {
291 assert_return(ret
, -EINVAL
);
293 r
= acquire_random_bytes(&t
, sizeof t
, true);
297 /* Turn this into a valid v4 UUID, to be nice. Note that we
298 * only guarantee this for newly generated UUIDs, not for
299 * pre-existing ones. */
301 *ret
= make_v4_uuid(t
);
305 _public_
int sd_id128_get_machine_app_specific(sd_id128_t app_id
, sd_id128_t
*ret
) {
306 _cleanup_(khash_unrefp
) khash
*h
= NULL
;
307 sd_id128_t m
, result
;
311 assert_return(ret
, -EINVAL
);
313 r
= sd_id128_get_machine(&m
);
317 r
= khash_new_with_key(&h
, "hmac(sha256)", &m
, sizeof(m
));
321 r
= khash_put(h
, &app_id
, sizeof(app_id
));
325 r
= khash_digest_data(h
, &p
);
329 /* We chop off the trailing 16 bytes */
330 memcpy(&result
, p
, MIN(khash_get_size(h
), sizeof(result
)));
332 *ret
= make_v4_uuid(result
);