2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "alloc-util.h"
28 #include "hexdecoct.h"
29 #include "id128-util.h"
34 #include "random-util.h"
35 #include "user-util.h"
38 _public_
char *sd_id128_to_string(sd_id128_t id
, char s
[SD_ID128_STRING_MAX
]) {
41 assert_return(s
, NULL
);
43 for (n
= 0; n
< 16; n
++) {
44 s
[n
*2] = hexchar(id
.bytes
[n
] >> 4);
45 s
[n
*2+1] = hexchar(id
.bytes
[n
] & 0xF);
53 _public_
int sd_id128_from_string(const char s
[], sd_id128_t
*ret
) {
58 assert_return(s
, -EINVAL
);
60 for (n
= 0, i
= 0; n
< 16;) {
64 /* Is this a GUID? Then be nice, and skip over
69 else if (IN_SET(i
, 13, 18, 23)) {
79 a
= unhexchar(s
[i
++]);
83 b
= unhexchar(s
[i
++]);
87 t
.bytes
[n
++] = (a
<< 4) | b
;
90 if (i
!= (is_guid
? 36 : 32))
101 _public_
int sd_id128_get_machine(sd_id128_t
*ret
) {
102 static thread_local sd_id128_t saved_machine_id
= {};
105 assert_return(ret
, -EINVAL
);
107 if (sd_id128_is_null(saved_machine_id
)) {
108 r
= id128_read("/etc/machine-id", ID128_PLAIN
, &saved_machine_id
);
112 if (sd_id128_is_null(saved_machine_id
))
116 *ret
= saved_machine_id
;
120 _public_
int sd_id128_get_boot(sd_id128_t
*ret
) {
121 static thread_local sd_id128_t saved_boot_id
= {};
124 assert_return(ret
, -EINVAL
);
126 if (sd_id128_is_null(saved_boot_id
)) {
127 r
= id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID
, &saved_boot_id
);
132 *ret
= saved_boot_id
;
136 static int get_invocation_from_keyring(sd_id128_t
*ret
) {
138 _cleanup_free_
char *description
= NULL
;
139 char *d
, *p
, *g
, *u
, *e
;
147 #define MAX_PERMS ((unsigned long) (KEY_POS_VIEW|KEY_POS_READ|KEY_POS_SEARCH| \
148 KEY_USR_VIEW|KEY_USR_READ|KEY_USR_SEARCH))
152 key
= request_key("user", "invocation_id", NULL
, 0);
154 /* Keyring support not available? No invocation key stored? */
155 if (IN_SET(errno
, ENOSYS
, ENOKEY
))
162 description
= new(char, sz
);
166 c
= keyctl(KEYCTL_DESCRIBE
, key
, (unsigned long) description
, sz
, 0);
170 if ((size_t) c
<= sz
)
177 /* The kernel returns a final NUL in the string, verify that. */
178 assert(description
[c
-1] == 0);
180 /* Chop off the final description string */
181 d
= strrchr(description
, ';');
186 /* Look for the permissions */
187 p
= strrchr(description
, ';');
192 perms
= strtoul(p
+ 1, &e
, 16);
195 if (e
== p
+ 1) /* Read at least one character */
197 if (e
!= d
) /* Must reached the end */
200 if ((perms
& ~MAX_PERMS
) != 0)
205 /* Look for the group ID */
206 g
= strrchr(description
, ';');
209 r
= parse_gid(g
+ 1, &gid
);
216 /* Look for the user ID */
217 u
= strrchr(description
, ';');
220 r
= parse_uid(u
+ 1, &uid
);
226 c
= keyctl(KEYCTL_READ
, key
, (unsigned long) ret
, sizeof(sd_id128_t
), 0);
229 if (c
!= sizeof(sd_id128_t
))
235 _public_
int sd_id128_get_invocation(sd_id128_t
*ret
) {
236 static thread_local sd_id128_t saved_invocation_id
= {};
239 assert_return(ret
, -EINVAL
);
241 if (sd_id128_is_null(saved_invocation_id
)) {
243 /* We first try to read the invocation ID from the kernel keyring. This has the benefit that it is not
244 * fakeable by unprivileged code. If the information is not available in the keyring, we use
245 * $INVOCATION_ID but ignore the data if our process was called by less privileged code
246 * (i.e. secure_getenv() instead of getenv()).
248 * The kernel keyring is only relevant for system services (as for user services we don't store the
249 * invocation ID in the keyring, as there'd be no trust benefit in that). The environment variable is
250 * primarily relevant for user services, and sufficiently safe as no privilege boundary is involved. */
252 r
= get_invocation_from_keyring(&saved_invocation_id
);
259 e
= secure_getenv("INVOCATION_ID");
263 r
= sd_id128_from_string(e
, &saved_invocation_id
);
269 *ret
= saved_invocation_id
;
273 static sd_id128_t
make_v4_uuid(sd_id128_t id
) {
274 /* Stolen from generate_random_uuid() of drivers/char/random.c
275 * in the kernel sources */
277 /* Set UUID version to 4 --- truly random generation */
278 id
.bytes
[6] = (id
.bytes
[6] & 0x0F) | 0x40;
280 /* Set the UUID variant to DCE */
281 id
.bytes
[8] = (id
.bytes
[8] & 0x3F) | 0x80;
286 _public_
int sd_id128_randomize(sd_id128_t
*ret
) {
290 assert_return(ret
, -EINVAL
);
292 r
= acquire_random_bytes(&t
, sizeof t
, true);
296 /* Turn this into a valid v4 UUID, to be nice. Note that we
297 * only guarantee this for newly generated UUIDs, not for
298 * pre-existing ones. */
300 *ret
= make_v4_uuid(t
);
304 _public_
int sd_id128_get_machine_app_specific(sd_id128_t app_id
, sd_id128_t
*ret
) {
305 _cleanup_(khash_unrefp
) khash
*h
= NULL
;
306 sd_id128_t m
, result
;
310 assert_return(ret
, -EINVAL
);
312 r
= sd_id128_get_machine(&m
);
316 r
= khash_new_with_key(&h
, "hmac(sha256)", &m
, sizeof(m
));
320 r
= khash_put(h
, &app_id
, sizeof(app_id
));
324 r
= khash_digest_data(h
, &p
);
328 /* We chop off the trailing 16 bytes */
329 memcpy(&result
, p
, MIN(khash_get_size(h
), sizeof(result
)));
331 *ret
= make_v4_uuid(result
);