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