]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-id128/sd-id128.c
Merge pull request #2495 from heftig/master
[thirdparty/systemd.git] / src / libsystemd / sd-id128 / sd-id128.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2011 Lennart Poettering
5
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.
10
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.
15
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/>.
18 ***/
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23
24 #include "sd-id128.h"
25
26 #include "fd-util.h"
27 #include "hexdecoct.h"
28 #include "io-util.h"
29 #include "macro.h"
30 #include "random-util.h"
31 #include "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 }