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