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