1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/mount.h>
26 /* When we include libgen.h because we need dirname() we immediately
27 * undefine basename() since libgen.h defines it as a macro to the POSIX
28 * version which is really broken. We prefer GNU basename(). */
32 #include "alloc-util.h"
33 #include "bus-common-errors.h"
34 #include "bus-internal.h"
35 #include "bus-label.h"
41 #include "format-util.h"
43 #include "in-addr-util.h"
44 #include "local-addresses.h"
45 #include "machine-dbus.h"
48 #include "path-util.h"
49 #include "process-util.h"
50 #include "signal-util.h"
52 #include "terminal-util.h"
53 #include "user-util.h"
55 static int property_get_state(
58 const char *interface
,
60 sd_bus_message
*reply
,
62 sd_bus_error
*error
) {
64 Machine
*m
= userdata
;
72 state
= machine_state_to_string(machine_get_state(m
));
74 r
= sd_bus_message_append_basic(reply
, 's', state
);
81 static int property_get_netif(
84 const char *interface
,
86 sd_bus_message
*reply
,
88 sd_bus_error
*error
) {
90 Machine
*m
= userdata
;
96 assert_cc(sizeof(int) == sizeof(int32_t));
98 return sd_bus_message_append_array(reply
, 'i', m
->netif
, m
->n_netif
* sizeof(int));
101 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class
, machine_class
, MachineClass
);
103 int bus_machine_method_terminate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
104 Machine
*m
= userdata
;
110 r
= bus_verify_polkit_async(
113 "org.freedesktop.machine1.manage-machines",
117 &m
->manager
->polkit_registry
,
122 return 1; /* Will call us back */
128 return sd_bus_reply_method_return(message
, NULL
);
131 int bus_machine_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
132 Machine
*m
= userdata
;
141 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
148 who
= kill_who_from_string(swho
);
150 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid kill parameter '%s'", swho
);
153 if (!SIGNAL_VALID(signo
))
154 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid signal %i", signo
);
156 r
= bus_verify_polkit_async(
159 "org.freedesktop.machine1.manage-machines",
163 &m
->manager
->polkit_registry
,
168 return 1; /* Will call us back */
170 r
= machine_kill(m
, who
, signo
);
174 return sd_bus_reply_method_return(message
, NULL
);
177 int bus_machine_method_get_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
178 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
179 Machine
*m
= userdata
;
185 r
= sd_bus_message_new_method_return(message
, &reply
);
189 r
= sd_bus_message_open_container(reply
, 'a', "(iay)");
196 _cleanup_free_
struct local_address
*addresses
= NULL
;
197 struct local_address
*a
;
200 n
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
204 for (a
= addresses
, i
= 0; i
< n
; a
++, i
++) {
206 r
= sd_bus_message_open_container(reply
, 'r', "iay");
210 r
= sd_bus_message_append(reply
, "i", addresses
[i
].family
);
214 r
= sd_bus_message_append_array(reply
, 'y', &addresses
[i
].address
, FAMILY_ADDRESS_SIZE(addresses
[i
].family
));
218 r
= sd_bus_message_close_container(reply
);
226 case MACHINE_CONTAINER
: {
227 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
228 _cleanup_free_
char *us
= NULL
, *them
= NULL
;
229 _cleanup_close_
int netns_fd
= -1;
233 r
= readlink_malloc("/proc/self/ns/net", &us
);
237 p
= procfs_file_alloca(m
->leader
, "ns/net");
238 r
= readlink_malloc(p
, &them
);
243 return sd_bus_error_setf(error
, BUS_ERROR_NO_PRIVATE_NETWORKING
, "Machine %s does not use private networking", m
->name
);
245 r
= namespace_open(m
->leader
, NULL
, NULL
, &netns_fd
, NULL
, NULL
);
249 if (socketpair(AF_UNIX
, SOCK_SEQPACKET
, 0, pair
) < 0)
252 r
= safe_fork("(sd-addr)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
, &child
);
254 return sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
256 _cleanup_free_
struct local_address
*addresses
= NULL
;
257 struct local_address
*a
;
260 pair
[0] = safe_close(pair
[0]);
262 r
= namespace_enter(-1, -1, netns_fd
, -1, -1);
266 n
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
270 for (a
= addresses
, i
= 0; i
< n
; a
++, i
++) {
271 struct iovec iov
[2] = {
272 { .iov_base
= &a
->family
, .iov_len
= sizeof(a
->family
) },
273 { .iov_base
= &a
->address
, .iov_len
= FAMILY_ADDRESS_SIZE(a
->family
) },
276 r
= writev(pair
[1], iov
, 2);
281 pair
[1] = safe_close(pair
[1]);
286 pair
[1] = safe_close(pair
[1]);
291 union in_addr_union in_addr
;
298 iov
[0] = (struct iovec
) { .iov_base
= &family
, .iov_len
= sizeof(family
) };
299 iov
[1] = (struct iovec
) { .iov_base
= &in_addr
, .iov_len
= sizeof(in_addr
) };
301 n
= recvmsg(pair
[0], &mh
, 0);
304 if ((size_t) n
< sizeof(family
))
307 r
= sd_bus_message_open_container(reply
, 'r', "iay");
311 r
= sd_bus_message_append(reply
, "i", family
);
318 if (n
!= sizeof(struct in_addr
) + sizeof(family
))
321 r
= sd_bus_message_append_array(reply
, 'y', &in_addr
.in
, sizeof(in_addr
.in
));
325 if (n
!= sizeof(struct in6_addr
) + sizeof(family
))
328 r
= sd_bus_message_append_array(reply
, 'y', &in_addr
.in6
, sizeof(in_addr
.in6
));
334 r
= sd_bus_message_close_container(reply
);
339 r
= wait_for_terminate_and_check("(sd-addr)", child
, 0);
341 return sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
342 if (r
!= EXIT_SUCCESS
)
343 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child died abnormally.");
348 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Requesting IP address data is only supported on container machines.");
351 r
= sd_bus_message_close_container(reply
);
355 return sd_bus_send(NULL
, reply
, NULL
);
358 #define EXIT_NOT_FOUND 2
360 int bus_machine_method_get_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
361 _cleanup_strv_free_
char **l
= NULL
;
362 Machine
*m
= userdata
;
371 r
= load_env_file_pairs(NULL
, "/etc/os-release", NULL
, &l
);
377 case MACHINE_CONTAINER
: {
378 _cleanup_close_
int mntns_fd
= -1, root_fd
= -1;
379 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
380 _cleanup_fclose_
FILE *f
= NULL
;
383 r
= namespace_open(m
->leader
, NULL
, &mntns_fd
, NULL
, NULL
, &root_fd
);
387 if (socketpair(AF_UNIX
, SOCK_SEQPACKET
, 0, pair
) < 0)
390 r
= safe_fork("(sd-osrel)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
, &child
);
392 return sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
396 pair
[0] = safe_close(pair
[0]);
398 r
= namespace_enter(-1, mntns_fd
, -1, -1, root_fd
);
402 fd
= open("/etc/os-release", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
403 if (fd
< 0 && errno
== ENOENT
) {
404 fd
= open("/usr/lib/os-release", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
405 if (fd
< 0 && errno
== ENOENT
)
406 _exit(EXIT_NOT_FOUND
);
411 r
= copy_bytes(fd
, pair
[1], (uint64_t) -1, 0);
418 pair
[1] = safe_close(pair
[1]);
420 f
= fdopen(pair
[0], "re");
426 r
= load_env_file_pairs(f
, "/etc/os-release", NULL
, &l
);
430 r
= wait_for_terminate_and_check("(sd-osrel)", child
, 0);
432 return sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
433 if (r
== EXIT_NOT_FOUND
)
434 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Machine does not contain OS release information");
435 if (r
!= EXIT_SUCCESS
)
436 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child died abnormally.");
442 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Requesting OS release data is only supported on container machines.");
445 return bus_reply_pair_array(message
, l
);
448 int bus_machine_method_open_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
449 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
450 _cleanup_free_
char *pty_name
= NULL
;
451 _cleanup_close_
int master
= -1;
452 Machine
*m
= userdata
;
458 r
= bus_verify_polkit_async(
461 m
->class == MACHINE_HOST
? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty",
465 &m
->manager
->polkit_registry
,
470 return 1; /* Will call us back */
472 master
= machine_openpt(m
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
476 r
= ptsname_namespace(master
, &pty_name
);
480 r
= sd_bus_message_new_method_return(message
, &reply
);
484 r
= sd_bus_message_append(reply
, "hs", master
, pty_name
);
488 return sd_bus_send(NULL
, reply
, NULL
);
491 static int container_bus_new(Machine
*m
, sd_bus_error
*error
, sd_bus
**ret
) {
503 case MACHINE_CONTAINER
: {
504 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
507 r
= sd_bus_new(&bus
);
511 if (asprintf(&address
, "x-machine-kernel:pid=%1$" PID_PRI
";x-machine-unix:pid=%1$" PID_PRI
, m
->leader
) < 0)
514 bus
->address
= address
;
515 bus
->bus_client
= true;
516 bus
->trusted
= false;
517 bus
->is_system
= true;
519 r
= sd_bus_start(bus
);
521 return sd_bus_error_set_errnof(error
, r
, "There is no system bus in container %s.", m
->name
);
525 *ret
= TAKE_PTR(bus
);
536 int bus_machine_method_open_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
537 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
538 _cleanup_free_
char *pty_name
= NULL
;
539 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*allocated_bus
= NULL
;
540 _cleanup_close_
int master
= -1;
541 sd_bus
*container_bus
= NULL
;
542 Machine
*m
= userdata
;
543 const char *p
, *getty
;
549 r
= bus_verify_polkit_async(
552 m
->class == MACHINE_HOST
? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
556 &m
->manager
->polkit_registry
,
561 return 1; /* Will call us back */
563 master
= machine_openpt(m
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
567 r
= ptsname_namespace(master
, &pty_name
);
571 p
= path_startswith(pty_name
, "/dev/pts/");
573 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "PTS name %s is invalid", pty_name
);
575 r
= container_bus_new(m
, error
, &allocated_bus
);
579 container_bus
= allocated_bus
?: m
->manager
->bus
;
581 getty
= strjoina("container-getty@", p
, ".service");
583 r
= sd_bus_call_method(
585 "org.freedesktop.systemd1",
586 "/org/freedesktop/systemd1",
587 "org.freedesktop.systemd1.Manager",
590 "ss", getty
, "replace");
594 r
= sd_bus_message_new_method_return(message
, &reply
);
598 r
= sd_bus_message_append(reply
, "hs", master
, pty_name
);
602 return sd_bus_send(NULL
, reply
, NULL
);
605 int bus_machine_method_open_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
606 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
, *tm
= NULL
;
607 _cleanup_free_
char *pty_name
= NULL
;
608 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*allocated_bus
= NULL
;
609 sd_bus
*container_bus
= NULL
;
610 _cleanup_close_
int master
= -1, slave
= -1;
611 _cleanup_strv_free_
char **env
= NULL
, **args_wire
= NULL
, **args
= NULL
;
612 Machine
*m
= userdata
;
613 const char *p
, *unit
, *user
, *path
, *description
, *utmp_id
;
619 r
= sd_bus_message_read(message
, "ss", &user
, &path
);
622 user
= empty_to_null(user
);
623 r
= sd_bus_message_read_strv(message
, &args_wire
);
629 args
= new0(char*, 3 + 1);
632 args
[0] = strdup("sh");
635 args
[1] = strdup("-c");
638 r
= asprintf(&args
[2],
639 "shell=$(getent passwd %s 2>/dev/null | { IFS=: read _ _ _ _ _ _ x; echo \"$x\"; })\n"\
640 "exec \"${shell:-/bin/sh}\" -l", /* -l is means --login */
641 isempty(user
) ? "root" : user
);
647 if (!path_is_absolute(path
))
648 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Specified path '%s' is not absolute", path
);
649 args
= TAKE_PTR(args_wire
);
650 if (strv_isempty(args
)) {
651 args
= strv_free(args
);
653 args
= strv_new(path
, NULL
);
659 r
= sd_bus_message_read_strv(message
, &env
);
662 if (!strv_env_is_valid(env
))
663 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid environment assignments");
665 r
= bus_verify_polkit_async(
668 m
->class == MACHINE_HOST
? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
672 &m
->manager
->polkit_registry
,
677 return 1; /* Will call us back */
679 master
= machine_openpt(m
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
683 r
= ptsname_namespace(master
, &pty_name
);
687 p
= path_startswith(pty_name
, "/dev/pts/");
690 slave
= machine_open_terminal(m
, pty_name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
694 utmp_id
= path_startswith(pty_name
, "/dev/");
697 r
= container_bus_new(m
, error
, &allocated_bus
);
701 container_bus
= allocated_bus
?: m
->manager
->bus
;
703 r
= sd_bus_message_new_method_call(
706 "org.freedesktop.systemd1",
707 "/org/freedesktop/systemd1",
708 "org.freedesktop.systemd1.Manager",
709 "StartTransientUnit");
714 unit
= strjoina("container-shell@", p
, ".service");
715 r
= sd_bus_message_append(tm
, "ss", unit
, "fail");
720 r
= sd_bus_message_open_container(tm
, 'a', "(sv)");
724 description
= strjoina("Shell for User ", isempty(user
) ? "root" : user
);
725 r
= sd_bus_message_append(tm
,
726 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
727 "Description", "s", description
,
728 "StandardInputFileDescriptor", "h", slave
,
729 "StandardOutputFileDescriptor", "h", slave
,
730 "StandardErrorFileDescriptor", "h", slave
,
731 "SendSIGHUP", "b", true,
732 "IgnoreSIGPIPE", "b", false,
733 "KillMode", "s", "mixed",
734 "TTYReset", "b", true,
735 "UtmpIdentifier", "s", utmp_id
,
736 "UtmpMode", "s", "user",
737 "PAMName", "s", "login",
738 "WorkingDirectory", "s", "-~");
742 r
= sd_bus_message_append(tm
, "(sv)", "User", "s", isempty(user
) ? "root" : user
);
746 if (!strv_isempty(env
)) {
747 r
= sd_bus_message_open_container(tm
, 'r', "sv");
751 r
= sd_bus_message_append(tm
, "s", "Environment");
755 r
= sd_bus_message_open_container(tm
, 'v', "as");
759 r
= sd_bus_message_append_strv(tm
, env
);
763 r
= sd_bus_message_close_container(tm
);
767 r
= sd_bus_message_close_container(tm
);
773 r
= sd_bus_message_open_container(tm
, 'r', "sv");
777 r
= sd_bus_message_append(tm
, "s", "ExecStart");
781 r
= sd_bus_message_open_container(tm
, 'v', "a(sasb)");
785 r
= sd_bus_message_open_container(tm
, 'a', "(sasb)");
789 r
= sd_bus_message_open_container(tm
, 'r', "sasb");
793 r
= sd_bus_message_append(tm
, "s", path
);
797 r
= sd_bus_message_append_strv(tm
, args
);
801 r
= sd_bus_message_append(tm
, "b", true);
805 r
= sd_bus_message_close_container(tm
);
809 r
= sd_bus_message_close_container(tm
);
813 r
= sd_bus_message_close_container(tm
);
817 r
= sd_bus_message_close_container(tm
);
821 r
= sd_bus_message_close_container(tm
);
825 /* Auxiliary units */
826 r
= sd_bus_message_append(tm
, "a(sa(sv))", 0);
830 r
= sd_bus_call(container_bus
, tm
, 0, error
, NULL
);
834 slave
= safe_close(slave
);
836 r
= sd_bus_message_new_method_return(message
, &reply
);
840 r
= sd_bus_message_append(reply
, "hs", master
, pty_name
);
844 return sd_bus_send(NULL
, reply
, NULL
);
847 int bus_machine_method_bind_mount(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
848 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
849 char mount_slave
[] = "/tmp/propagate.XXXXXX", *mount_tmp
, *mount_outside
, *p
;
850 bool mount_slave_created
= false, mount_slave_mounted
= false,
851 mount_tmp_created
= false, mount_tmp_mounted
= false,
852 mount_outside_created
= false, mount_outside_mounted
= false;
853 _cleanup_free_
char *chased_src
= NULL
;
854 int read_only
, make_file_or_directory
;
855 const char *dest
, *src
;
856 Machine
*m
= userdata
;
865 if (m
->class != MACHINE_CONTAINER
)
866 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Bind mounting is only supported on container machines.");
868 r
= sd_bus_message_read(message
, "ssbb", &src
, &dest
, &read_only
, &make_file_or_directory
);
872 if (!path_is_absolute(src
) || !path_is_normalized(src
))
873 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Source path must be absolute and not contain ../.");
877 else if (!path_is_absolute(dest
) || !path_is_normalized(dest
))
878 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Destination path must be absolute and not contain ../.");
880 r
= bus_verify_polkit_async(
883 "org.freedesktop.machine1.manage-machines",
887 &m
->manager
->polkit_registry
,
892 return 1; /* Will call us back */
894 r
= machine_get_uid_shift(m
, &uid
);
898 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Can't bind mount on container with user namespacing applied.");
900 /* One day, when bind mounting /proc/self/fd/n works across
901 * namespace boundaries we should rework this logic to make
904 p
= strjoina("/run/systemd/nspawn/propagate/", m
->name
, "/");
905 if (laccess(p
, F_OK
) < 0)
906 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Container does not allow propagation of mount points.");
908 r
= chase_symlinks(src
, NULL
, CHASE_TRAIL_SLASH
, &chased_src
);
910 return sd_bus_error_set_errnof(error
, r
, "Failed to resolve source path: %m");
912 if (lstat(chased_src
, &st
) < 0)
913 return sd_bus_error_set_errnof(error
, errno
, "Failed to stat() source path: %m");
914 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… */
915 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Source directory can't be a symbolic link");
917 /* Our goal is to install a new bind mount into the container,
918 possibly read-only. This is irritatingly complex
919 unfortunately, currently.
921 First, we start by creating a private playground in /tmp,
922 that we can mount MS_SLAVE. (Which is necessary, since
923 MS_MOVE cannot be applied to mounts with MS_SHARED parent
926 if (!mkdtemp(mount_slave
))
927 return sd_bus_error_set_errnof(error
, errno
, "Failed to create playground %s: %m", mount_slave
);
929 mount_slave_created
= true;
931 if (mount(mount_slave
, mount_slave
, NULL
, MS_BIND
, NULL
) < 0) {
932 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to make bind mount %s: %m", mount_slave
);
936 mount_slave_mounted
= true;
938 if (mount(NULL
, mount_slave
, NULL
, MS_SLAVE
, NULL
) < 0) {
939 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to remount slave %s: %m", mount_slave
);
943 /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */
944 mount_tmp
= strjoina(mount_slave
, "/mount");
945 if (S_ISDIR(st
.st_mode
))
946 r
= mkdir_errno_wrapper(mount_tmp
, 0700);
948 r
= touch(mount_tmp
);
950 sd_bus_error_set_errnof(error
, errno
, "Failed to create temporary mount point %s: %m", mount_tmp
);
954 mount_tmp_created
= true;
956 if (mount(chased_src
, mount_tmp
, NULL
, MS_BIND
, NULL
) < 0) {
957 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to mount %s: %m", chased_src
);
961 mount_tmp_mounted
= true;
963 /* Third, we remount the new bind mount read-only if requested. */
965 if (mount(NULL
, mount_tmp
, NULL
, MS_BIND
|MS_REMOUNT
|MS_RDONLY
, NULL
) < 0) {
966 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to remount read-only %s: %m", mount_tmp
);
970 /* Fourth, we move the new bind mount into the propagation directory. This way it will appear there read-only
973 mount_outside
= strjoina("/run/systemd/nspawn/propagate/", m
->name
, "/XXXXXX");
974 if (S_ISDIR(st
.st_mode
))
975 r
= mkdtemp(mount_outside
) ? 0 : -errno
;
977 r
= mkostemp_safe(mount_outside
);
981 sd_bus_error_set_errnof(error
, errno
, "Cannot create propagation file or directory %s: %m", mount_outside
);
985 mount_outside_created
= true;
987 if (mount(mount_tmp
, mount_outside
, NULL
, MS_MOVE
, NULL
) < 0) {
988 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to move %s to %s: %m", mount_tmp
, mount_outside
);
992 mount_outside_mounted
= true;
993 mount_tmp_mounted
= false;
995 if (S_ISDIR(st
.st_mode
))
996 (void) rmdir(mount_tmp
);
998 (void) unlink(mount_tmp
);
999 mount_tmp_created
= false;
1001 (void) umount(mount_slave
);
1002 mount_slave_mounted
= false;
1004 (void) rmdir(mount_slave
);
1005 mount_slave_created
= false;
1007 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0) {
1008 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
1012 r
= safe_fork("(sd-bindmnt)", FORK_RESET_SIGNALS
, &child
);
1014 sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
1018 const char *mount_inside
;
1022 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
1024 q
= procfs_file_alloca(m
->leader
, "ns/mnt");
1025 mntfd
= open(q
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1027 r
= log_error_errno(errno
, "Failed to open mount namespace of leader: %m");
1031 if (setns(mntfd
, CLONE_NEWNS
) < 0) {
1032 r
= log_error_errno(errno
, "Failed to join namespace of leader: %m");
1036 if (make_file_or_directory
) {
1037 if (S_ISDIR(st
.st_mode
))
1038 (void) mkdir_p(dest
, 0755);
1040 (void) mkdir_parents(dest
, 0755);
1041 safe_close(open(dest
, O_CREAT
|O_EXCL
|O_WRONLY
|O_CLOEXEC
|O_NOCTTY
, 0600));
1045 /* Fifth, move the mount to the right place inside */
1046 mount_inside
= strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside
));
1047 if (mount(mount_inside
, dest
, NULL
, MS_MOVE
, NULL
) < 0) {
1048 r
= log_error_errno(errno
, "Failed to mount: %m");
1052 _exit(EXIT_SUCCESS
);
1055 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
1056 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1058 _exit(EXIT_FAILURE
);
1061 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1063 r
= wait_for_terminate_and_check("(sd-bindmnt)", child
, 0);
1065 r
= sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
1068 if (r
!= EXIT_SUCCESS
) {
1069 if (read(errno_pipe_fd
[0], &r
, sizeof(r
)) == sizeof(r
))
1070 r
= sd_bus_error_set_errnof(error
, r
, "Failed to mount: %m");
1072 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child failed.");
1076 r
= sd_bus_reply_method_return(message
, NULL
);
1079 if (mount_outside_mounted
)
1080 (void) umount(mount_outside
);
1081 if (mount_outside_created
) {
1082 if (S_ISDIR(st
.st_mode
))
1083 (void) rmdir(mount_outside
);
1085 (void) unlink(mount_outside
);
1088 if (mount_tmp_mounted
)
1089 (void) umount(mount_tmp
);
1090 if (mount_tmp_created
) {
1091 if (S_ISDIR(st
.st_mode
))
1092 (void) rmdir(mount_tmp
);
1094 (void) unlink(mount_tmp
);
1097 if (mount_slave_mounted
)
1098 (void) umount(mount_slave
);
1099 if (mount_slave_created
)
1100 (void) rmdir(mount_slave
);
1105 int bus_machine_method_copy(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1106 const char *src
, *dest
, *host_path
, *container_path
, *host_basename
, *host_dirname
, *container_basename
, *container_dirname
;
1107 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
1108 CopyFlags copy_flags
= COPY_REFLINK
|COPY_MERGE
;
1109 _cleanup_close_
int hostfd
= -1;
1110 Machine
*m
= userdata
;
1120 if (m
->manager
->n_operations
>= OPERATIONS_MAX
)
1121 return sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing copies.");
1123 if (m
->class != MACHINE_CONTAINER
)
1124 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Copying files is only supported on container machines.");
1126 r
= sd_bus_message_read(message
, "ss", &src
, &dest
);
1130 if (!path_is_absolute(src
))
1131 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Source path must be absolute.");
1135 else if (!path_is_absolute(dest
))
1136 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Destination path must be absolute.");
1138 r
= bus_verify_polkit_async(
1141 "org.freedesktop.machine1.manage-machines",
1145 &m
->manager
->polkit_registry
,
1150 return 1; /* Will call us back */
1152 r
= machine_get_uid_shift(m
, &uid_shift
);
1156 copy_from
= strstr(sd_bus_message_get_member(message
), "CopyFrom");
1159 container_path
= src
;
1163 container_path
= dest
;
1166 host_basename
= basename(host_path
);
1167 t
= strdupa(host_path
);
1168 host_dirname
= dirname(t
);
1170 container_basename
= basename(container_path
);
1171 t
= strdupa(container_path
);
1172 container_dirname
= dirname(t
);
1174 hostfd
= open(host_dirname
, O_CLOEXEC
|O_RDONLY
|O_NOCTTY
|O_DIRECTORY
);
1176 return sd_bus_error_set_errnof(error
, errno
, "Failed to open host directory %s: %m", host_dirname
);
1178 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0)
1179 return sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
1181 r
= safe_fork("(sd-copy)", FORK_RESET_SIGNALS
, &child
);
1183 return sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
1189 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
1191 q
= procfs_file_alloca(m
->leader
, "ns/mnt");
1192 mntfd
= open(q
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1194 r
= log_error_errno(errno
, "Failed to open mount namespace of leader: %m");
1198 if (setns(mntfd
, CLONE_NEWNS
) < 0) {
1199 r
= log_error_errno(errno
, "Failed to join namespace of leader: %m");
1203 containerfd
= open(container_dirname
, O_CLOEXEC
|O_RDONLY
|O_NOCTTY
|O_DIRECTORY
);
1204 if (containerfd
< 0) {
1205 r
= log_error_errno(errno
, "Failed to open destination directory: %m");
1209 /* Run the actual copy operation. Note that when an UID shift is set we'll either clamp the UID/GID to
1210 * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
1211 * the UID/GIDs as they are. */
1213 r
= copy_tree_at(containerfd
, container_basename
, hostfd
, host_basename
, uid_shift
== 0 ? UID_INVALID
: 0, uid_shift
== 0 ? GID_INVALID
: 0, copy_flags
);
1215 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
);
1217 hostfd
= safe_close(hostfd
);
1218 containerfd
= safe_close(containerfd
);
1221 r
= log_error_errno(r
, "Failed to copy tree: %m");
1225 _exit(EXIT_SUCCESS
);
1228 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
1229 _exit(EXIT_FAILURE
);
1232 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1234 /* Copying might take a while, hence install a watch on the child, and return */
1236 r
= operation_new(m
->manager
, m
, child
, message
, errno_pipe_fd
[0], NULL
);
1238 (void) sigkill_wait(child
);
1241 errno_pipe_fd
[0] = -1;
1246 int bus_machine_method_open_root_directory(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1247 _cleanup_close_
int fd
= -1;
1248 Machine
*m
= userdata
;
1254 r
= bus_verify_polkit_async(
1257 "org.freedesktop.machine1.manage-machines",
1261 &m
->manager
->polkit_registry
,
1266 return 1; /* Will call us back */
1271 fd
= open("/", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
1277 case MACHINE_CONTAINER
: {
1278 _cleanup_close_
int mntns_fd
= -1, root_fd
= -1;
1279 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1282 r
= namespace_open(m
->leader
, NULL
, &mntns_fd
, NULL
, NULL
, &root_fd
);
1286 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1289 r
= safe_fork("(sd-openroot)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
, &child
);
1291 return sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
1293 _cleanup_close_
int dfd
= -1;
1295 pair
[0] = safe_close(pair
[0]);
1297 r
= namespace_enter(-1, mntns_fd
, -1, -1, root_fd
);
1299 _exit(EXIT_FAILURE
);
1301 dfd
= open("/", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
1303 _exit(EXIT_FAILURE
);
1305 r
= send_one_fd(pair
[1], dfd
, 0);
1306 dfd
= safe_close(dfd
);
1308 _exit(EXIT_FAILURE
);
1310 _exit(EXIT_SUCCESS
);
1313 pair
[1] = safe_close(pair
[1]);
1315 r
= wait_for_terminate_and_check("(sd-openroot)", child
, 0);
1317 return sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
1318 if (r
!= EXIT_SUCCESS
)
1319 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child died abnormally.");
1321 fd
= receive_one_fd(pair
[0], MSG_DONTWAIT
);
1329 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Opening the root directory is only supported on container machines.");
1332 return sd_bus_reply_method_return(message
, "h", fd
);
1335 int bus_machine_method_get_uid_shift(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1336 Machine
*m
= userdata
;
1343 /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but
1344 * we kinda have to for this. */
1346 if (m
->class == MACHINE_HOST
)
1347 return sd_bus_reply_method_return(message
, "u", UINT32_C(0));
1349 if (m
->class != MACHINE_CONTAINER
)
1350 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "UID/GID shift may only be determined for container machines.");
1352 r
= machine_get_uid_shift(m
, &shift
);
1354 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m
->name
);
1358 return sd_bus_reply_method_return(message
, "u", (uint32_t) shift
);
1361 const sd_bus_vtable machine_vtable
[] = {
1362 SD_BUS_VTABLE_START(0),
1363 SD_BUS_PROPERTY("Name", "s", NULL
, offsetof(Machine
, name
), SD_BUS_VTABLE_PROPERTY_CONST
),
1364 SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128
, offsetof(Machine
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
1365 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine
, timestamp
), SD_BUS_VTABLE_PROPERTY_CONST
),
1366 SD_BUS_PROPERTY("Service", "s", NULL
, offsetof(Machine
, service
), SD_BUS_VTABLE_PROPERTY_CONST
),
1367 SD_BUS_PROPERTY("Unit", "s", NULL
, offsetof(Machine
, unit
), SD_BUS_VTABLE_PROPERTY_CONST
),
1368 SD_BUS_PROPERTY("Scope", "s", NULL
, offsetof(Machine
, unit
), SD_BUS_VTABLE_PROPERTY_CONST
|SD_BUS_VTABLE_HIDDEN
),
1369 SD_BUS_PROPERTY("Leader", "u", NULL
, offsetof(Machine
, leader
), SD_BUS_VTABLE_PROPERTY_CONST
),
1370 SD_BUS_PROPERTY("Class", "s", property_get_class
, offsetof(Machine
, class), SD_BUS_VTABLE_PROPERTY_CONST
),
1371 SD_BUS_PROPERTY("RootDirectory", "s", NULL
, offsetof(Machine
, root_directory
), SD_BUS_VTABLE_PROPERTY_CONST
),
1372 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
1373 SD_BUS_PROPERTY("State", "s", property_get_state
, 0, 0),
1374 SD_BUS_METHOD("Terminate", NULL
, NULL
, bus_machine_method_terminate
, SD_BUS_VTABLE_UNPRIVILEGED
),
1375 SD_BUS_METHOD("Kill", "si", NULL
, bus_machine_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
1376 SD_BUS_METHOD("GetAddresses", NULL
, "a(iay)", bus_machine_method_get_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1377 SD_BUS_METHOD("GetOSRelease", NULL
, "a{ss}", bus_machine_method_get_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1378 SD_BUS_METHOD("GetUIDShift", NULL
, "u", bus_machine_method_get_uid_shift
, SD_BUS_VTABLE_UNPRIVILEGED
),
1379 SD_BUS_METHOD("OpenPTY", NULL
, "hs", bus_machine_method_open_pty
, SD_BUS_VTABLE_UNPRIVILEGED
),
1380 SD_BUS_METHOD("OpenLogin", NULL
, "hs", bus_machine_method_open_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1381 SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1382 SD_BUS_METHOD("BindMount", "ssbb", NULL
, bus_machine_method_bind_mount
, SD_BUS_VTABLE_UNPRIVILEGED
),
1383 SD_BUS_METHOD("CopyFrom", "ss", NULL
, bus_machine_method_copy
, SD_BUS_VTABLE_UNPRIVILEGED
),
1384 SD_BUS_METHOD("CopyTo", "ss", NULL
, bus_machine_method_copy
, SD_BUS_VTABLE_UNPRIVILEGED
),
1385 SD_BUS_METHOD("OpenRootDirectory", NULL
, "h", bus_machine_method_open_root_directory
, SD_BUS_VTABLE_UNPRIVILEGED
),
1389 int machine_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
1390 Manager
*m
= userdata
;
1400 if (streq(path
, "/org/freedesktop/machine1/machine/self")) {
1401 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
1402 sd_bus_message
*message
;
1405 message
= sd_bus_get_current_message(bus
);
1409 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
1413 r
= sd_bus_creds_get_pid(creds
, &pid
);
1417 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
1421 _cleanup_free_
char *e
= NULL
;
1424 p
= startswith(path
, "/org/freedesktop/machine1/machine/");
1428 e
= bus_label_unescape(p
);
1432 machine
= hashmap_get(m
->machines
, e
);
1441 char *machine_bus_path(Machine
*m
) {
1442 _cleanup_free_
char *e
= NULL
;
1446 e
= bus_label_escape(m
->name
);
1450 return strappend("/org/freedesktop/machine1/machine/", e
);
1453 int machine_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
1454 _cleanup_strv_free_
char **l
= NULL
;
1455 Machine
*machine
= NULL
;
1456 Manager
*m
= userdata
;
1464 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1467 p
= machine_bus_path(machine
);
1471 r
= strv_consume(&l
, p
);
1476 *nodes
= TAKE_PTR(l
);
1481 int machine_send_signal(Machine
*m
, bool new_machine
) {
1482 _cleanup_free_
char *p
= NULL
;
1486 p
= machine_bus_path(m
);
1490 return sd_bus_emit_signal(
1492 "/org/freedesktop/machine1",
1493 "org.freedesktop.machine1.Manager",
1494 new_machine
? "MachineNew" : "MachineRemoved",
1498 int machine_send_create_reply(Machine
*m
, sd_bus_error
*error
) {
1499 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*c
= NULL
;
1500 _cleanup_free_
char *p
= NULL
;
1504 if (!m
->create_message
)
1507 c
= TAKE_PTR(m
->create_message
);
1510 return sd_bus_reply_method_error(c
, error
);
1512 /* Update the machine state file before we notify the client
1513 * about the result. */
1516 p
= machine_bus_path(m
);
1520 return sd_bus_reply_method_return(c
, "o", p
);