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/>.
27 #include "hexdecoct.h"
28 #include "id128-util.h"
32 #include "random-util.h"
35 _public_
char *sd_id128_to_string(sd_id128_t id
, char s
[SD_ID128_STRING_MAX
]) {
38 assert_return(s
, NULL
);
40 for (n
= 0; n
< 16; n
++) {
41 s
[n
*2] = hexchar(id
.bytes
[n
] >> 4);
42 s
[n
*2+1] = hexchar(id
.bytes
[n
] & 0xF);
50 _public_
int sd_id128_from_string(const char s
[], sd_id128_t
*ret
) {
55 assert_return(s
, -EINVAL
);
57 for (n
= 0, i
= 0; n
< 16;) {
61 /* Is this a GUID? Then be nice, and skip over
66 else if (i
== 13 || i
== 18 || i
== 23) {
76 a
= unhexchar(s
[i
++]);
80 b
= unhexchar(s
[i
++]);
84 t
.bytes
[n
++] = (a
<< 4) | b
;
87 if (i
!= (is_guid
? 36 : 32))
98 _public_
int sd_id128_get_machine(sd_id128_t
*ret
) {
99 static thread_local sd_id128_t saved_machine_id
= {};
102 assert_return(ret
, -EINVAL
);
104 if (sd_id128_is_null(saved_machine_id
)) {
105 r
= id128_read("/etc/machine-id", ID128_PLAIN
, &saved_machine_id
);
109 if (sd_id128_is_null(saved_machine_id
))
113 *ret
= saved_machine_id
;
117 _public_
int sd_id128_get_boot(sd_id128_t
*ret
) {
118 static thread_local sd_id128_t saved_boot_id
= {};
121 assert_return(ret
, -EINVAL
);
123 if (sd_id128_is_null(saved_boot_id
)) {
124 r
= id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID
, &saved_boot_id
);
129 *ret
= saved_boot_id
;
133 _public_
int sd_id128_get_invocation(sd_id128_t
*ret
) {
134 static thread_local sd_id128_t saved_invocation_id
= {};
137 assert_return(ret
, -EINVAL
);
139 if (sd_id128_is_null(saved_invocation_id
)) {
142 e
= secure_getenv("INVOCATION_ID");
146 r
= sd_id128_from_string(e
, &saved_invocation_id
);
151 *ret
= saved_invocation_id
;
155 static sd_id128_t
make_v4_uuid(sd_id128_t id
) {
156 /* Stolen from generate_random_uuid() of drivers/char/random.c
157 * in the kernel sources */
159 /* Set UUID version to 4 --- truly random generation */
160 id
.bytes
[6] = (id
.bytes
[6] & 0x0F) | 0x40;
162 /* Set the UUID variant to DCE */
163 id
.bytes
[8] = (id
.bytes
[8] & 0x3F) | 0x80;
168 _public_
int sd_id128_randomize(sd_id128_t
*ret
) {
172 assert_return(ret
, -EINVAL
);
174 r
= dev_urandom(&t
, sizeof(t
));
178 /* Turn this into a valid v4 UUID, to be nice. Note that we
179 * only guarantee this for newly generated UUIDs, not for
180 * pre-existing ones. */
182 *ret
= make_v4_uuid(t
);
186 _public_
int sd_id128_get_machine_app_specific(sd_id128_t app_id
, sd_id128_t
*ret
) {
187 _cleanup_(khash_unrefp
) khash
*h
= NULL
;
188 sd_id128_t m
, result
;
192 assert_return(ret
, -EINVAL
);
194 r
= sd_id128_get_machine(&m
);
198 r
= khash_new_with_key(&h
, "hmac(sha256)", &m
, sizeof(m
));
202 r
= khash_put(h
, &app_id
, sizeof(app_id
));
206 r
= khash_digest_data(h
, &p
);
210 /* We chop off the trailing 16 bytes */
211 memcpy(&result
, p
, MIN(khash_get_size(h
), sizeof(result
)));
213 *ret
= make_v4_uuid(result
);