]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machine-dbus.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[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 = TAKE_PTR(bus);
526 break;
527 }
528
529 default:
530 return -EOPNOTSUPP;
531 }
532
533 return 0;
534 }
535
536 int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
537 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
538 _cleanup_free_ char *pty_name = NULL;
539 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
540 _cleanup_close_ int master = -1;
541 sd_bus *container_bus = NULL;
542 Machine *m = userdata;
543 const char *p, *getty;
544 int r;
545
546 assert(message);
547 assert(m);
548
549 r = bus_verify_polkit_async(
550 message,
551 CAP_SYS_ADMIN,
552 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
553 NULL,
554 false,
555 UID_INVALID,
556 &m->manager->polkit_registry,
557 error);
558 if (r < 0)
559 return r;
560 if (r == 0)
561 return 1; /* Will call us back */
562
563 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
564 if (master < 0)
565 return master;
566
567 r = ptsname_namespace(master, &pty_name);
568 if (r < 0)
569 return r;
570
571 p = path_startswith(pty_name, "/dev/pts/");
572 if (!p)
573 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
574
575 r = container_bus_new(m, error, &allocated_bus);
576 if (r < 0)
577 return r;
578
579 container_bus = allocated_bus ?: m->manager->bus;
580
581 getty = strjoina("container-getty@", p, ".service");
582
583 r = sd_bus_call_method(
584 container_bus,
585 "org.freedesktop.systemd1",
586 "/org/freedesktop/systemd1",
587 "org.freedesktop.systemd1.Manager",
588 "StartUnit",
589 error, NULL,
590 "ss", getty, "replace");
591 if (r < 0)
592 return r;
593
594 r = sd_bus_message_new_method_return(message, &reply);
595 if (r < 0)
596 return r;
597
598 r = sd_bus_message_append(reply, "hs", master, pty_name);
599 if (r < 0)
600 return r;
601
602 return sd_bus_send(NULL, reply, NULL);
603 }
604
605 int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
606 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *tm = NULL;
607 _cleanup_free_ char *pty_name = NULL;
608 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
609 sd_bus *container_bus = NULL;
610 _cleanup_close_ int master = -1, slave = -1;
611 _cleanup_strv_free_ char **env = NULL, **args_wire = NULL, **args = NULL;
612 Machine *m = userdata;
613 const char *p, *unit, *user, *path, *description, *utmp_id;
614 int r;
615
616 assert(message);
617 assert(m);
618
619 r = sd_bus_message_read(message, "ss", &user, &path);
620 if (r < 0)
621 return r;
622 user = empty_to_null(user);
623 r = sd_bus_message_read_strv(message, &args_wire);
624 if (r < 0)
625 return r;
626 if (isempty(path)) {
627 path = "/bin/sh";
628
629 args = new0(char*, 3 + 1);
630 if (!args)
631 return -ENOMEM;
632 args[0] = strdup("sh");
633 if (!args[0])
634 return -ENOMEM;
635 args[1] = strdup("-c");
636 if (!args[1])
637 return -ENOMEM;
638 r = asprintf(&args[2],
639 "shell=$(getent passwd %s 2>/dev/null | { IFS=: read _ _ _ _ _ _ x; echo \"$x\"; })\n"\
640 "exec \"${shell:-/bin/sh}\" -l", /* -l is means --login */
641 isempty(user) ? "root" : user);
642 if (r < 0) {
643 args[2] = NULL;
644 return -ENOMEM;
645 }
646 } else {
647 if (!path_is_absolute(path))
648 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified path '%s' is not absolute", path);
649 args = TAKE_PTR(args_wire);
650 if (strv_isempty(args)) {
651 args = strv_free(args);
652
653 args = strv_new(path, NULL);
654 if (!args)
655 return -ENOMEM;
656 }
657 }
658
659 r = sd_bus_message_read_strv(message, &env);
660 if (r < 0)
661 return r;
662 if (!strv_env_is_valid(env))
663 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
664
665 r = bus_verify_polkit_async(
666 message,
667 CAP_SYS_ADMIN,
668 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
669 NULL,
670 false,
671 UID_INVALID,
672 &m->manager->polkit_registry,
673 error);
674 if (r < 0)
675 return r;
676 if (r == 0)
677 return 1; /* Will call us back */
678
679 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
680 if (master < 0)
681 return master;
682
683 r = ptsname_namespace(master, &pty_name);
684 if (r < 0)
685 return r;
686
687 p = path_startswith(pty_name, "/dev/pts/");
688 assert(p);
689
690 slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
691 if (slave < 0)
692 return slave;
693
694 utmp_id = path_startswith(pty_name, "/dev/");
695 assert(utmp_id);
696
697 r = container_bus_new(m, error, &allocated_bus);
698 if (r < 0)
699 return r;
700
701 container_bus = allocated_bus ?: m->manager->bus;
702
703 r = sd_bus_message_new_method_call(
704 container_bus,
705 &tm,
706 "org.freedesktop.systemd1",
707 "/org/freedesktop/systemd1",
708 "org.freedesktop.systemd1.Manager",
709 "StartTransientUnit");
710 if (r < 0)
711 return r;
712
713 /* Name and mode */
714 unit = strjoina("container-shell@", p, ".service");
715 r = sd_bus_message_append(tm, "ss", unit, "fail");
716 if (r < 0)
717 return r;
718
719 /* Properties */
720 r = sd_bus_message_open_container(tm, 'a', "(sv)");
721 if (r < 0)
722 return r;
723
724 description = strjoina("Shell for User ", isempty(user) ? "root" : user);
725 r = sd_bus_message_append(tm,
726 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
727 "Description", "s", description,
728 "StandardInputFileDescriptor", "h", slave,
729 "StandardOutputFileDescriptor", "h", slave,
730 "StandardErrorFileDescriptor", "h", slave,
731 "SendSIGHUP", "b", true,
732 "IgnoreSIGPIPE", "b", false,
733 "KillMode", "s", "mixed",
734 "TTYReset", "b", true,
735 "UtmpIdentifier", "s", utmp_id,
736 "UtmpMode", "s", "user",
737 "PAMName", "s", "login",
738 "WorkingDirectory", "s", "-~");
739 if (r < 0)
740 return r;
741
742 r = sd_bus_message_append(tm, "(sv)", "User", "s", isempty(user) ? "root" : user);
743 if (r < 0)
744 return r;
745
746 if (!strv_isempty(env)) {
747 r = sd_bus_message_open_container(tm, 'r', "sv");
748 if (r < 0)
749 return r;
750
751 r = sd_bus_message_append(tm, "s", "Environment");
752 if (r < 0)
753 return r;
754
755 r = sd_bus_message_open_container(tm, 'v', "as");
756 if (r < 0)
757 return r;
758
759 r = sd_bus_message_append_strv(tm, env);
760 if (r < 0)
761 return r;
762
763 r = sd_bus_message_close_container(tm);
764 if (r < 0)
765 return r;
766
767 r = sd_bus_message_close_container(tm);
768 if (r < 0)
769 return r;
770 }
771
772 /* Exec container */
773 r = sd_bus_message_open_container(tm, 'r', "sv");
774 if (r < 0)
775 return r;
776
777 r = sd_bus_message_append(tm, "s", "ExecStart");
778 if (r < 0)
779 return r;
780
781 r = sd_bus_message_open_container(tm, 'v', "a(sasb)");
782 if (r < 0)
783 return r;
784
785 r = sd_bus_message_open_container(tm, 'a', "(sasb)");
786 if (r < 0)
787 return r;
788
789 r = sd_bus_message_open_container(tm, 'r', "sasb");
790 if (r < 0)
791 return r;
792
793 r = sd_bus_message_append(tm, "s", path);
794 if (r < 0)
795 return r;
796
797 r = sd_bus_message_append_strv(tm, args);
798 if (r < 0)
799 return r;
800
801 r = sd_bus_message_append(tm, "b", true);
802 if (r < 0)
803 return r;
804
805 r = sd_bus_message_close_container(tm);
806 if (r < 0)
807 return r;
808
809 r = sd_bus_message_close_container(tm);
810 if (r < 0)
811 return r;
812
813 r = sd_bus_message_close_container(tm);
814 if (r < 0)
815 return r;
816
817 r = sd_bus_message_close_container(tm);
818 if (r < 0)
819 return r;
820
821 r = sd_bus_message_close_container(tm);
822 if (r < 0)
823 return r;
824
825 /* Auxiliary units */
826 r = sd_bus_message_append(tm, "a(sa(sv))", 0);
827 if (r < 0)
828 return r;
829
830 r = sd_bus_call(container_bus, tm, 0, error, NULL);
831 if (r < 0)
832 return r;
833
834 slave = safe_close(slave);
835
836 r = sd_bus_message_new_method_return(message, &reply);
837 if (r < 0)
838 return r;
839
840 r = sd_bus_message_append(reply, "hs", master, pty_name);
841 if (r < 0)
842 return r;
843
844 return sd_bus_send(NULL, reply, NULL);
845 }
846
847 int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
848 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
849 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
850 bool mount_slave_created = false, mount_slave_mounted = false,
851 mount_tmp_created = false, mount_tmp_mounted = false,
852 mount_outside_created = false, mount_outside_mounted = false;
853 _cleanup_free_ char *chased_src = NULL;
854 int read_only, make_file_or_directory;
855 const char *dest, *src;
856 Machine *m = userdata;
857 struct stat st;
858 pid_t child;
859 uid_t uid;
860 int r;
861
862 assert(message);
863 assert(m);
864
865 if (m->class != MACHINE_CONTAINER)
866 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
867
868 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory);
869 if (r < 0)
870 return r;
871
872 if (!path_is_absolute(src) || !path_is_normalized(src))
873 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
874
875 if (isempty(dest))
876 dest = src;
877 else if (!path_is_absolute(dest) || !path_is_normalized(dest))
878 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
879
880 r = bus_verify_polkit_async(
881 message,
882 CAP_SYS_ADMIN,
883 "org.freedesktop.machine1.manage-machines",
884 NULL,
885 false,
886 UID_INVALID,
887 &m->manager->polkit_registry,
888 error);
889 if (r < 0)
890 return r;
891 if (r == 0)
892 return 1; /* Will call us back */
893
894 r = machine_get_uid_shift(m, &uid);
895 if (r < 0)
896 return r;
897 if (uid != 0)
898 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied.");
899
900 /* One day, when bind mounting /proc/self/fd/n works across
901 * namespace boundaries we should rework this logic to make
902 * use of it... */
903
904 p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
905 if (laccess(p, F_OK) < 0)
906 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
907
908 r = chase_symlinks(src, NULL, CHASE_TRAIL_SLASH, &chased_src);
909 if (r < 0)
910 return sd_bus_error_set_errnof(error, r, "Failed to resolve source path: %m");
911
912 if (lstat(chased_src, &st) < 0)
913 return sd_bus_error_set_errnof(error, errno, "Failed to stat() source path: %m");
914 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… */
915 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Source directory can't be a symbolic link");
916
917 /* Our goal is to install a new bind mount into the container,
918 possibly read-only. This is irritatingly complex
919 unfortunately, currently.
920
921 First, we start by creating a private playground in /tmp,
922 that we can mount MS_SLAVE. (Which is necessary, since
923 MS_MOVE cannot be applied to mounts with MS_SHARED parent
924 mounts.) */
925
926 if (!mkdtemp(mount_slave))
927 return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
928
929 mount_slave_created = true;
930
931 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
932 r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
933 goto finish;
934 }
935
936 mount_slave_mounted = true;
937
938 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
939 r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
940 goto finish;
941 }
942
943 /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */
944 mount_tmp = strjoina(mount_slave, "/mount");
945 if (S_ISDIR(st.st_mode))
946 r = mkdir_errno_wrapper(mount_tmp, 0700);
947 else
948 r = touch(mount_tmp);
949 if (r < 0) {
950 sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
951 goto finish;
952 }
953
954 mount_tmp_created = true;
955
956 if (mount(chased_src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
957 r = sd_bus_error_set_errnof(error, errno, "Failed to mount %s: %m", chased_src);
958 goto finish;
959 }
960
961 mount_tmp_mounted = true;
962
963 /* Third, we remount the new bind mount read-only if requested. */
964 if (read_only)
965 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
966 r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
967 goto finish;
968 }
969
970 /* Fourth, we move the new bind mount into the propagation directory. This way it will appear there read-only
971 * right-away. */
972
973 mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
974 if (S_ISDIR(st.st_mode))
975 r = mkdtemp(mount_outside) ? 0 : -errno;
976 else {
977 r = mkostemp_safe(mount_outside);
978 safe_close(r);
979 }
980 if (r < 0) {
981 sd_bus_error_set_errnof(error, errno, "Cannot create propagation file or directory %s: %m", mount_outside);
982 goto finish;
983 }
984
985 mount_outside_created = true;
986
987 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
988 r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
989 goto finish;
990 }
991
992 mount_outside_mounted = true;
993 mount_tmp_mounted = false;
994
995 if (S_ISDIR(st.st_mode))
996 (void) rmdir(mount_tmp);
997 else
998 (void) unlink(mount_tmp);
999 mount_tmp_created = false;
1000
1001 (void) umount(mount_slave);
1002 mount_slave_mounted = false;
1003
1004 (void) rmdir(mount_slave);
1005 mount_slave_created = false;
1006
1007 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
1008 r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
1009 goto finish;
1010 }
1011
1012 r = safe_fork("(sd-bindmnt)", FORK_RESET_SIGNALS, &child);
1013 if (r < 0) {
1014 sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
1015 goto finish;
1016 }
1017 if (r == 0) {
1018 const char *mount_inside;
1019 int mntfd;
1020 const char *q;
1021
1022 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1023
1024 q = procfs_file_alloca(m->leader, "ns/mnt");
1025 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1026 if (mntfd < 0) {
1027 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1028 goto child_fail;
1029 }
1030
1031 if (setns(mntfd, CLONE_NEWNS) < 0) {
1032 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1033 goto child_fail;
1034 }
1035
1036 if (make_file_or_directory) {
1037 if (S_ISDIR(st.st_mode))
1038 (void) mkdir_p(dest, 0755);
1039 else {
1040 (void) mkdir_parents(dest, 0755);
1041 safe_close(open(dest, O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600));
1042 }
1043 }
1044
1045 /* Fifth, move the mount to the right place inside */
1046 mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
1047 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
1048 r = log_error_errno(errno, "Failed to mount: %m");
1049 goto child_fail;
1050 }
1051
1052 _exit(EXIT_SUCCESS);
1053
1054 child_fail:
1055 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1056 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1057
1058 _exit(EXIT_FAILURE);
1059 }
1060
1061 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1062
1063 r = wait_for_terminate_and_check("(sd-bindmnt)", child, 0);
1064 if (r < 0) {
1065 r = sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
1066 goto finish;
1067 }
1068 if (r != EXIT_SUCCESS) {
1069 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
1070 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
1071 else
1072 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child failed.");
1073 goto finish;
1074 }
1075
1076 r = sd_bus_reply_method_return(message, NULL);
1077
1078 finish:
1079 if (mount_outside_mounted)
1080 (void) umount(mount_outside);
1081 if (mount_outside_created) {
1082 if (S_ISDIR(st.st_mode))
1083 (void) rmdir(mount_outside);
1084 else
1085 (void) unlink(mount_outside);
1086 }
1087
1088 if (mount_tmp_mounted)
1089 (void) umount(mount_tmp);
1090 if (mount_tmp_created) {
1091 if (S_ISDIR(st.st_mode))
1092 (void) rmdir(mount_tmp);
1093 else
1094 (void) unlink(mount_tmp);
1095 }
1096
1097 if (mount_slave_mounted)
1098 (void) umount(mount_slave);
1099 if (mount_slave_created)
1100 (void) rmdir(mount_slave);
1101
1102 return r;
1103 }
1104
1105 int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1106 const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
1107 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
1108 CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE;
1109 _cleanup_close_ int hostfd = -1;
1110 Machine *m = userdata;
1111 bool copy_from;
1112 pid_t child;
1113 uid_t uid_shift;
1114 char *t;
1115 int r;
1116
1117 assert(message);
1118 assert(m);
1119
1120 if (m->manager->n_operations >= OPERATIONS_MAX)
1121 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
1122
1123 if (m->class != MACHINE_CONTAINER)
1124 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
1125
1126 r = sd_bus_message_read(message, "ss", &src, &dest);
1127 if (r < 0)
1128 return r;
1129
1130 if (!path_is_absolute(src))
1131 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
1132
1133 if (isempty(dest))
1134 dest = src;
1135 else if (!path_is_absolute(dest))
1136 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
1137
1138 r = bus_verify_polkit_async(
1139 message,
1140 CAP_SYS_ADMIN,
1141 "org.freedesktop.machine1.manage-machines",
1142 NULL,
1143 false,
1144 UID_INVALID,
1145 &m->manager->polkit_registry,
1146 error);
1147 if (r < 0)
1148 return r;
1149 if (r == 0)
1150 return 1; /* Will call us back */
1151
1152 r = machine_get_uid_shift(m, &uid_shift);
1153 if (r < 0)
1154 return r;
1155
1156 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
1157
1158 if (copy_from) {
1159 container_path = src;
1160 host_path = dest;
1161 } else {
1162 host_path = src;
1163 container_path = dest;
1164 }
1165
1166 host_basename = basename(host_path);
1167 t = strdupa(host_path);
1168 host_dirname = dirname(t);
1169
1170 container_basename = basename(container_path);
1171 t = strdupa(container_path);
1172 container_dirname = dirname(t);
1173
1174 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1175 if (hostfd < 0)
1176 return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
1177
1178 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
1179 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
1180
1181 r = safe_fork("(sd-copy)", FORK_RESET_SIGNALS, &child);
1182 if (r < 0)
1183 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
1184 if (r == 0) {
1185 int containerfd;
1186 const char *q;
1187 int mntfd;
1188
1189 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1190
1191 q = procfs_file_alloca(m->leader, "ns/mnt");
1192 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1193 if (mntfd < 0) {
1194 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1195 goto child_fail;
1196 }
1197
1198 if (setns(mntfd, CLONE_NEWNS) < 0) {
1199 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1200 goto child_fail;
1201 }
1202
1203 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1204 if (containerfd < 0) {
1205 r = log_error_errno(errno, "Failed to open destination directory: %m");
1206 goto child_fail;
1207 }
1208
1209 /* Run the actual copy operation. Note that when an UID shift is set we'll either clamp the UID/GID to
1210 * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
1211 * the UID/GIDs as they are. */
1212 if (copy_from)
1213 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags);
1214 else
1215 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);
1216
1217 hostfd = safe_close(hostfd);
1218 containerfd = safe_close(containerfd);
1219
1220 if (r < 0) {
1221 r = log_error_errno(r, "Failed to copy tree: %m");
1222 goto child_fail;
1223 }
1224
1225 _exit(EXIT_SUCCESS);
1226
1227 child_fail:
1228 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1229 _exit(EXIT_FAILURE);
1230 }
1231
1232 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1233
1234 /* Copying might take a while, hence install a watch on the child, and return */
1235
1236 r = operation_new(m->manager, m, child, message, errno_pipe_fd[0], NULL);
1237 if (r < 0) {
1238 (void) sigkill_wait(child);
1239 return r;
1240 }
1241 errno_pipe_fd[0] = -1;
1242
1243 return 1;
1244 }
1245
1246 int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1247 _cleanup_close_ int fd = -1;
1248 Machine *m = userdata;
1249 int r;
1250
1251 assert(message);
1252 assert(m);
1253
1254 r = bus_verify_polkit_async(
1255 message,
1256 CAP_SYS_ADMIN,
1257 "org.freedesktop.machine1.manage-machines",
1258 NULL,
1259 false,
1260 UID_INVALID,
1261 &m->manager->polkit_registry,
1262 error);
1263 if (r < 0)
1264 return r;
1265 if (r == 0)
1266 return 1; /* Will call us back */
1267
1268 switch (m->class) {
1269
1270 case MACHINE_HOST:
1271 fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1272 if (fd < 0)
1273 return -errno;
1274
1275 break;
1276
1277 case MACHINE_CONTAINER: {
1278 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
1279 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1280 pid_t child;
1281
1282 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
1283 if (r < 0)
1284 return r;
1285
1286 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1287 return -errno;
1288
1289 r = safe_fork("(sd-openroot)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
1290 if (r < 0)
1291 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
1292 if (r == 0) {
1293 _cleanup_close_ int dfd = -1;
1294
1295 pair[0] = safe_close(pair[0]);
1296
1297 r = namespace_enter(-1, mntns_fd, -1, -1, root_fd);
1298 if (r < 0)
1299 _exit(EXIT_FAILURE);
1300
1301 dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1302 if (dfd < 0)
1303 _exit(EXIT_FAILURE);
1304
1305 r = send_one_fd(pair[1], dfd, 0);
1306 dfd = safe_close(dfd);
1307 if (r < 0)
1308 _exit(EXIT_FAILURE);
1309
1310 _exit(EXIT_SUCCESS);
1311 }
1312
1313 pair[1] = safe_close(pair[1]);
1314
1315 r = wait_for_terminate_and_check("(sd-openroot)", child, 0);
1316 if (r < 0)
1317 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
1318 if (r != EXIT_SUCCESS)
1319 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
1320
1321 fd = receive_one_fd(pair[0], MSG_DONTWAIT);
1322 if (fd < 0)
1323 return fd;
1324
1325 break;
1326 }
1327
1328 default:
1329 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
1330 }
1331
1332 return sd_bus_reply_method_return(message, "h", fd);
1333 }
1334
1335 int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1336 Machine *m = userdata;
1337 uid_t shift = 0;
1338 int r;
1339
1340 assert(message);
1341 assert(m);
1342
1343 /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but
1344 * we kinda have to for this. */
1345
1346 if (m->class == MACHINE_HOST)
1347 return sd_bus_reply_method_return(message, "u", UINT32_C(0));
1348
1349 if (m->class != MACHINE_CONTAINER)
1350 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines.");
1351
1352 r = machine_get_uid_shift(m, &shift);
1353 if (r == -ENXIO)
1354 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m->name);
1355 if (r < 0)
1356 return r;
1357
1358 return sd_bus_reply_method_return(message, "u", (uint32_t) shift);
1359 }
1360
1361 const sd_bus_vtable machine_vtable[] = {
1362 SD_BUS_VTABLE_START(0),
1363 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
1364 SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST),
1365 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1366 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
1367 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
1368 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1369 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
1370 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
1371 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
1372 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1373 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
1374 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
1375 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
1376 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
1377 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
1378 SD_BUS_METHOD("GetUIDShift", NULL, "u", bus_machine_method_get_uid_shift, SD_BUS_VTABLE_UNPRIVILEGED),
1379 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, SD_BUS_VTABLE_UNPRIVILEGED),
1380 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
1381 SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell, SD_BUS_VTABLE_UNPRIVILEGED),
1382 SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
1383 SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
1384 SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
1385 SD_BUS_METHOD("OpenRootDirectory", NULL, "h", bus_machine_method_open_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
1386 SD_BUS_VTABLE_END
1387 };
1388
1389 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
1390 Manager *m = userdata;
1391 Machine *machine;
1392 int r;
1393
1394 assert(bus);
1395 assert(path);
1396 assert(interface);
1397 assert(found);
1398 assert(m);
1399
1400 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
1401 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
1402 sd_bus_message *message;
1403 pid_t pid;
1404
1405 message = sd_bus_get_current_message(bus);
1406 if (!message)
1407 return 0;
1408
1409 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
1410 if (r < 0)
1411 return r;
1412
1413 r = sd_bus_creds_get_pid(creds, &pid);
1414 if (r < 0)
1415 return r;
1416
1417 r = manager_get_machine_by_pid(m, pid, &machine);
1418 if (r <= 0)
1419 return 0;
1420 } else {
1421 _cleanup_free_ char *e = NULL;
1422 const char *p;
1423
1424 p = startswith(path, "/org/freedesktop/machine1/machine/");
1425 if (!p)
1426 return 0;
1427
1428 e = bus_label_unescape(p);
1429 if (!e)
1430 return -ENOMEM;
1431
1432 machine = hashmap_get(m->machines, e);
1433 if (!machine)
1434 return 0;
1435 }
1436
1437 *found = machine;
1438 return 1;
1439 }
1440
1441 char *machine_bus_path(Machine *m) {
1442 _cleanup_free_ char *e = NULL;
1443
1444 assert(m);
1445
1446 e = bus_label_escape(m->name);
1447 if (!e)
1448 return NULL;
1449
1450 return strappend("/org/freedesktop/machine1/machine/", e);
1451 }
1452
1453 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
1454 _cleanup_strv_free_ char **l = NULL;
1455 Machine *machine = NULL;
1456 Manager *m = userdata;
1457 Iterator i;
1458 int r;
1459
1460 assert(bus);
1461 assert(path);
1462 assert(nodes);
1463
1464 HASHMAP_FOREACH(machine, m->machines, i) {
1465 char *p;
1466
1467 p = machine_bus_path(machine);
1468 if (!p)
1469 return -ENOMEM;
1470
1471 r = strv_consume(&l, p);
1472 if (r < 0)
1473 return r;
1474 }
1475
1476 *nodes = TAKE_PTR(l);
1477
1478 return 1;
1479 }
1480
1481 int machine_send_signal(Machine *m, bool new_machine) {
1482 _cleanup_free_ char *p = NULL;
1483
1484 assert(m);
1485
1486 p = machine_bus_path(m);
1487 if (!p)
1488 return -ENOMEM;
1489
1490 return sd_bus_emit_signal(
1491 m->manager->bus,
1492 "/org/freedesktop/machine1",
1493 "org.freedesktop.machine1.Manager",
1494 new_machine ? "MachineNew" : "MachineRemoved",
1495 "so", m->name, p);
1496 }
1497
1498 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
1499 _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
1500 _cleanup_free_ char *p = NULL;
1501
1502 assert(m);
1503
1504 if (!m->create_message)
1505 return 0;
1506
1507 c = TAKE_PTR(m->create_message);
1508
1509 if (error)
1510 return sd_bus_reply_method_error(c, error);
1511
1512 /* Update the machine state file before we notify the client
1513 * about the result. */
1514 machine_save(m);
1515
1516 p = machine_bus_path(m);
1517 if (!p)
1518 return -ENOMEM;
1519
1520 return sd_bus_reply_method_return(c, "o", p);
1521 }