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