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