]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-id128/sd-id128.c
Merge pull request #1695 from evverx/fix-cap-bounding-merging
[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 "fd-util.h"
29 #include "io-util.h"
30 #include "macro.h"
31 #include "hexdecoct.h"
32 #include "random-util.h"
33 #include "util.h"
34
35 _public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) {
36 unsigned n;
37
38 assert_return(s, NULL);
39
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);
43 }
44
45 s[32] = 0;
46
47 return s;
48 }
49
50 _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
51 unsigned n, i;
52 sd_id128_t t;
53 bool is_guid = false;
54
55 assert_return(s, -EINVAL);
56 assert_return(ret, -EINVAL);
57
58 for (n = 0, i = 0; n < 16;) {
59 int a, b;
60
61 if (s[i] == '-') {
62 /* Is this a GUID? Then be nice, and skip over
63 * the dashes */
64
65 if (i == 8)
66 is_guid = true;
67 else if (i == 13 || i == 18 || i == 23) {
68 if (!is_guid)
69 return -EINVAL;
70 } else
71 return -EINVAL;
72
73 i++;
74 continue;
75 }
76
77 a = unhexchar(s[i++]);
78 if (a < 0)
79 return -EINVAL;
80
81 b = unhexchar(s[i++]);
82 if (b < 0)
83 return -EINVAL;
84
85 t.bytes[n++] = (a << 4) | b;
86 }
87
88 if (i != (is_guid ? 36 : 32))
89 return -EINVAL;
90
91 if (s[i] != 0)
92 return -EINVAL;
93
94 *ret = t;
95 return 0;
96 }
97
98 static sd_id128_t make_v4_uuid(sd_id128_t id) {
99 /* Stolen from generate_random_uuid() of drivers/char/random.c
100 * in the kernel sources */
101
102 /* Set UUID version to 4 --- truly random generation */
103 id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
104
105 /* Set the UUID variant to DCE */
106 id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
107
108 return id;
109 }
110
111 _public_ int sd_id128_get_machine(sd_id128_t *ret) {
112 static thread_local sd_id128_t saved_machine_id;
113 static thread_local bool saved_machine_id_valid = false;
114 _cleanup_close_ int fd = -1;
115 char buf[33];
116 unsigned j;
117 sd_id128_t t;
118 int r;
119
120 assert_return(ret, -EINVAL);
121
122 if (saved_machine_id_valid) {
123 *ret = saved_machine_id;
124 return 0;
125 }
126
127 fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
128 if (fd < 0)
129 return -errno;
130
131 r = loop_read_exact(fd, buf, 33, false);
132 if (r < 0)
133 return r;
134 if (buf[32] !='\n')
135 return -EIO;
136
137 for (j = 0; j < 16; j++) {
138 int a, b;
139
140 a = unhexchar(buf[j*2]);
141 b = unhexchar(buf[j*2+1]);
142
143 if (a < 0 || b < 0)
144 return -EIO;
145
146 t.bytes[j] = a << 4 | b;
147 }
148
149 saved_machine_id = t;
150 saved_machine_id_valid = true;
151
152 *ret = t;
153 return 0;
154 }
155
156 _public_ int sd_id128_get_boot(sd_id128_t *ret) {
157 static thread_local sd_id128_t saved_boot_id;
158 static thread_local bool saved_boot_id_valid = false;
159 _cleanup_close_ int fd = -1;
160 char buf[36];
161 unsigned j;
162 sd_id128_t t;
163 char *p;
164 int r;
165
166 assert_return(ret, -EINVAL);
167
168 if (saved_boot_id_valid) {
169 *ret = saved_boot_id;
170 return 0;
171 }
172
173 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
174 if (fd < 0)
175 return -errno;
176
177 r = loop_read_exact(fd, buf, 36, false);
178 if (r < 0)
179 return r;
180
181 for (j = 0, p = buf; j < 16; j++) {
182 int a, b;
183
184 if (p >= buf + 35)
185 return -EIO;
186
187 if (*p == '-') {
188 p++;
189 if (p >= buf + 35)
190 return -EIO;
191 }
192
193 a = unhexchar(p[0]);
194 b = unhexchar(p[1]);
195
196 if (a < 0 || b < 0)
197 return -EIO;
198
199 t.bytes[j] = a << 4 | b;
200
201 p += 2;
202 }
203
204 saved_boot_id = t;
205 saved_boot_id_valid = true;
206
207 *ret = t;
208 return 0;
209 }
210
211 _public_ int sd_id128_randomize(sd_id128_t *ret) {
212 sd_id128_t t;
213 int r;
214
215 assert_return(ret, -EINVAL);
216
217 r = dev_urandom(&t, sizeof(t));
218 if (r < 0)
219 return r;
220
221 /* Turn this into a valid v4 UUID, to be nice. Note that we
222 * only guarantee this for newly generated UUIDs, not for
223 * pre-existing ones. */
224
225 *ret = make_v4_uuid(t);
226 return 0;
227 }