]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine-id-setup.c
9e84ac0cb990757d6981d1adef8c8d9507bdea12
[thirdparty/systemd.git] / src / machine-id-setup.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 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 <unistd.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <fcntl.h>
28 #include <sys/mount.h>
29
30 #include <systemd/sd-id128.h>
31
32 #include "machine-id-setup.h"
33 #include "macro.h"
34 #include "util.h"
35 #include "mkdir.h"
36 #include "log.h"
37 #include "virt.h"
38
39 static int shorten_uuid(char destination[36], const char *source) {
40 unsigned i, j;
41
42 for (i = 0, j = 0; i < 36 && j < 32; i++) {
43 int t;
44
45 t = unhexchar(source[i]);
46 if (t < 0)
47 continue;
48
49 destination[j++] = hexchar(t);
50 }
51
52 if (i == 36 && j == 32) {
53 destination[32] = '\n';
54 destination[33] = 0;
55 return 0;
56 }
57
58 return -EINVAL;
59 }
60
61 static int generate(char id[34]) {
62 int fd, r;
63 unsigned char *p;
64 sd_id128_t buf;
65 char *q;
66 ssize_t k;
67 const char *vm_id;
68
69 assert(id);
70
71 /* First, try reading the D-Bus machine id, unless it is a symlink */
72 fd = open("/var/lib/dbus/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
73 if (fd >= 0) {
74
75 k = loop_read(fd, id, 32, false);
76 close_nointr_nofail(fd);
77
78 if (k >= 32) {
79 id[32] = '\n';
80 id[33] = 0;
81
82 log_info("Initializing machine ID from D-Bus machine ID.");
83 return 0;
84 }
85 }
86
87 /* If that didn't work, see if we are running in qemu/kvm and a
88 * machine ID was passed in via -uuid on the qemu/kvm command
89 * line */
90
91 r = detect_vm(&vm_id);
92 if (r > 0 && streq(vm_id, "kvm")) {
93 char uuid[37];
94
95 fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
96 if (fd >= 0) {
97 k = loop_read(fd, uuid, 36, false);
98 close_nointr_nofail(fd);
99
100 if (k >= 36) {
101 r = shorten_uuid(id, uuid);
102 if (r >= 0) {
103 log_info("Initializing machine ID from KVM UUID");
104 return 0;
105 }
106 }
107 }
108 }
109
110 /* If that didn't work either, see if we are running in a
111 * container, and a machine ID was passed in via
112 * $container_uuid the way libvirt/LXC does it */
113
114 r = detect_container(NULL);
115 if (r > 0) {
116 FILE *f;
117
118 f = fopen("/proc/1/environ", "re");
119 if (f) {
120 bool done = false;
121
122 do {
123 char line[LINE_MAX];
124 unsigned i;
125
126 for (i = 0; i < sizeof(line)-1; i++) {
127 int c;
128
129 c = getc(f);
130 if (_unlikely_(c == EOF)) {
131 done = true;
132 break;
133 } else if (c == 0)
134 break;
135
136 line[i] = c;
137 }
138 line[i] = 0;
139
140 if (startswith(line, "container_uuid=") &&
141 strlen(line + 15) >= 36) {
142 r = shorten_uuid(id, line + 15);
143 if (r >= 0) {
144 log_info("Initializing machine ID from container UUID");
145 return 0;
146 }
147 }
148
149 } while (!done);
150
151 fclose(f);
152 }
153 }
154
155 /* If that didn't work, generate a random machine id */
156 r = sd_id128_randomize(&buf);
157 if (r < 0) {
158 log_error("Failed to open /dev/urandom: %s", strerror(-r));
159 return r;
160 }
161
162 for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) {
163 q[0] = hexchar(*p >> 4);
164 q[1] = hexchar(*p & 15);
165 }
166
167 id[32] = '\n';
168 id[33] = 0;
169
170 log_info("Initializing machine ID from random generator.");
171
172 return 0;
173 }
174
175 int machine_id_setup(void) {
176 int fd, r;
177 bool writable;
178 struct stat st;
179 char id[34]; /* 32 + \n + \0 */
180 mode_t m;
181
182 m = umask(0000);
183
184 /* We create this 0444, to indicate that this isn't really
185 * something you should ever modify. Of course, since the file
186 * will be owned by root it doesn't matter much, but maybe
187 * people look. */
188
189 fd = open("/etc/machine-id", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
190 if (fd >= 0)
191 writable = true;
192 else {
193 fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
194 if (fd < 0) {
195 umask(m);
196 log_error("Cannot open /etc/machine-id: %m");
197 return -errno;
198 }
199
200 writable = false;
201 }
202
203 umask(m);
204
205 if (fstat(fd, &st) < 0) {
206 log_error("fstat() failed: %m");
207 r = -errno;
208 goto finish;
209 }
210
211 if (S_ISREG(st.st_mode)) {
212 if (loop_read(fd, id, 32, false) >= 32) {
213 r = 0;
214 goto finish;
215 }
216 }
217
218 /* Hmm, so, the id currently stored is not useful, then let's
219 * generate one */
220
221 r = generate(id);
222 if (r < 0)
223 goto finish;
224
225 if (S_ISREG(st.st_mode) && writable) {
226 lseek(fd, 0, SEEK_SET);
227
228 if (loop_write(fd, id, 33, false) == 33) {
229 r = 0;
230 goto finish;
231 }
232 }
233
234 close_nointr_nofail(fd);
235 fd = -1;
236
237 /* Hmm, we couldn't write it? So let's write it to
238 * /run/machine-id as a replacement */
239
240 m = umask(0022);
241 r = write_one_line_file("/run/machine-id", id);
242 umask(m);
243
244 if (r < 0) {
245 log_error("Cannot write /run/machine-id: %s", strerror(-r));
246
247 unlink("/run/machine-id");
248 goto finish;
249 }
250
251 /* And now, let's mount it over */
252 r = mount("/run/machine-id", "/etc/machine-id", "bind", MS_BIND|MS_RDONLY, NULL) < 0 ? -errno : 0;
253 if (r < 0) {
254 unlink("/run/machine-id");
255 log_error("Failed to mount /etc/machine-id: %s", strerror(-r));
256 } else
257 log_info("Installed transient /etc/machine-id file.");
258
259 finish:
260
261 if (fd >= 0)
262 close_nointr_nofail(fd);
263
264 return r;
265 }