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