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