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