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