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