]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-id128/sd-id128.c
ef89fd2572fcdbc3b218d09fdc824b0b9c12cc23
[thirdparty/systemd.git] / src / libsystemd / sd-id128 / sd-id128.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25
26 #include "sd-id128.h"
27
28 #include "macro.h"
29 #include "random-util.h"
30 #include "util.h"
31 #include "fd-util.h"
32
33 _public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) {
34 unsigned n;
35
36 assert_return(s, NULL);
37
38 for (n = 0; n < 16; n++) {
39 s[n*2] = hexchar(id.bytes[n] >> 4);
40 s[n*2+1] = hexchar(id.bytes[n] & 0xF);
41 }
42
43 s[32] = 0;
44
45 return s;
46 }
47
48 _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
49 unsigned n, i;
50 sd_id128_t t;
51 bool is_guid = false;
52
53 assert_return(s, -EINVAL);
54 assert_return(ret, -EINVAL);
55
56 for (n = 0, i = 0; n < 16;) {
57 int a, b;
58
59 if (s[i] == '-') {
60 /* Is this a GUID? Then be nice, and skip over
61 * the dashes */
62
63 if (i == 8)
64 is_guid = true;
65 else if (i == 13 || i == 18 || i == 23) {
66 if (!is_guid)
67 return -EINVAL;
68 } else
69 return -EINVAL;
70
71 i++;
72 continue;
73 }
74
75 a = unhexchar(s[i++]);
76 if (a < 0)
77 return -EINVAL;
78
79 b = unhexchar(s[i++]);
80 if (b < 0)
81 return -EINVAL;
82
83 t.bytes[n++] = (a << 4) | b;
84 }
85
86 if (i != (is_guid ? 36 : 32))
87 return -EINVAL;
88
89 if (s[i] != 0)
90 return -EINVAL;
91
92 *ret = t;
93 return 0;
94 }
95
96 static sd_id128_t make_v4_uuid(sd_id128_t id) {
97 /* Stolen from generate_random_uuid() of drivers/char/random.c
98 * in the kernel sources */
99
100 /* Set UUID version to 4 --- truly random generation */
101 id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
102
103 /* Set the UUID variant to DCE */
104 id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
105
106 return id;
107 }
108
109 _public_ int sd_id128_get_machine(sd_id128_t *ret) {
110 static thread_local sd_id128_t saved_machine_id;
111 static thread_local bool saved_machine_id_valid = false;
112 _cleanup_close_ int fd = -1;
113 char buf[33];
114 unsigned j;
115 sd_id128_t t;
116 int r;
117
118 assert_return(ret, -EINVAL);
119
120 if (saved_machine_id_valid) {
121 *ret = saved_machine_id;
122 return 0;
123 }
124
125 fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
126 if (fd < 0)
127 return -errno;
128
129 r = loop_read_exact(fd, buf, 33, false);
130 if (r < 0)
131 return r;
132 if (buf[32] !='\n')
133 return -EIO;
134
135 for (j = 0; j < 16; j++) {
136 int a, b;
137
138 a = unhexchar(buf[j*2]);
139 b = unhexchar(buf[j*2+1]);
140
141 if (a < 0 || b < 0)
142 return -EIO;
143
144 t.bytes[j] = a << 4 | b;
145 }
146
147 saved_machine_id = t;
148 saved_machine_id_valid = true;
149
150 *ret = t;
151 return 0;
152 }
153
154 _public_ int sd_id128_get_boot(sd_id128_t *ret) {
155 static thread_local sd_id128_t saved_boot_id;
156 static thread_local bool saved_boot_id_valid = false;
157 _cleanup_close_ int fd = -1;
158 char buf[36];
159 unsigned j;
160 sd_id128_t t;
161 char *p;
162 int r;
163
164 assert_return(ret, -EINVAL);
165
166 if (saved_boot_id_valid) {
167 *ret = saved_boot_id;
168 return 0;
169 }
170
171 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
172 if (fd < 0)
173 return -errno;
174
175 r = loop_read_exact(fd, buf, 36, false);
176 if (r < 0)
177 return r;
178
179 for (j = 0, p = buf; j < 16; j++) {
180 int a, b;
181
182 if (p >= buf + 35)
183 return -EIO;
184
185 if (*p == '-') {
186 p++;
187 if (p >= buf + 35)
188 return -EIO;
189 }
190
191 a = unhexchar(p[0]);
192 b = unhexchar(p[1]);
193
194 if (a < 0 || b < 0)
195 return -EIO;
196
197 t.bytes[j] = a << 4 | b;
198
199 p += 2;
200 }
201
202 saved_boot_id = t;
203 saved_boot_id_valid = true;
204
205 *ret = t;
206 return 0;
207 }
208
209 _public_ int sd_id128_randomize(sd_id128_t *ret) {
210 sd_id128_t t;
211 int r;
212
213 assert_return(ret, -EINVAL);
214
215 r = dev_urandom(&t, sizeof(t));
216 if (r < 0)
217 return r;
218
219 /* Turn this into a valid v4 UUID, to be nice. Note that we
220 * only guarantee this for newly generated UUIDs, not for
221 * pre-existing ones. */
222
223 *ret = make_v4_uuid(t);
224 return 0;
225 }