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
);
537 int bus_machine_method_open_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
538 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
539 _cleanup_free_
char *pty_name
= NULL
;
540 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*allocated_bus
= NULL
;
541 _cleanup_close_
int master
= -1;
542 sd_bus
*container_bus
= NULL
;
543 Machine
*m
= userdata
;
544 const char *p
, *getty
;
550 r
= bus_verify_polkit_async(
553 m
->class == MACHINE_HOST
? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
557 &m
->manager
->polkit_registry
,
562 return 1; /* Will call us back */
564 master
= machine_openpt(m
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
568 r
= ptsname_namespace(master
, &pty_name
);
572 p
= path_startswith(pty_name
, "/dev/pts/");
574 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "PTS name %s is invalid", pty_name
);
576 r
= container_bus_new(m
, error
, &allocated_bus
);
580 container_bus
= allocated_bus
?: m
->manager
->bus
;
582 getty
= strjoina("container-getty@", p
, ".service");
584 r
= sd_bus_call_method(
586 "org.freedesktop.systemd1",
587 "/org/freedesktop/systemd1",
588 "org.freedesktop.systemd1.Manager",
591 "ss", getty
, "replace");
595 r
= sd_bus_message_new_method_return(message
, &reply
);
599 r
= sd_bus_message_append(reply
, "hs", master
, pty_name
);
603 return sd_bus_send(NULL
, reply
, NULL
);
606 int bus_machine_method_open_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
607 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
, *tm
= NULL
;
608 _cleanup_free_
char *pty_name
= NULL
;
609 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*allocated_bus
= NULL
;
610 sd_bus
*container_bus
= NULL
;
611 _cleanup_close_
int master
= -1, slave
= -1;
612 _cleanup_strv_free_
char **env
= NULL
, **args_wire
= NULL
, **args
= NULL
;
613 Machine
*m
= userdata
;
614 const char *p
, *unit
, *user
, *path
, *description
, *utmp_id
;
620 r
= sd_bus_message_read(message
, "ss", &user
, &path
);
623 user
= empty_to_null(user
);
624 r
= sd_bus_message_read_strv(message
, &args_wire
);
630 args
= new0(char*, 3 + 1);
633 args
[0] = strdup("sh");
636 args
[1] = strdup("-c");
639 r
= asprintf(&args
[2],
640 "shell=$(getent passwd %s 2>/dev/null | { IFS=: read _ _ _ _ _ _ x; echo \"$x\"; })\n"\
641 "exec \"${shell:-/bin/sh}\" -l", /* -l is means --login */
642 isempty(user
) ? "root" : user
);
648 if (!path_is_absolute(path
))
649 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Specified path '%s' is not absolute", path
);
652 if (strv_isempty(args
)) {
653 args
= strv_free(args
);
655 args
= strv_new(path
, NULL
);
661 r
= sd_bus_message_read_strv(message
, &env
);
664 if (!strv_env_is_valid(env
))
665 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid environment assignments");
667 r
= bus_verify_polkit_async(
670 m
->class == MACHINE_HOST
? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
674 &m
->manager
->polkit_registry
,
679 return 1; /* Will call us back */
681 master
= machine_openpt(m
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
685 r
= ptsname_namespace(master
, &pty_name
);
689 p
= path_startswith(pty_name
, "/dev/pts/");
692 slave
= machine_open_terminal(m
, pty_name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
696 utmp_id
= path_startswith(pty_name
, "/dev/");
699 r
= container_bus_new(m
, error
, &allocated_bus
);
703 container_bus
= allocated_bus
?: m
->manager
->bus
;
705 r
= sd_bus_message_new_method_call(
708 "org.freedesktop.systemd1",
709 "/org/freedesktop/systemd1",
710 "org.freedesktop.systemd1.Manager",
711 "StartTransientUnit");
716 unit
= strjoina("container-shell@", p
, ".service");
717 r
= sd_bus_message_append(tm
, "ss", unit
, "fail");
722 r
= sd_bus_message_open_container(tm
, 'a', "(sv)");
726 description
= strjoina("Shell for User ", isempty(user
) ? "root" : user
);
727 r
= sd_bus_message_append(tm
,
728 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
729 "Description", "s", description
,
730 "StandardInputFileDescriptor", "h", slave
,
731 "StandardOutputFileDescriptor", "h", slave
,
732 "StandardErrorFileDescriptor", "h", slave
,
733 "SendSIGHUP", "b", true,
734 "IgnoreSIGPIPE", "b", false,
735 "KillMode", "s", "mixed",
736 "TTYReset", "b", true,
737 "UtmpIdentifier", "s", utmp_id
,
738 "UtmpMode", "s", "user",
739 "PAMName", "s", "login",
740 "WorkingDirectory", "s", "-~");
744 r
= sd_bus_message_append(tm
, "(sv)", "User", "s", isempty(user
) ? "root" : user
);
748 if (!strv_isempty(env
)) {
749 r
= sd_bus_message_open_container(tm
, 'r', "sv");
753 r
= sd_bus_message_append(tm
, "s", "Environment");
757 r
= sd_bus_message_open_container(tm
, 'v', "as");
761 r
= sd_bus_message_append_strv(tm
, env
);
765 r
= sd_bus_message_close_container(tm
);
769 r
= sd_bus_message_close_container(tm
);
775 r
= sd_bus_message_open_container(tm
, 'r', "sv");
779 r
= sd_bus_message_append(tm
, "s", "ExecStart");
783 r
= sd_bus_message_open_container(tm
, 'v', "a(sasb)");
787 r
= sd_bus_message_open_container(tm
, 'a', "(sasb)");
791 r
= sd_bus_message_open_container(tm
, 'r', "sasb");
795 r
= sd_bus_message_append(tm
, "s", path
);
799 r
= sd_bus_message_append_strv(tm
, args
);
803 r
= sd_bus_message_append(tm
, "b", true);
807 r
= sd_bus_message_close_container(tm
);
811 r
= sd_bus_message_close_container(tm
);
815 r
= sd_bus_message_close_container(tm
);
819 r
= sd_bus_message_close_container(tm
);
823 r
= sd_bus_message_close_container(tm
);
827 /* Auxiliary units */
828 r
= sd_bus_message_append(tm
, "a(sa(sv))", 0);
832 r
= sd_bus_call(container_bus
, tm
, 0, error
, NULL
);
836 slave
= safe_close(slave
);
838 r
= sd_bus_message_new_method_return(message
, &reply
);
842 r
= sd_bus_message_append(reply
, "hs", master
, pty_name
);
846 return sd_bus_send(NULL
, reply
, NULL
);
849 int bus_machine_method_bind_mount(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
850 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
851 char mount_slave
[] = "/tmp/propagate.XXXXXX", *mount_tmp
, *mount_outside
, *p
;
852 bool mount_slave_created
= false, mount_slave_mounted
= false,
853 mount_tmp_created
= false, mount_tmp_mounted
= false,
854 mount_outside_created
= false, mount_outside_mounted
= false;
855 _cleanup_free_
char *chased_src
= NULL
;
856 int read_only
, make_file_or_directory
;
857 const char *dest
, *src
;
858 Machine
*m
= userdata
;
867 if (m
->class != MACHINE_CONTAINER
)
868 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Bind mounting is only supported on container machines.");
870 r
= sd_bus_message_read(message
, "ssbb", &src
, &dest
, &read_only
, &make_file_or_directory
);
874 if (!path_is_absolute(src
) || !path_is_normalized(src
))
875 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Source path must be absolute and not contain ../.");
879 else if (!path_is_absolute(dest
) || !path_is_normalized(dest
))
880 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Destination path must be absolute and not contain ../.");
882 r
= bus_verify_polkit_async(
885 "org.freedesktop.machine1.manage-machines",
889 &m
->manager
->polkit_registry
,
894 return 1; /* Will call us back */
896 r
= machine_get_uid_shift(m
, &uid
);
900 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Can't bind mount on container with user namespacing applied.");
902 /* One day, when bind mounting /proc/self/fd/n works across
903 * namespace boundaries we should rework this logic to make
906 p
= strjoina("/run/systemd/nspawn/propagate/", m
->name
, "/");
907 if (laccess(p
, F_OK
) < 0)
908 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Container does not allow propagation of mount points.");
910 r
= chase_symlinks(src
, NULL
, 0, &chased_src
);
912 return sd_bus_error_set_errnof(error
, r
, "Failed to resolve source path: %m");
914 if (lstat(chased_src
, &st
) < 0)
915 return sd_bus_error_set_errnof(error
, errno
, "Failed to stat() source path: %m");
916 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… */
917 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Source directory can't be a symbolic link");
919 /* Our goal is to install a new bind mount into the container,
920 possibly read-only. This is irritatingly complex
921 unfortunately, currently.
923 First, we start by creating a private playground in /tmp,
924 that we can mount MS_SLAVE. (Which is necessary, since
925 MS_MOVE cannot be applied to mounts with MS_SHARED parent
928 if (!mkdtemp(mount_slave
))
929 return sd_bus_error_set_errnof(error
, errno
, "Failed to create playground %s: %m", mount_slave
);
931 mount_slave_created
= true;
933 if (mount(mount_slave
, mount_slave
, NULL
, MS_BIND
, NULL
) < 0) {
934 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to make bind mount %s: %m", mount_slave
);
938 mount_slave_mounted
= true;
940 if (mount(NULL
, mount_slave
, NULL
, MS_SLAVE
, NULL
) < 0) {
941 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to remount slave %s: %m", mount_slave
);
945 /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */
946 mount_tmp
= strjoina(mount_slave
, "/mount");
947 if (S_ISDIR(st
.st_mode
))
948 r
= mkdir_errno_wrapper(mount_tmp
, 0700);
950 r
= touch(mount_tmp
);
952 sd_bus_error_set_errnof(error
, errno
, "Failed to create temporary mount point %s: %m", mount_tmp
);
956 mount_tmp_created
= true;
958 if (mount(chased_src
, mount_tmp
, NULL
, MS_BIND
, NULL
) < 0) {
959 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to mount %s: %m", chased_src
);
963 mount_tmp_mounted
= true;
965 /* Third, we remount the new bind mount read-only if requested. */
967 if (mount(NULL
, mount_tmp
, NULL
, MS_BIND
|MS_REMOUNT
|MS_RDONLY
, NULL
) < 0) {
968 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to remount read-only %s: %m", mount_tmp
);
972 /* Fourth, we move the new bind mount into the propagation directory. This way it will appear there read-only
975 mount_outside
= strjoina("/run/systemd/nspawn/propagate/", m
->name
, "/XXXXXX");
976 if (S_ISDIR(st
.st_mode
))
977 r
= mkdtemp(mount_outside
) ? 0 : -errno
;
979 r
= mkostemp_safe(mount_outside
);
983 sd_bus_error_set_errnof(error
, errno
, "Cannot create propagation file or directory %s: %m", mount_outside
);
987 mount_outside_created
= true;
989 if (mount(mount_tmp
, mount_outside
, NULL
, MS_MOVE
, NULL
) < 0) {
990 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to move %s to %s: %m", mount_tmp
, mount_outside
);
994 mount_outside_mounted
= true;
995 mount_tmp_mounted
= false;
997 if (S_ISDIR(st
.st_mode
))
998 (void) rmdir(mount_tmp
);
1000 (void) unlink(mount_tmp
);
1001 mount_tmp_created
= false;
1003 (void) umount(mount_slave
);
1004 mount_slave_mounted
= false;
1006 (void) rmdir(mount_slave
);
1007 mount_slave_created
= false;
1009 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0) {
1010 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
1014 r
= safe_fork("(sd-bindmnt)", FORK_RESET_SIGNALS
, &child
);
1016 sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
1020 const char *mount_inside
;
1024 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
1026 q
= procfs_file_alloca(m
->leader
, "ns/mnt");
1027 mntfd
= open(q
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1029 r
= log_error_errno(errno
, "Failed to open mount namespace of leader: %m");
1033 if (setns(mntfd
, CLONE_NEWNS
) < 0) {
1034 r
= log_error_errno(errno
, "Failed to join namespace of leader: %m");
1038 if (make_file_or_directory
) {
1039 if (S_ISDIR(st
.st_mode
))
1040 (void) mkdir_p(dest
, 0755);
1042 (void) mkdir_parents(dest
, 0755);
1043 safe_close(open(dest
, O_CREAT
|O_EXCL
|O_WRONLY
|O_CLOEXEC
|O_NOCTTY
, 0600));
1047 /* Fifth, move the mount to the right place inside */
1048 mount_inside
= strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside
));
1049 if (mount(mount_inside
, dest
, NULL
, MS_MOVE
, NULL
) < 0) {
1050 r
= log_error_errno(errno
, "Failed to mount: %m");
1054 _exit(EXIT_SUCCESS
);
1057 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
1058 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1060 _exit(EXIT_FAILURE
);
1063 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1065 r
= wait_for_terminate_and_check("(sd-bindmnt)", child
, 0);
1067 r
= sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
1070 if (r
!= EXIT_SUCCESS
) {
1071 if (read(errno_pipe_fd
[0], &r
, sizeof(r
)) == sizeof(r
))
1072 r
= sd_bus_error_set_errnof(error
, r
, "Failed to mount: %m");
1074 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child failed.");
1078 r
= sd_bus_reply_method_return(message
, NULL
);
1081 if (mount_outside_mounted
)
1082 (void) umount(mount_outside
);
1083 if (mount_outside_created
) {
1084 if (S_ISDIR(st
.st_mode
))
1085 (void) rmdir(mount_outside
);
1087 (void) unlink(mount_outside
);
1090 if (mount_tmp_mounted
)
1091 (void) umount(mount_tmp
);
1092 if (mount_tmp_created
) {
1093 if (S_ISDIR(st
.st_mode
))
1094 (void) rmdir(mount_tmp
);
1096 (void) unlink(mount_tmp
);
1099 if (mount_slave_mounted
)
1100 (void) umount(mount_slave
);
1101 if (mount_slave_created
)
1102 (void) rmdir(mount_slave
);
1107 int bus_machine_method_copy(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1108 const char *src
, *dest
, *host_path
, *container_path
, *host_basename
, *host_dirname
, *container_basename
, *container_dirname
;
1109 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
1110 CopyFlags copy_flags
= COPY_REFLINK
|COPY_MERGE
;
1111 _cleanup_close_
int hostfd
= -1;
1112 Machine
*m
= userdata
;
1122 if (m
->manager
->n_operations
>= OPERATIONS_MAX
)
1123 return sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing copies.");
1125 if (m
->class != MACHINE_CONTAINER
)
1126 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Copying files is only supported on container machines.");
1128 r
= sd_bus_message_read(message
, "ss", &src
, &dest
);
1132 if (!path_is_absolute(src
))
1133 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Source path must be absolute.");
1137 else if (!path_is_absolute(dest
))
1138 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Destination path must be absolute.");
1140 r
= bus_verify_polkit_async(
1143 "org.freedesktop.machine1.manage-machines",
1147 &m
->manager
->polkit_registry
,
1152 return 1; /* Will call us back */
1154 r
= machine_get_uid_shift(m
, &uid_shift
);
1158 copy_from
= strstr(sd_bus_message_get_member(message
), "CopyFrom");
1161 container_path
= src
;
1165 container_path
= dest
;
1168 host_basename
= basename(host_path
);
1169 t
= strdupa(host_path
);
1170 host_dirname
= dirname(t
);
1172 container_basename
= basename(container_path
);
1173 t
= strdupa(container_path
);
1174 container_dirname
= dirname(t
);
1176 hostfd
= open(host_dirname
, O_CLOEXEC
|O_RDONLY
|O_NOCTTY
|O_DIRECTORY
);
1178 return sd_bus_error_set_errnof(error
, errno
, "Failed to open host directory %s: %m", host_dirname
);
1180 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0)
1181 return sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
1183 r
= safe_fork("(sd-copy)", FORK_RESET_SIGNALS
, &child
);
1185 return sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
1191 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
1193 q
= procfs_file_alloca(m
->leader
, "ns/mnt");
1194 mntfd
= open(q
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1196 r
= log_error_errno(errno
, "Failed to open mount namespace of leader: %m");
1200 if (setns(mntfd
, CLONE_NEWNS
) < 0) {
1201 r
= log_error_errno(errno
, "Failed to join namespace of leader: %m");
1205 containerfd
= open(container_dirname
, O_CLOEXEC
|O_RDONLY
|O_NOCTTY
|O_DIRECTORY
);
1206 if (containerfd
< 0) {
1207 r
= log_error_errno(errno
, "Failed to open destination directory: %m");
1211 /* Run the actual copy operation. Note that when an UID shift is set we'll either clamp the UID/GID to
1212 * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
1213 * the UID/GIDs as they are. */
1215 r
= copy_tree_at(containerfd
, container_basename
, hostfd
, host_basename
, uid_shift
== 0 ? UID_INVALID
: 0, uid_shift
== 0 ? GID_INVALID
: 0, copy_flags
);
1217 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
);
1219 hostfd
= safe_close(hostfd
);
1220 containerfd
= safe_close(containerfd
);
1223 r
= log_error_errno(r
, "Failed to copy tree: %m");
1227 _exit(EXIT_SUCCESS
);
1230 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
1231 _exit(EXIT_FAILURE
);
1234 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1236 /* Copying might take a while, hence install a watch on the child, and return */
1238 r
= operation_new(m
->manager
, m
, child
, message
, errno_pipe_fd
[0], NULL
);
1240 (void) sigkill_wait(child
);
1243 errno_pipe_fd
[0] = -1;
1248 int bus_machine_method_open_root_directory(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1249 _cleanup_close_
int fd
= -1;
1250 Machine
*m
= userdata
;
1256 r
= bus_verify_polkit_async(
1259 "org.freedesktop.machine1.manage-machines",
1263 &m
->manager
->polkit_registry
,
1268 return 1; /* Will call us back */
1273 fd
= open("/", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
1279 case MACHINE_CONTAINER
: {
1280 _cleanup_close_
int mntns_fd
= -1, root_fd
= -1;
1281 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1284 r
= namespace_open(m
->leader
, NULL
, &mntns_fd
, NULL
, NULL
, &root_fd
);
1288 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1291 r
= safe_fork("(sd-openroot)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
, &child
);
1293 return sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
1295 _cleanup_close_
int dfd
= -1;
1297 pair
[0] = safe_close(pair
[0]);
1299 r
= namespace_enter(-1, mntns_fd
, -1, -1, root_fd
);
1301 _exit(EXIT_FAILURE
);
1303 dfd
= open("/", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
1305 _exit(EXIT_FAILURE
);
1307 r
= send_one_fd(pair
[1], dfd
, 0);
1308 dfd
= safe_close(dfd
);
1310 _exit(EXIT_FAILURE
);
1312 _exit(EXIT_SUCCESS
);
1315 pair
[1] = safe_close(pair
[1]);
1317 r
= wait_for_terminate_and_check("(sd-openroot)", child
, 0);
1319 return sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
1320 if (r
!= EXIT_SUCCESS
)
1321 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child died abnormally.");
1323 fd
= receive_one_fd(pair
[0], MSG_DONTWAIT
);
1331 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Opening the root directory is only supported on container machines.");
1334 return sd_bus_reply_method_return(message
, "h", fd
);
1337 int bus_machine_method_get_uid_shift(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1338 Machine
*m
= userdata
;
1345 /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but
1346 * we kinda have to for this. */
1348 if (m
->class == MACHINE_HOST
)
1349 return sd_bus_reply_method_return(message
, "u", UINT32_C(0));
1351 if (m
->class != MACHINE_CONTAINER
)
1352 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "UID/GID shift may only be determined for container machines.");
1354 r
= machine_get_uid_shift(m
, &shift
);
1356 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m
->name
);
1360 return sd_bus_reply_method_return(message
, "u", (uint32_t) shift
);
1363 const sd_bus_vtable machine_vtable
[] = {
1364 SD_BUS_VTABLE_START(0),
1365 SD_BUS_PROPERTY("Name", "s", NULL
, offsetof(Machine
, name
), SD_BUS_VTABLE_PROPERTY_CONST
),
1366 SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128
, offsetof(Machine
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
1367 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine
, timestamp
), SD_BUS_VTABLE_PROPERTY_CONST
),
1368 SD_BUS_PROPERTY("Service", "s", NULL
, offsetof(Machine
, service
), SD_BUS_VTABLE_PROPERTY_CONST
),
1369 SD_BUS_PROPERTY("Unit", "s", NULL
, offsetof(Machine
, unit
), SD_BUS_VTABLE_PROPERTY_CONST
),
1370 SD_BUS_PROPERTY("Scope", "s", NULL
, offsetof(Machine
, unit
), SD_BUS_VTABLE_PROPERTY_CONST
|SD_BUS_VTABLE_HIDDEN
),
1371 SD_BUS_PROPERTY("Leader", "u", NULL
, offsetof(Machine
, leader
), SD_BUS_VTABLE_PROPERTY_CONST
),
1372 SD_BUS_PROPERTY("Class", "s", property_get_class
, offsetof(Machine
, class), SD_BUS_VTABLE_PROPERTY_CONST
),
1373 SD_BUS_PROPERTY("RootDirectory", "s", NULL
, offsetof(Machine
, root_directory
), SD_BUS_VTABLE_PROPERTY_CONST
),
1374 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
1375 SD_BUS_PROPERTY("State", "s", property_get_state
, 0, 0),
1376 SD_BUS_METHOD("Terminate", NULL
, NULL
, bus_machine_method_terminate
, SD_BUS_VTABLE_UNPRIVILEGED
),
1377 SD_BUS_METHOD("Kill", "si", NULL
, bus_machine_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
1378 SD_BUS_METHOD("GetAddresses", NULL
, "a(iay)", bus_machine_method_get_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1379 SD_BUS_METHOD("GetOSRelease", NULL
, "a{ss}", bus_machine_method_get_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1380 SD_BUS_METHOD("GetUIDShift", NULL
, "u", bus_machine_method_get_uid_shift
, SD_BUS_VTABLE_UNPRIVILEGED
),
1381 SD_BUS_METHOD("OpenPTY", NULL
, "hs", bus_machine_method_open_pty
, SD_BUS_VTABLE_UNPRIVILEGED
),
1382 SD_BUS_METHOD("OpenLogin", NULL
, "hs", bus_machine_method_open_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1383 SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1384 SD_BUS_METHOD("BindMount", "ssbb", NULL
, bus_machine_method_bind_mount
, SD_BUS_VTABLE_UNPRIVILEGED
),
1385 SD_BUS_METHOD("CopyFrom", "ss", NULL
, bus_machine_method_copy
, SD_BUS_VTABLE_UNPRIVILEGED
),
1386 SD_BUS_METHOD("CopyTo", "ss", NULL
, bus_machine_method_copy
, SD_BUS_VTABLE_UNPRIVILEGED
),
1387 SD_BUS_METHOD("OpenRootDirectory", NULL
, "h", bus_machine_method_open_root_directory
, SD_BUS_VTABLE_UNPRIVILEGED
),
1391 int machine_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
1392 Manager
*m
= userdata
;
1402 if (streq(path
, "/org/freedesktop/machine1/machine/self")) {
1403 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
1404 sd_bus_message
*message
;
1407 message
= sd_bus_get_current_message(bus
);
1411 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
1415 r
= sd_bus_creds_get_pid(creds
, &pid
);
1419 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
1423 _cleanup_free_
char *e
= NULL
;
1426 p
= startswith(path
, "/org/freedesktop/machine1/machine/");
1430 e
= bus_label_unescape(p
);
1434 machine
= hashmap_get(m
->machines
, e
);
1443 char *machine_bus_path(Machine
*m
) {
1444 _cleanup_free_
char *e
= NULL
;
1448 e
= bus_label_escape(m
->name
);
1452 return strappend("/org/freedesktop/machine1/machine/", e
);
1455 int machine_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
1456 _cleanup_strv_free_
char **l
= NULL
;
1457 Machine
*machine
= NULL
;
1458 Manager
*m
= userdata
;
1466 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1469 p
= machine_bus_path(machine
);
1473 r
= strv_consume(&l
, p
);
1478 *nodes
= TAKE_PTR(l
);
1483 int machine_send_signal(Machine
*m
, bool new_machine
) {
1484 _cleanup_free_
char *p
= NULL
;
1488 p
= machine_bus_path(m
);
1492 return sd_bus_emit_signal(
1494 "/org/freedesktop/machine1",
1495 "org.freedesktop.machine1.Manager",
1496 new_machine
? "MachineNew" : "MachineRemoved",
1500 int machine_send_create_reply(Machine
*m
, sd_bus_error
*error
) {
1501 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*c
= NULL
;
1502 _cleanup_free_
char *p
= NULL
;
1506 if (!m
->create_message
)
1509 c
= m
->create_message
;
1510 m
->create_message
= NULL
;
1513 return sd_bus_reply_method_error(c
, error
);
1515 /* Update the machine state file before we notify the client
1516 * about the result. */
1519 p
= machine_bus_path(m
);
1523 return sd_bus_reply_method_return(c
, "o", p
);