]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machine-dbus.c
tree-wide: use UINT64_MAX or friends
[thirdparty/systemd.git] / src / machine / machine-dbus.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <sys/mount.h>
5 #include <sys/wait.h>
6
7 /* When we include libgen.h because we need dirname() we immediately
8 * undefine basename() since libgen.h defines it as a macro to the POSIX
9 * version which is really broken. We prefer GNU basename(). */
10 #include <libgen.h>
11 #undef basename
12
13 #include "alloc-util.h"
14 #include "bus-common-errors.h"
15 #include "bus-get-properties.h"
16 #include "bus-internal.h"
17 #include "bus-label.h"
18 #include "bus-locator.h"
19 #include "bus-polkit.h"
20 #include "copy.h"
21 #include "env-file.h"
22 #include "env-util.h"
23 #include "fd-util.h"
24 #include "fileio.h"
25 #include "format-util.h"
26 #include "fs-util.h"
27 #include "in-addr-util.h"
28 #include "io-util.h"
29 #include "local-addresses.h"
30 #include "machine-dbus.h"
31 #include "machine.h"
32 #include "missing_capability.h"
33 #include "mkdir.h"
34 #include "mount-util.h"
35 #include "mountpoint-util.h"
36 #include "namespace-util.h"
37 #include "os-util.h"
38 #include "path-util.h"
39 #include "process-util.h"
40 #include "signal-util.h"
41 #include "strv.h"
42 #include "terminal-util.h"
43 #include "tmpfile-util.h"
44 #include "user-util.h"
45
46 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
47 static BUS_DEFINE_PROPERTY_GET2(property_get_state, "s", Machine, machine_get_state, machine_state_to_string);
48
49 static int property_get_netif(
50 sd_bus *bus,
51 const char *path,
52 const char *interface,
53 const char *property,
54 sd_bus_message *reply,
55 void *userdata,
56 sd_bus_error *error) {
57
58 Machine *m = userdata;
59
60 assert(bus);
61 assert(reply);
62 assert(m);
63
64 assert_cc(sizeof(int) == sizeof(int32_t));
65
66 return sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
67 }
68
69 int bus_machine_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error) {
70 Machine *m = userdata;
71 int r;
72
73 assert(message);
74 assert(m);
75
76 r = bus_verify_polkit_async(
77 message,
78 CAP_KILL,
79 "org.freedesktop.machine1.manage-machines",
80 NULL,
81 false,
82 UID_INVALID,
83 &m->manager->polkit_registry,
84 error);
85 if (r < 0)
86 return r;
87 if (r == 0)
88 return 1; /* Will call us back */
89
90 r = machine_finalize(m);
91 if (r < 0)
92 return r;
93
94 return sd_bus_reply_method_return(message, NULL);
95 }
96
97 int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
98 Machine *m = userdata;
99 int r;
100
101 assert(message);
102 assert(m);
103
104 r = bus_verify_polkit_async(
105 message,
106 CAP_KILL,
107 "org.freedesktop.machine1.manage-machines",
108 NULL,
109 false,
110 UID_INVALID,
111 &m->manager->polkit_registry,
112 error);
113 if (r < 0)
114 return r;
115 if (r == 0)
116 return 1; /* Will call us back */
117
118 r = machine_stop(m);
119 if (r < 0)
120 return r;
121
122 return sd_bus_reply_method_return(message, NULL);
123 }
124
125 int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
126 Machine *m = userdata;
127 const char *swho;
128 int32_t signo;
129 KillWho who;
130 int r;
131
132 assert(message);
133 assert(m);
134
135 r = sd_bus_message_read(message, "si", &swho, &signo);
136 if (r < 0)
137 return r;
138
139 if (isempty(swho))
140 who = KILL_ALL;
141 else {
142 who = kill_who_from_string(swho);
143 if (who < 0)
144 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
145 }
146
147 if (!SIGNAL_VALID(signo))
148 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
149
150 r = bus_verify_polkit_async(
151 message,
152 CAP_KILL,
153 "org.freedesktop.machine1.manage-machines",
154 NULL,
155 false,
156 UID_INVALID,
157 &m->manager->polkit_registry,
158 error);
159 if (r < 0)
160 return r;
161 if (r == 0)
162 return 1; /* Will call us back */
163
164 r = machine_kill(m, who, signo);
165 if (r < 0)
166 return r;
167
168 return sd_bus_reply_method_return(message, NULL);
169 }
170
171 int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
172 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
173 Machine *m = userdata;
174 int r;
175
176 assert(message);
177 assert(m);
178
179 r = sd_bus_message_new_method_return(message, &reply);
180 if (r < 0)
181 return r;
182
183 r = sd_bus_message_open_container(reply, 'a', "(iay)");
184 if (r < 0)
185 return r;
186
187 switch (m->class) {
188
189 case MACHINE_HOST: {
190 _cleanup_free_ struct local_address *addresses = NULL;
191 struct local_address *a;
192 int n, i;
193
194 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
195 if (n < 0)
196 return n;
197
198 for (a = addresses, i = 0; i < n; a++, i++) {
199
200 r = sd_bus_message_open_container(reply, 'r', "iay");
201 if (r < 0)
202 return r;
203
204 r = sd_bus_message_append(reply, "i", addresses[i].family);
205 if (r < 0)
206 return r;
207
208 r = sd_bus_message_append_array(reply, 'y', &addresses[i].address, FAMILY_ADDRESS_SIZE(addresses[i].family));
209 if (r < 0)
210 return r;
211
212 r = sd_bus_message_close_container(reply);
213 if (r < 0)
214 return r;
215 }
216
217 break;
218 }
219
220 case MACHINE_CONTAINER: {
221 _cleanup_close_pair_ int pair[2] = { -1, -1 };
222 _cleanup_free_ char *us = NULL, *them = NULL;
223 _cleanup_close_ int netns_fd = -1;
224 const char *p;
225 pid_t child;
226
227 r = readlink_malloc("/proc/self/ns/net", &us);
228 if (r < 0)
229 return r;
230
231 p = procfs_file_alloca(m->leader, "ns/net");
232 r = readlink_malloc(p, &them);
233 if (r < 0)
234 return r;
235
236 if (streq(us, them))
237 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
238
239 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL, NULL);
240 if (r < 0)
241 return r;
242
243 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
244 return -errno;
245
246 r = namespace_fork("(sd-addrns)", "(sd-addr)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG,
247 -1, -1, netns_fd, -1, -1, &child);
248 if (r < 0)
249 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
250 if (r == 0) {
251 _cleanup_free_ struct local_address *addresses = NULL;
252 struct local_address *a;
253 int i, n;
254
255 pair[0] = safe_close(pair[0]);
256
257 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
258 if (n < 0)
259 _exit(EXIT_FAILURE);
260
261 for (a = addresses, i = 0; i < n; a++, i++) {
262 struct iovec iov[2] = {
263 { .iov_base = &a->family, .iov_len = sizeof(a->family) },
264 { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
265 };
266
267 r = writev(pair[1], iov, 2);
268 if (r < 0)
269 _exit(EXIT_FAILURE);
270 }
271
272 pair[1] = safe_close(pair[1]);
273
274 _exit(EXIT_SUCCESS);
275 }
276
277 pair[1] = safe_close(pair[1]);
278
279 for (;;) {
280 int family;
281 ssize_t n;
282 union in_addr_union in_addr;
283 struct iovec iov[2];
284 struct msghdr mh = {
285 .msg_iov = iov,
286 .msg_iovlen = 2,
287 };
288
289 iov[0] = IOVEC_MAKE(&family, sizeof(family));
290 iov[1] = IOVEC_MAKE(&in_addr, sizeof(in_addr));
291
292 n = recvmsg(pair[0], &mh, 0);
293 if (n < 0)
294 return -errno;
295 if ((size_t) n < sizeof(family))
296 break;
297
298 r = sd_bus_message_open_container(reply, 'r', "iay");
299 if (r < 0)
300 return r;
301
302 r = sd_bus_message_append(reply, "i", family);
303 if (r < 0)
304 return r;
305
306 switch (family) {
307
308 case AF_INET:
309 if (n != sizeof(struct in_addr) + sizeof(family))
310 return -EIO;
311
312 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
313 break;
314
315 case AF_INET6:
316 if (n != sizeof(struct in6_addr) + sizeof(family))
317 return -EIO;
318
319 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
320 break;
321 }
322 if (r < 0)
323 return r;
324
325 r = sd_bus_message_close_container(reply);
326 if (r < 0)
327 return r;
328 }
329
330 r = wait_for_terminate_and_check("(sd-addrns)", child, 0);
331 if (r < 0)
332 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
333 if (r != EXIT_SUCCESS)
334 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
335 break;
336 }
337
338 default:
339 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
340 }
341
342 r = sd_bus_message_close_container(reply);
343 if (r < 0)
344 return r;
345
346 return sd_bus_send(NULL, reply, NULL);
347 }
348
349 #define EXIT_NOT_FOUND 2
350
351 int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
352 _cleanup_strv_free_ char **l = NULL;
353 Machine *m = userdata;
354 int r;
355
356 assert(message);
357 assert(m);
358
359 switch (m->class) {
360
361 case MACHINE_HOST:
362 r = load_os_release_pairs(NULL, &l);
363 if (r < 0)
364 return r;
365
366 break;
367
368 case MACHINE_CONTAINER: {
369 _cleanup_close_ int mntns_fd = -1, root_fd = -1, pidns_fd = -1;
370 _cleanup_close_pair_ int pair[2] = { -1, -1 };
371 _cleanup_fclose_ FILE *f = NULL;
372 pid_t child;
373
374 r = namespace_open(m->leader, &pidns_fd, &mntns_fd, NULL, NULL, &root_fd);
375 if (r < 0)
376 return r;
377
378 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
379 return -errno;
380
381 r = namespace_fork("(sd-osrelns)", "(sd-osrel)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG,
382 pidns_fd, mntns_fd, -1, -1, root_fd,
383 &child);
384 if (r < 0)
385 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
386 if (r == 0) {
387 int fd = -1;
388
389 pair[0] = safe_close(pair[0]);
390
391 r = open_os_release(NULL, NULL, &fd);
392 if (r == -ENOENT)
393 _exit(EXIT_NOT_FOUND);
394 if (r < 0)
395 _exit(EXIT_FAILURE);
396
397 r = copy_bytes(fd, pair[1], UINT64_MAX, 0);
398 if (r < 0)
399 _exit(EXIT_FAILURE);
400
401 _exit(EXIT_SUCCESS);
402 }
403
404 pair[1] = safe_close(pair[1]);
405
406 f = take_fdopen(&pair[0], "r");
407 if (!f)
408 return -errno;
409
410 r = load_env_file_pairs(f, "/etc/os-release", &l);
411 if (r < 0)
412 return r;
413
414 r = wait_for_terminate_and_check("(sd-osrelns)", child, 0);
415 if (r < 0)
416 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
417 if (r == EXIT_NOT_FOUND)
418 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Machine does not contain OS release information");
419 if (r != EXIT_SUCCESS)
420 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
421
422 break;
423 }
424
425 default:
426 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
427 }
428
429 return bus_reply_pair_array(message, l);
430 }
431
432 int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
433 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
434 _cleanup_free_ char *pty_name = NULL;
435 _cleanup_close_ int master = -1;
436 Machine *m = userdata;
437 int r;
438
439 assert(message);
440 assert(m);
441
442 r = bus_verify_polkit_async(
443 message,
444 CAP_SYS_ADMIN,
445 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty",
446 NULL,
447 false,
448 UID_INVALID,
449 &m->manager->polkit_registry,
450 error);
451 if (r < 0)
452 return r;
453 if (r == 0)
454 return 1; /* Will call us back */
455
456 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
457 if (master < 0)
458 return master;
459
460 r = sd_bus_message_new_method_return(message, &reply);
461 if (r < 0)
462 return r;
463
464 r = sd_bus_message_append(reply, "hs", master, pty_name);
465 if (r < 0)
466 return r;
467
468 return sd_bus_send(NULL, reply, NULL);
469 }
470
471 static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) {
472 int r;
473
474 assert(m);
475 assert(ret);
476
477 switch (m->class) {
478
479 case MACHINE_HOST:
480 *ret = NULL;
481 break;
482
483 case MACHINE_CONTAINER: {
484 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
485 char *address;
486
487 r = sd_bus_new(&bus);
488 if (r < 0)
489 return r;
490
491 if (asprintf(&address, "x-machine-unix:pid=%" PID_PRI, m->leader) < 0)
492 return -ENOMEM;
493
494 bus->address = address;
495 bus->bus_client = true;
496 bus->trusted = false;
497 bus->is_system = true;
498
499 r = sd_bus_start(bus);
500 if (r == -ENOENT)
501 return sd_bus_error_set_errnof(error, r, "There is no system bus in container %s.", m->name);
502 if (r < 0)
503 return r;
504
505 *ret = TAKE_PTR(bus);
506 break;
507 }
508
509 default:
510 return -EOPNOTSUPP;
511 }
512
513 return 0;
514 }
515
516 int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
517 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
518 _cleanup_free_ char *pty_name = NULL;
519 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
520 _cleanup_close_ int master = -1;
521 sd_bus *container_bus = NULL;
522 Machine *m = userdata;
523 const char *p, *getty;
524 int r;
525
526 assert(message);
527 assert(m);
528
529 r = bus_verify_polkit_async(
530 message,
531 CAP_SYS_ADMIN,
532 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
533 NULL,
534 false,
535 UID_INVALID,
536 &m->manager->polkit_registry,
537 error);
538 if (r < 0)
539 return r;
540 if (r == 0)
541 return 1; /* Will call us back */
542
543 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
544 if (master < 0)
545 return master;
546
547 p = path_startswith(pty_name, "/dev/pts/");
548 assert(p);
549
550 r = container_bus_new(m, error, &allocated_bus);
551 if (r < 0)
552 return r;
553
554 container_bus = allocated_bus ?: m->manager->bus;
555
556 getty = strjoina("container-getty@", p, ".service");
557
558 r = bus_call_method(container_bus, bus_systemd_mgr, "StartUnit", error, NULL, "ss", getty, "replace");
559 if (r < 0)
560 return r;
561
562 r = sd_bus_message_new_method_return(message, &reply);
563 if (r < 0)
564 return r;
565
566 r = sd_bus_message_append(reply, "hs", master, pty_name);
567 if (r < 0)
568 return r;
569
570 return sd_bus_send(NULL, reply, NULL);
571 }
572
573 int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
574 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *tm = NULL;
575 _cleanup_free_ char *pty_name = NULL;
576 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
577 sd_bus *container_bus = NULL;
578 _cleanup_close_ int master = -1, slave = -1;
579 _cleanup_strv_free_ char **env = NULL, **args_wire = NULL, **args = NULL;
580 Machine *m = userdata;
581 const char *p, *unit, *user, *path, *description, *utmp_id;
582 int r;
583
584 assert(message);
585 assert(m);
586
587 r = sd_bus_message_read(message, "ss", &user, &path);
588 if (r < 0)
589 return r;
590 user = isempty(user) ? "root" : user;
591 r = sd_bus_message_read_strv(message, &args_wire);
592 if (r < 0)
593 return r;
594 if (isempty(path)) {
595 path = "/bin/sh";
596
597 args = new0(char*, 3 + 1);
598 if (!args)
599 return -ENOMEM;
600 args[0] = strdup("sh");
601 if (!args[0])
602 return -ENOMEM;
603 args[1] = strdup("-c");
604 if (!args[1])
605 return -ENOMEM;
606 r = asprintf(&args[2],
607 "shell=$(getent passwd %s 2>/dev/null | { IFS=: read _ _ _ _ _ _ x; echo \"$x\"; })\n"\
608 "exec \"${shell:-/bin/sh}\" -l", /* -l is means --login */
609 user);
610 if (r < 0) {
611 args[2] = NULL;
612 return -ENOMEM;
613 }
614 } else {
615 if (!path_is_absolute(path))
616 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified path '%s' is not absolute", path);
617 args = TAKE_PTR(args_wire);
618 if (strv_isempty(args)) {
619 args = strv_free(args);
620
621 args = strv_new(path);
622 if (!args)
623 return -ENOMEM;
624 }
625 }
626
627 r = sd_bus_message_read_strv(message, &env);
628 if (r < 0)
629 return r;
630 if (!strv_env_is_valid(env))
631 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
632
633 const char *details[] = {
634 "machine", m->name,
635 "user", user,
636 "program", path,
637 NULL
638 };
639
640 r = bus_verify_polkit_async(
641 message,
642 CAP_SYS_ADMIN,
643 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
644 details,
645 false,
646 UID_INVALID,
647 &m->manager->polkit_registry,
648 error);
649 if (r < 0)
650 return r;
651 if (r == 0)
652 return 1; /* Will call us back */
653
654 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
655 if (master < 0)
656 return master;
657
658 p = path_startswith(pty_name, "/dev/pts/");
659 assert(p);
660
661 slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
662 if (slave < 0)
663 return slave;
664
665 utmp_id = path_startswith(pty_name, "/dev/");
666 assert(utmp_id);
667
668 r = container_bus_new(m, error, &allocated_bus);
669 if (r < 0)
670 return r;
671
672 container_bus = allocated_bus ?: m->manager->bus;
673
674 r = bus_message_new_method_call(container_bus, &tm, bus_systemd_mgr, "StartTransientUnit");
675 if (r < 0)
676 return r;
677
678 /* Name and mode */
679 unit = strjoina("container-shell@", p, ".service");
680 r = sd_bus_message_append(tm, "ss", unit, "fail");
681 if (r < 0)
682 return r;
683
684 /* Properties */
685 r = sd_bus_message_open_container(tm, 'a', "(sv)");
686 if (r < 0)
687 return r;
688
689 description = strjoina("Shell for User ", user);
690 r = sd_bus_message_append(tm,
691 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
692 "Description", "s", description,
693 "StandardInputFileDescriptor", "h", slave,
694 "StandardOutputFileDescriptor", "h", slave,
695 "StandardErrorFileDescriptor", "h", slave,
696 "SendSIGHUP", "b", true,
697 "IgnoreSIGPIPE", "b", false,
698 "KillMode", "s", "mixed",
699 "TTYReset", "b", true,
700 "UtmpIdentifier", "s", utmp_id,
701 "UtmpMode", "s", "user",
702 "PAMName", "s", "login",
703 "WorkingDirectory", "s", "-~");
704 if (r < 0)
705 return r;
706
707 r = sd_bus_message_append(tm, "(sv)", "User", "s", user);
708 if (r < 0)
709 return r;
710
711 if (!strv_isempty(env)) {
712 r = sd_bus_message_open_container(tm, 'r', "sv");
713 if (r < 0)
714 return r;
715
716 r = sd_bus_message_append(tm, "s", "Environment");
717 if (r < 0)
718 return r;
719
720 r = sd_bus_message_open_container(tm, 'v', "as");
721 if (r < 0)
722 return r;
723
724 r = sd_bus_message_append_strv(tm, env);
725 if (r < 0)
726 return r;
727
728 r = sd_bus_message_close_container(tm);
729 if (r < 0)
730 return r;
731
732 r = sd_bus_message_close_container(tm);
733 if (r < 0)
734 return r;
735 }
736
737 /* Exec container */
738 r = sd_bus_message_open_container(tm, 'r', "sv");
739 if (r < 0)
740 return r;
741
742 r = sd_bus_message_append(tm, "s", "ExecStart");
743 if (r < 0)
744 return r;
745
746 r = sd_bus_message_open_container(tm, 'v', "a(sasb)");
747 if (r < 0)
748 return r;
749
750 r = sd_bus_message_open_container(tm, 'a', "(sasb)");
751 if (r < 0)
752 return r;
753
754 r = sd_bus_message_open_container(tm, 'r', "sasb");
755 if (r < 0)
756 return r;
757
758 r = sd_bus_message_append(tm, "s", path);
759 if (r < 0)
760 return r;
761
762 r = sd_bus_message_append_strv(tm, args);
763 if (r < 0)
764 return r;
765
766 r = sd_bus_message_append(tm, "b", true);
767 if (r < 0)
768 return r;
769
770 r = sd_bus_message_close_container(tm);
771 if (r < 0)
772 return r;
773
774 r = sd_bus_message_close_container(tm);
775 if (r < 0)
776 return r;
777
778 r = sd_bus_message_close_container(tm);
779 if (r < 0)
780 return r;
781
782 r = sd_bus_message_close_container(tm);
783 if (r < 0)
784 return r;
785
786 r = sd_bus_message_close_container(tm);
787 if (r < 0)
788 return r;
789
790 /* Auxiliary units */
791 r = sd_bus_message_append(tm, "a(sa(sv))", 0);
792 if (r < 0)
793 return r;
794
795 r = sd_bus_call(container_bus, tm, 0, error, NULL);
796 if (r < 0)
797 return r;
798
799 slave = safe_close(slave);
800
801 r = sd_bus_message_new_method_return(message, &reply);
802 if (r < 0)
803 return r;
804
805 r = sd_bus_message_append(reply, "hs", master, pty_name);
806 if (r < 0)
807 return r;
808
809 return sd_bus_send(NULL, reply, NULL);
810 }
811
812 int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
813 int read_only, make_file_or_directory;
814 const char *dest, *src, *propagate_directory;
815 Machine *m = userdata;
816 uid_t uid;
817 int r;
818
819 assert(message);
820 assert(m);
821
822 if (m->class != MACHINE_CONTAINER)
823 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
824
825 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory);
826 if (r < 0)
827 return r;
828
829 if (!path_is_absolute(src) || !path_is_normalized(src))
830 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized.");
831
832 if (isempty(dest))
833 dest = src;
834 else if (!path_is_absolute(dest) || !path_is_normalized(dest))
835 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized.");
836
837 r = bus_verify_polkit_async(
838 message,
839 CAP_SYS_ADMIN,
840 "org.freedesktop.machine1.manage-machines",
841 NULL,
842 false,
843 UID_INVALID,
844 &m->manager->polkit_registry,
845 error);
846 if (r < 0)
847 return r;
848 if (r == 0)
849 return 1; /* Will call us back */
850
851 r = machine_get_uid_shift(m, &uid);
852 if (r < 0)
853 return r;
854 if (uid != 0)
855 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied.");
856
857 propagate_directory = strjoina("/run/systemd/nspawn/propagate/", m->name);
858 r = bind_mount_in_namespace(m->leader,
859 propagate_directory,
860 "/run/host/incoming/",
861 src, dest, read_only, make_file_or_directory);
862 if (r < 0)
863 return sd_bus_error_set_errnof(error, r, "Failed to mount %s on %s in machine's namespace: %m", src, dest);
864
865 return sd_bus_reply_method_return(message, NULL);
866 }
867
868 int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
869 const char *src, *dest, *host_path, *container_path, *host_basename, *container_basename, *container_dirname;
870 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
871 CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS;
872 _cleanup_close_ int hostfd = -1;
873 Machine *m = userdata;
874 bool copy_from;
875 pid_t child;
876 uid_t uid_shift;
877 char *t;
878 int r;
879
880 assert(message);
881 assert(m);
882
883 if (m->manager->n_operations >= OPERATIONS_MAX)
884 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
885
886 if (m->class != MACHINE_CONTAINER)
887 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
888
889 r = sd_bus_message_read(message, "ss", &src, &dest);
890 if (r < 0)
891 return r;
892
893 if (!path_is_absolute(src))
894 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
895
896 if (isempty(dest))
897 dest = src;
898 else if (!path_is_absolute(dest))
899 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
900
901 r = bus_verify_polkit_async(
902 message,
903 CAP_SYS_ADMIN,
904 "org.freedesktop.machine1.manage-machines",
905 NULL,
906 false,
907 UID_INVALID,
908 &m->manager->polkit_registry,
909 error);
910 if (r < 0)
911 return r;
912 if (r == 0)
913 return 1; /* Will call us back */
914
915 r = machine_get_uid_shift(m, &uid_shift);
916 if (r < 0)
917 return r;
918
919 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
920
921 if (copy_from) {
922 container_path = src;
923 host_path = dest;
924 } else {
925 host_path = src;
926 container_path = dest;
927 }
928
929 host_basename = basename(host_path);
930
931 container_basename = basename(container_path);
932 t = strdupa(container_path);
933 container_dirname = dirname(t);
934
935 hostfd = open_parent(host_path, O_CLOEXEC, 0);
936 if (hostfd < 0)
937 return sd_bus_error_set_errnof(error, hostfd, "Failed to open host directory %s: %m", host_path);
938
939 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
940 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
941
942 r = safe_fork("(sd-copy)", FORK_RESET_SIGNALS, &child);
943 if (r < 0)
944 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
945 if (r == 0) {
946 int containerfd;
947 const char *q;
948 int mntfd;
949
950 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
951
952 q = procfs_file_alloca(m->leader, "ns/mnt");
953 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
954 if (mntfd < 0) {
955 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
956 goto child_fail;
957 }
958
959 if (setns(mntfd, CLONE_NEWNS) < 0) {
960 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
961 goto child_fail;
962 }
963
964 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
965 if (containerfd < 0) {
966 r = log_error_errno(errno, "Failed to open destination directory: %m");
967 goto child_fail;
968 }
969
970 /* Run the actual copy operation. Note that when an UID shift is set we'll either clamp the UID/GID to
971 * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
972 * the UID/GIDs as they are. */
973 if (copy_from)
974 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags);
975 else
976 r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags);
977
978 hostfd = safe_close(hostfd);
979 containerfd = safe_close(containerfd);
980
981 if (r < 0) {
982 r = log_error_errno(r, "Failed to copy tree: %m");
983 goto child_fail;
984 }
985
986 _exit(EXIT_SUCCESS);
987
988 child_fail:
989 (void) write(errno_pipe_fd[1], &r, sizeof(r));
990 _exit(EXIT_FAILURE);
991 }
992
993 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
994
995 /* Copying might take a while, hence install a watch on the child, and return */
996
997 r = operation_new(m->manager, m, child, message, errno_pipe_fd[0], NULL);
998 if (r < 0) {
999 (void) sigkill_wait(child);
1000 return r;
1001 }
1002 errno_pipe_fd[0] = -1;
1003
1004 return 1;
1005 }
1006
1007 int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1008 _cleanup_close_ int fd = -1;
1009 Machine *m = userdata;
1010 int r;
1011
1012 assert(message);
1013 assert(m);
1014
1015 r = bus_verify_polkit_async(
1016 message,
1017 CAP_SYS_ADMIN,
1018 "org.freedesktop.machine1.manage-machines",
1019 NULL,
1020 false,
1021 UID_INVALID,
1022 &m->manager->polkit_registry,
1023 error);
1024 if (r < 0)
1025 return r;
1026 if (r == 0)
1027 return 1; /* Will call us back */
1028
1029 switch (m->class) {
1030
1031 case MACHINE_HOST:
1032 fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1033 if (fd < 0)
1034 return -errno;
1035
1036 break;
1037
1038 case MACHINE_CONTAINER: {
1039 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
1040 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1041 pid_t child;
1042
1043 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
1044 if (r < 0)
1045 return r;
1046
1047 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1048 return -errno;
1049
1050 r = namespace_fork("(sd-openrootns)", "(sd-openroot)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG,
1051 -1, mntns_fd, -1, -1, root_fd, &child);
1052 if (r < 0)
1053 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
1054 if (r == 0) {
1055 _cleanup_close_ int dfd = -1;
1056
1057 pair[0] = safe_close(pair[0]);
1058
1059 dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1060 if (dfd < 0)
1061 _exit(EXIT_FAILURE);
1062
1063 r = send_one_fd(pair[1], dfd, 0);
1064 dfd = safe_close(dfd);
1065 if (r < 0)
1066 _exit(EXIT_FAILURE);
1067
1068 _exit(EXIT_SUCCESS);
1069 }
1070
1071 pair[1] = safe_close(pair[1]);
1072
1073 r = wait_for_terminate_and_check("(sd-openrootns)", child, 0);
1074 if (r < 0)
1075 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
1076 if (r != EXIT_SUCCESS)
1077 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
1078
1079 fd = receive_one_fd(pair[0], MSG_DONTWAIT);
1080 if (fd < 0)
1081 return fd;
1082
1083 break;
1084 }
1085
1086 default:
1087 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
1088 }
1089
1090 return sd_bus_reply_method_return(message, "h", fd);
1091 }
1092
1093 int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1094 Machine *m = userdata;
1095 uid_t shift = 0;
1096 int r;
1097
1098 assert(message);
1099 assert(m);
1100
1101 /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but
1102 * we kinda have to for this. */
1103
1104 if (m->class == MACHINE_HOST)
1105 return sd_bus_reply_method_return(message, "u", UINT32_C(0));
1106
1107 if (m->class != MACHINE_CONTAINER)
1108 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines.");
1109
1110 r = machine_get_uid_shift(m, &shift);
1111 if (r == -ENXIO)
1112 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m->name);
1113 if (r < 0)
1114 return r;
1115
1116 return sd_bus_reply_method_return(message, "u", (uint32_t) shift);
1117 }
1118
1119 static int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
1120 Manager *m = userdata;
1121 Machine *machine;
1122 int r;
1123
1124 assert(bus);
1125 assert(path);
1126 assert(interface);
1127 assert(found);
1128 assert(m);
1129
1130 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
1131 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
1132 sd_bus_message *message;
1133 pid_t pid;
1134
1135 message = sd_bus_get_current_message(bus);
1136 if (!message)
1137 return 0;
1138
1139 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
1140 if (r < 0)
1141 return r;
1142
1143 r = sd_bus_creds_get_pid(creds, &pid);
1144 if (r < 0)
1145 return r;
1146
1147 r = manager_get_machine_by_pid(m, pid, &machine);
1148 if (r <= 0)
1149 return 0;
1150 } else {
1151 _cleanup_free_ char *e = NULL;
1152 const char *p;
1153
1154 p = startswith(path, "/org/freedesktop/machine1/machine/");
1155 if (!p)
1156 return 0;
1157
1158 e = bus_label_unescape(p);
1159 if (!e)
1160 return -ENOMEM;
1161
1162 machine = hashmap_get(m->machines, e);
1163 if (!machine)
1164 return 0;
1165 }
1166
1167 *found = machine;
1168 return 1;
1169 }
1170
1171 char *machine_bus_path(Machine *m) {
1172 _cleanup_free_ char *e = NULL;
1173
1174 assert(m);
1175
1176 e = bus_label_escape(m->name);
1177 if (!e)
1178 return NULL;
1179
1180 return strjoin("/org/freedesktop/machine1/machine/", e);
1181 }
1182
1183 static int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
1184 _cleanup_strv_free_ char **l = NULL;
1185 Machine *machine = NULL;
1186 Manager *m = userdata;
1187 int r;
1188
1189 assert(bus);
1190 assert(path);
1191 assert(nodes);
1192
1193 HASHMAP_FOREACH(machine, m->machines) {
1194 char *p;
1195
1196 p = machine_bus_path(machine);
1197 if (!p)
1198 return -ENOMEM;
1199
1200 r = strv_consume(&l, p);
1201 if (r < 0)
1202 return r;
1203 }
1204
1205 *nodes = TAKE_PTR(l);
1206
1207 return 1;
1208 }
1209
1210 static const sd_bus_vtable machine_vtable[] = {
1211 SD_BUS_VTABLE_START(0),
1212 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
1213 SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST),
1214 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1215 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
1216 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
1217 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1218 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
1219 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
1220 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
1221 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1222 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
1223
1224 SD_BUS_METHOD("Terminate",
1225 NULL,
1226 NULL,
1227 bus_machine_method_terminate,
1228 SD_BUS_VTABLE_UNPRIVILEGED),
1229 SD_BUS_METHOD_WITH_NAMES("Kill",
1230 "si",
1231 SD_BUS_PARAM(who)
1232 SD_BUS_PARAM(signal),
1233 NULL,,
1234 bus_machine_method_kill,
1235 SD_BUS_VTABLE_UNPRIVILEGED),
1236 SD_BUS_METHOD_WITH_NAMES("GetAddresses",
1237 NULL,,
1238 "a(iay)",
1239 SD_BUS_PARAM(addresses),
1240 bus_machine_method_get_addresses,
1241 SD_BUS_VTABLE_UNPRIVILEGED),
1242 SD_BUS_METHOD_WITH_NAMES("GetOSRelease",
1243 NULL,,
1244 "a{ss}",
1245 SD_BUS_PARAM(fields),
1246 bus_machine_method_get_os_release,
1247 SD_BUS_VTABLE_UNPRIVILEGED),
1248 SD_BUS_METHOD_WITH_NAMES("GetUIDShift",
1249 NULL,,
1250 "u",
1251 SD_BUS_PARAM(shift),
1252 bus_machine_method_get_uid_shift,
1253 SD_BUS_VTABLE_UNPRIVILEGED),
1254 SD_BUS_METHOD_WITH_NAMES("OpenPTY",
1255 NULL,,
1256 "hs",
1257 SD_BUS_PARAM(pty)
1258 SD_BUS_PARAM(pty_path),
1259 bus_machine_method_open_pty,
1260 SD_BUS_VTABLE_UNPRIVILEGED),
1261 SD_BUS_METHOD_WITH_NAMES("OpenLogin",
1262 NULL,,
1263 "hs",
1264 SD_BUS_PARAM(pty)
1265 SD_BUS_PARAM(pty_path),
1266 bus_machine_method_open_login,
1267 SD_BUS_VTABLE_UNPRIVILEGED),
1268 SD_BUS_METHOD_WITH_NAMES("OpenShell",
1269 "ssasas",
1270 SD_BUS_PARAM(user)
1271 SD_BUS_PARAM(path)
1272 SD_BUS_PARAM(args)
1273 SD_BUS_PARAM(environment),
1274 "hs",
1275 SD_BUS_PARAM(pty)
1276 SD_BUS_PARAM(pty_path),
1277 bus_machine_method_open_shell,
1278 SD_BUS_VTABLE_UNPRIVILEGED),
1279 SD_BUS_METHOD_WITH_NAMES("BindMount",
1280 "ssbb",
1281 SD_BUS_PARAM(source)
1282 SD_BUS_PARAM(destination)
1283 SD_BUS_PARAM(read_only)
1284 SD_BUS_PARAM(mkdir),
1285 NULL,,
1286 bus_machine_method_bind_mount,
1287 SD_BUS_VTABLE_UNPRIVILEGED),
1288 SD_BUS_METHOD_WITH_NAMES("CopyFrom",
1289 "ss",
1290 SD_BUS_PARAM(source)
1291 SD_BUS_PARAM(destination),
1292 NULL,,
1293 bus_machine_method_copy,
1294 SD_BUS_VTABLE_UNPRIVILEGED),
1295 SD_BUS_METHOD_WITH_NAMES("CopyTo",
1296 "ss",
1297 SD_BUS_PARAM(source)
1298 SD_BUS_PARAM(destination),
1299 NULL,,
1300 bus_machine_method_copy,
1301 SD_BUS_VTABLE_UNPRIVILEGED),
1302 SD_BUS_METHOD_WITH_NAMES("OpenRootDirectory",
1303 NULL,,
1304 "h",
1305 SD_BUS_PARAM(fd),
1306 bus_machine_method_open_root_directory,
1307 SD_BUS_VTABLE_UNPRIVILEGED),
1308
1309 SD_BUS_VTABLE_END
1310 };
1311
1312 const BusObjectImplementation machine_object = {
1313 "/org/freedesktop/machine1/machine",
1314 "org.freedesktop.machine1.Machine",
1315 .fallback_vtables = BUS_FALLBACK_VTABLES({machine_vtable, machine_object_find}),
1316 .node_enumerator = machine_node_enumerator,
1317 };
1318
1319 int machine_send_signal(Machine *m, bool new_machine) {
1320 _cleanup_free_ char *p = NULL;
1321
1322 assert(m);
1323
1324 p = machine_bus_path(m);
1325 if (!p)
1326 return -ENOMEM;
1327
1328 return sd_bus_emit_signal(
1329 m->manager->bus,
1330 "/org/freedesktop/machine1",
1331 "org.freedesktop.machine1.Manager",
1332 new_machine ? "MachineNew" : "MachineRemoved",
1333 "so", m->name, p);
1334 }
1335
1336 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
1337 _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
1338 _cleanup_free_ char *p = NULL;
1339
1340 assert(m);
1341
1342 if (!m->create_message)
1343 return 0;
1344
1345 c = TAKE_PTR(m->create_message);
1346
1347 if (error)
1348 return sd_bus_reply_method_error(c, error);
1349
1350 /* Update the machine state file before we notify the client
1351 * about the result. */
1352 machine_save(m);
1353
1354 p = machine_bus_path(m);
1355 if (!p)
1356 return -ENOMEM;
1357
1358 return sd_bus_reply_method_return(c, "o", p);
1359 }