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