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