]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machine.c
user-util: add UID_NOBODY defines that resolve to (uid_t) 65534
[thirdparty/systemd.git] / src / machine / machine.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #include "sd-messages.h"
26
27 #include "alloc-util.h"
28 #include "bus-error.h"
29 #include "bus-util.h"
30 #include "escape.h"
31 #include "extract-word.h"
32 #include "fd-util.h"
33 #include "fileio.h"
34 #include "format-util.h"
35 #include "hashmap.h"
36 #include "machine-dbus.h"
37 #include "machine.h"
38 #include "mkdir.h"
39 #include "parse-util.h"
40 #include "process-util.h"
41 #include "special.h"
42 #include "stdio-util.h"
43 #include "string-table.h"
44 #include "terminal-util.h"
45 #include "unit-name.h"
46 #include "user-util.h"
47 #include "util.h"
48
49 Machine* machine_new(Manager *manager, MachineClass class, const char *name) {
50 Machine *m;
51
52 assert(manager);
53 assert(class < _MACHINE_CLASS_MAX);
54 assert(name);
55
56 /* Passing class == _MACHINE_CLASS_INVALID here is fine. It
57 * means as much as "we don't know yet", and that we'll figure
58 * it out later when loading the state file. */
59
60 m = new0(Machine, 1);
61 if (!m)
62 return NULL;
63
64 m->name = strdup(name);
65 if (!m->name)
66 goto fail;
67
68 if (class != MACHINE_HOST) {
69 m->state_file = strappend("/run/systemd/machines/", m->name);
70 if (!m->state_file)
71 goto fail;
72 }
73
74 m->class = class;
75
76 if (hashmap_put(manager->machines, m->name, m) < 0)
77 goto fail;
78
79 m->manager = manager;
80
81 return m;
82
83 fail:
84 free(m->state_file);
85 free(m->name);
86 return mfree(m);
87 }
88
89 void machine_free(Machine *m) {
90 assert(m);
91
92 while (m->operations)
93 operation_free(m->operations);
94
95 if (m->in_gc_queue)
96 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
97
98 machine_release_unit(m);
99
100 free(m->scope_job);
101
102 (void) hashmap_remove(m->manager->machines, m->name);
103
104 if (m->manager->host_machine == m)
105 m->manager->host_machine = NULL;
106
107 if (m->leader > 0)
108 (void) hashmap_remove_value(m->manager->machine_leaders, PID_TO_PTR(m->leader), m);
109
110 sd_bus_message_unref(m->create_message);
111
112 free(m->name);
113 free(m->state_file);
114 free(m->service);
115 free(m->root_directory);
116 free(m->netif);
117 free(m);
118 }
119
120 int machine_save(Machine *m) {
121 _cleanup_free_ char *temp_path = NULL;
122 _cleanup_fclose_ FILE *f = NULL;
123 int r;
124
125 assert(m);
126
127 if (!m->state_file)
128 return 0;
129
130 if (!m->started)
131 return 0;
132
133 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0, false);
134 if (r < 0)
135 goto fail;
136
137 r = fopen_temporary(m->state_file, &f, &temp_path);
138 if (r < 0)
139 goto fail;
140
141 (void) fchmod(fileno(f), 0644);
142
143 fprintf(f,
144 "# This is private data. Do not parse.\n"
145 "NAME=%s\n",
146 m->name);
147
148 if (m->unit) {
149 _cleanup_free_ char *escaped;
150
151 escaped = cescape(m->unit);
152 if (!escaped) {
153 r = -ENOMEM;
154 goto fail;
155 }
156
157 fprintf(f, "SCOPE=%s\n", escaped); /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */
158 }
159
160 if (m->scope_job)
161 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
162
163 if (m->service) {
164 _cleanup_free_ char *escaped;
165
166 escaped = cescape(m->service);
167 if (!escaped) {
168 r = -ENOMEM;
169 goto fail;
170 }
171 fprintf(f, "SERVICE=%s\n", escaped);
172 }
173
174 if (m->root_directory) {
175 _cleanup_free_ char *escaped;
176
177 escaped = cescape(m->root_directory);
178 if (!escaped) {
179 r = -ENOMEM;
180 goto fail;
181 }
182 fprintf(f, "ROOT=%s\n", escaped);
183 }
184
185 if (!sd_id128_is_null(m->id))
186 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
187
188 if (m->leader != 0)
189 fprintf(f, "LEADER="PID_FMT"\n", m->leader);
190
191 if (m->class != _MACHINE_CLASS_INVALID)
192 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
193
194 if (dual_timestamp_is_set(&m->timestamp))
195 fprintf(f,
196 "REALTIME="USEC_FMT"\n"
197 "MONOTONIC="USEC_FMT"\n",
198 m->timestamp.realtime,
199 m->timestamp.monotonic);
200
201 if (m->n_netif > 0) {
202 unsigned i;
203
204 fputs_unlocked("NETIF=", f);
205
206 for (i = 0; i < m->n_netif; i++) {
207 if (i != 0)
208 fputc_unlocked(' ', f);
209
210 fprintf(f, "%i", m->netif[i]);
211 }
212
213 fputc_unlocked('\n', f);
214 }
215
216 r = fflush_and_check(f);
217 if (r < 0)
218 goto fail;
219
220 if (rename(temp_path, m->state_file) < 0) {
221 r = -errno;
222 goto fail;
223 }
224
225 if (m->unit) {
226 char *sl;
227
228 /* Create a symlink from the unit name to the machine
229 * name, so that we can quickly find the machine for
230 * each given unit. Ignore error. */
231 sl = strjoina("/run/systemd/machines/unit:", m->unit);
232 (void) symlink(m->name, sl);
233 }
234
235 return 0;
236
237 fail:
238 (void) unlink(m->state_file);
239
240 if (temp_path)
241 (void) unlink(temp_path);
242
243 return log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
244 }
245
246 static void machine_unlink(Machine *m) {
247 assert(m);
248
249 if (m->unit) {
250
251 char *sl;
252
253 sl = strjoina("/run/systemd/machines/unit:", m->unit);
254 (void) unlink(sl);
255 }
256
257 if (m->state_file)
258 (void) unlink(m->state_file);
259 }
260
261 int machine_load(Machine *m) {
262 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL, *netif = NULL;
263 int r;
264
265 assert(m);
266
267 if (!m->state_file)
268 return 0;
269
270 r = parse_env_file(m->state_file, NEWLINE,
271 "SCOPE", &m->unit,
272 "SCOPE_JOB", &m->scope_job,
273 "SERVICE", &m->service,
274 "ROOT", &m->root_directory,
275 "ID", &id,
276 "LEADER", &leader,
277 "CLASS", &class,
278 "REALTIME", &realtime,
279 "MONOTONIC", &monotonic,
280 "NETIF", &netif,
281 NULL);
282 if (r < 0) {
283 if (r == -ENOENT)
284 return 0;
285
286 return log_error_errno(r, "Failed to read %s: %m", m->state_file);
287 }
288
289 if (id)
290 sd_id128_from_string(id, &m->id);
291
292 if (leader)
293 parse_pid(leader, &m->leader);
294
295 if (class) {
296 MachineClass c;
297
298 c = machine_class_from_string(class);
299 if (c >= 0)
300 m->class = c;
301 }
302
303 if (realtime)
304 timestamp_deserialize(realtime, &m->timestamp.realtime);
305 if (monotonic)
306 timestamp_deserialize(monotonic, &m->timestamp.monotonic);
307
308 if (netif) {
309 size_t allocated = 0, nr = 0;
310 const char *p;
311 int *ni = NULL;
312
313 p = netif;
314 for (;;) {
315 _cleanup_free_ char *word = NULL;
316 int ifi;
317
318 r = extract_first_word(&p, &word, NULL, 0);
319 if (r == 0)
320 break;
321 if (r == -ENOMEM)
322 return log_oom();
323 if (r < 0) {
324 log_warning_errno(r, "Failed to parse NETIF: %s", netif);
325 break;
326 }
327
328 if (parse_ifindex(word, &ifi) < 0)
329 continue;
330
331 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
332 free(ni);
333 return log_oom();
334 }
335
336 ni[nr++] = ifi;
337 }
338
339 free(m->netif);
340 m->netif = ni;
341 m->n_netif = nr;
342 }
343
344 return r;
345 }
346
347 static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
348 int r = 0;
349
350 assert(m);
351 assert(m->class != MACHINE_HOST);
352
353 if (!m->unit) {
354 _cleanup_free_ char *escaped = NULL;
355 char *scope, *description, *job = NULL;
356
357 escaped = unit_name_escape(m->name);
358 if (!escaped)
359 return log_oom();
360
361 scope = strjoin("machine-", escaped, ".scope");
362 if (!scope)
363 return log_oom();
364
365 description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
366
367 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
368 if (r < 0) {
369 log_error("Failed to start machine scope: %s", bus_error_message(error, r));
370 free(scope);
371 return r;
372 } else {
373 m->unit = scope;
374
375 free(m->scope_job);
376 m->scope_job = job;
377 }
378 }
379
380 if (m->unit)
381 hashmap_put(m->manager->machine_units, m->unit, m);
382
383 return r;
384 }
385
386 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
387 int r;
388
389 assert(m);
390
391 if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
392 return -EOPNOTSUPP;
393
394 if (m->started)
395 return 0;
396
397 r = hashmap_put(m->manager->machine_leaders, PID_TO_PTR(m->leader), m);
398 if (r < 0)
399 return r;
400
401 /* Create cgroup */
402 r = machine_start_scope(m, properties, error);
403 if (r < 0)
404 return r;
405
406 log_struct(LOG_INFO,
407 "MESSAGE_ID=" SD_MESSAGE_MACHINE_START_STR,
408 "NAME=%s", m->name,
409 "LEADER="PID_FMT, m->leader,
410 LOG_MESSAGE("New machine %s.", m->name),
411 NULL);
412
413 if (!dual_timestamp_is_set(&m->timestamp))
414 dual_timestamp_get(&m->timestamp);
415
416 m->started = true;
417
418 /* Save new machine data */
419 machine_save(m);
420
421 machine_send_signal(m, true);
422
423 return 0;
424 }
425
426 static int machine_stop_scope(Machine *m) {
427 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
428 char *job = NULL;
429 int r;
430
431 assert(m);
432 assert(m->class != MACHINE_HOST);
433
434 if (!m->unit)
435 return 0;
436
437 r = manager_stop_unit(m->manager, m->unit, &error, &job);
438 if (r < 0) {
439 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
440 return r;
441 }
442
443 free(m->scope_job);
444 m->scope_job = job;
445
446 return 0;
447 }
448
449 int machine_stop(Machine *m) {
450 int r;
451 assert(m);
452
453 if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
454 return -EOPNOTSUPP;
455
456 r = machine_stop_scope(m);
457
458 m->stopping = true;
459
460 machine_save(m);
461
462 return r;
463 }
464
465 int machine_finalize(Machine *m) {
466 assert(m);
467
468 if (m->started)
469 log_struct(LOG_INFO,
470 "MESSAGE_ID=" SD_MESSAGE_MACHINE_STOP_STR,
471 "NAME=%s", m->name,
472 "LEADER="PID_FMT, m->leader,
473 LOG_MESSAGE("Machine %s terminated.", m->name),
474 NULL);
475
476 machine_unlink(m);
477 machine_add_to_gc_queue(m);
478
479 if (m->started) {
480 machine_send_signal(m, false);
481 m->started = false;
482 }
483
484 return 0;
485 }
486
487 bool machine_check_gc(Machine *m, bool drop_not_started) {
488 assert(m);
489
490 if (m->class == MACHINE_HOST)
491 return true;
492
493 if (drop_not_started && !m->started)
494 return false;
495
496 if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
497 return true;
498
499 if (m->unit && manager_unit_is_active(m->manager, m->unit))
500 return true;
501
502 return false;
503 }
504
505 void machine_add_to_gc_queue(Machine *m) {
506 assert(m);
507
508 if (m->in_gc_queue)
509 return;
510
511 LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
512 m->in_gc_queue = true;
513 }
514
515 MachineState machine_get_state(Machine *s) {
516 assert(s);
517
518 if (s->class == MACHINE_HOST)
519 return MACHINE_RUNNING;
520
521 if (s->stopping)
522 return MACHINE_CLOSING;
523
524 if (s->scope_job)
525 return MACHINE_OPENING;
526
527 return MACHINE_RUNNING;
528 }
529
530 int machine_kill(Machine *m, KillWho who, int signo) {
531 assert(m);
532
533 if (!IN_SET(m->class, MACHINE_VM, MACHINE_CONTAINER))
534 return -EOPNOTSUPP;
535
536 if (!m->unit)
537 return -ESRCH;
538
539 if (who == KILL_LEADER) {
540 /* If we shall simply kill the leader, do so directly */
541
542 if (kill(m->leader, signo) < 0)
543 return -errno;
544
545 return 0;
546 }
547
548 /* Otherwise, make PID 1 do it for us, for the entire cgroup */
549 return manager_kill_unit(m->manager, m->unit, signo, NULL);
550 }
551
552 int machine_openpt(Machine *m, int flags) {
553 assert(m);
554
555 switch (m->class) {
556
557 case MACHINE_HOST: {
558 int fd;
559
560 fd = posix_openpt(flags);
561 if (fd < 0)
562 return -errno;
563
564 if (unlockpt(fd) < 0)
565 return -errno;
566
567 return fd;
568 }
569
570 case MACHINE_CONTAINER:
571 if (m->leader <= 0)
572 return -EINVAL;
573
574 return openpt_in_namespace(m->leader, flags);
575
576 default:
577 return -EOPNOTSUPP;
578 }
579 }
580
581 int machine_open_terminal(Machine *m, const char *path, int mode) {
582 assert(m);
583
584 switch (m->class) {
585
586 case MACHINE_HOST:
587 return open_terminal(path, mode);
588
589 case MACHINE_CONTAINER:
590 if (m->leader <= 0)
591 return -EINVAL;
592
593 return open_terminal_in_namespace(m->leader, path, mode);
594
595 default:
596 return -EOPNOTSUPP;
597 }
598 }
599
600 void machine_release_unit(Machine *m) {
601 assert(m);
602
603 if (!m->unit)
604 return;
605
606 (void) hashmap_remove(m->manager->machine_units, m->unit);
607 m->unit = mfree(m->unit);
608 }
609
610 int machine_get_uid_shift(Machine *m, uid_t *ret) {
611 char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
612 uid_t uid_base, uid_shift, uid_range;
613 gid_t gid_base, gid_shift, gid_range;
614 _cleanup_fclose_ FILE *f = NULL;
615 int k;
616
617 assert(m);
618 assert(ret);
619
620 /* Return the base UID/GID of the specified machine. Note that this only works for containers with simple
621 * mappings. In most cases setups should be simple like this, and administrators should only care about the
622 * basic offset a container has relative to the host. This is what this function exposes.
623 *
624 * If we encounter any more complex mappings we politely refuse this with ENXIO. */
625
626 if (m->class == MACHINE_HOST) {
627 *ret = 0;
628 return 0;
629 }
630
631 if (m->class != MACHINE_CONTAINER)
632 return -EOPNOTSUPP;
633
634 xsprintf(p, "/proc/" PID_FMT "/uid_map", m->leader);
635 f = fopen(p, "re");
636 if (!f) {
637 if (errno == ENOENT) {
638 /* If the file doesn't exist, user namespacing is off in the kernel, return a zero mapping hence. */
639 *ret = 0;
640 return 0;
641 }
642
643 return -errno;
644 }
645
646 /* Read the first line. There's at least one. */
647 errno = 0;
648 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range);
649 if (k != 3) {
650 if (ferror(f))
651 return -errno;
652
653 return -EBADMSG;
654 }
655
656 /* Not a mapping starting at 0? Then it's a complex mapping we can't expose here. */
657 if (uid_base != 0)
658 return -ENXIO;
659 /* Insist that at least the nobody user is mapped, everything else is weird, and hence complex, and we don't support it */
660 if (uid_range < UID_NOBODY)
661 return -ENXIO;
662
663 /* If there's more than one line, then we don't support this mapping. */
664 if (fgetc(f) != EOF)
665 return -ENXIO;
666
667 fclose(f);
668
669 xsprintf(p, "/proc/" PID_FMT "/gid_map", m->leader);
670 f = fopen(p, "re");
671 if (!f)
672 return -errno;
673
674 /* Read the first line. There's at least one. */
675 errno = 0;
676 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT "\n", &gid_base, &gid_shift, &gid_range);
677 if (k != 3) {
678 if (ferror(f))
679 return -errno;
680
681 return -EBADMSG;
682 }
683
684 /* If there's more than one line, then we don't support this file. */
685 if (fgetc(f) != EOF)
686 return -ENXIO;
687
688 /* If the UID and GID mapping doesn't match, we don't support this mapping. */
689 if (uid_base != (uid_t) gid_base)
690 return -ENXIO;
691 if (uid_shift != (uid_t) gid_shift)
692 return -ENXIO;
693 if (uid_range != (uid_t) gid_range)
694 return -ENXIO;
695
696 *ret = uid_shift;
697 return 0;
698 }
699
700 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
701 [MACHINE_CONTAINER] = "container",
702 [MACHINE_VM] = "vm",
703 [MACHINE_HOST] = "host",
704 };
705
706 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
707
708 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
709 [MACHINE_OPENING] = "opening",
710 [MACHINE_RUNNING] = "running",
711 [MACHINE_CLOSING] = "closing"
712 };
713
714 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
715
716 static const char* const kill_who_table[_KILL_WHO_MAX] = {
717 [KILL_LEADER] = "leader",
718 [KILL_ALL] = "all"
719 };
720
721 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);