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