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
= 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
);
626 if (!path_is_absolute(path
))
627 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Specified path '%s' is not absolute", path
);
629 r
= sd_bus_message_read_strv(message
, &args
);
632 if (strv_isempty(args
)) {
633 args
= strv_free(args
);
635 args
= strv_new(path
, NULL
);
639 args
[0][0] = '-'; /* Tell /bin/sh that this shall be a login shell */
642 r
= sd_bus_message_read_strv(message
, &env
);
645 if (!strv_env_is_valid(env
))
646 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid environment assignments");
648 r
= bus_verify_polkit_async(
651 m
->class == MACHINE_HOST
? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
655 &m
->manager
->polkit_registry
,
660 return 1; /* Will call us back */
662 master
= machine_openpt(m
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
666 r
= ptsname_namespace(master
, &pty_name
);
670 p
= path_startswith(pty_name
, "/dev/pts/");
673 slave
= machine_open_terminal(m
, pty_name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
677 utmp_id
= path_startswith(pty_name
, "/dev/");
680 r
= container_bus_new(m
, error
, &allocated_bus
);
684 container_bus
= allocated_bus
?: m
->manager
->bus
;
686 r
= sd_bus_message_new_method_call(
689 "org.freedesktop.systemd1",
690 "/org/freedesktop/systemd1",
691 "org.freedesktop.systemd1.Manager",
692 "StartTransientUnit");
697 unit
= strjoina("container-shell@", p
, ".service");
698 r
= sd_bus_message_append(tm
, "ss", unit
, "fail");
703 r
= sd_bus_message_open_container(tm
, 'a', "(sv)");
707 description
= strjoina("Shell for User ", isempty(user
) ? "root" : user
);
708 r
= sd_bus_message_append(tm
,
709 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
710 "Description", "s", description
,
711 "StandardInputFileDescriptor", "h", slave
,
712 "StandardOutputFileDescriptor", "h", slave
,
713 "StandardErrorFileDescriptor", "h", slave
,
714 "SendSIGHUP", "b", true,
715 "IgnoreSIGPIPE", "b", false,
716 "KillMode", "s", "mixed",
717 "TTYReset", "b", true,
718 "UtmpIdentifier", "s", utmp_id
,
719 "UtmpMode", "s", "user",
720 "PAMName", "s", "login",
721 "WorkingDirectory", "s", "-~");
725 r
= sd_bus_message_append(tm
, "(sv)", "User", "s", isempty(user
) ? "root" : user
);
729 if (!strv_isempty(env
)) {
730 r
= sd_bus_message_open_container(tm
, 'r', "sv");
734 r
= sd_bus_message_append(tm
, "s", "Environment");
738 r
= sd_bus_message_open_container(tm
, 'v', "as");
742 r
= sd_bus_message_append_strv(tm
, env
);
746 r
= sd_bus_message_close_container(tm
);
750 r
= sd_bus_message_close_container(tm
);
756 r
= sd_bus_message_open_container(tm
, 'r', "sv");
760 r
= sd_bus_message_append(tm
, "s", "ExecStart");
764 r
= sd_bus_message_open_container(tm
, 'v', "a(sasb)");
768 r
= sd_bus_message_open_container(tm
, 'a', "(sasb)");
772 r
= sd_bus_message_open_container(tm
, 'r', "sasb");
776 r
= sd_bus_message_append(tm
, "s", path
);
780 r
= sd_bus_message_append_strv(tm
, args
);
784 r
= sd_bus_message_append(tm
, "b", true);
788 r
= sd_bus_message_close_container(tm
);
792 r
= sd_bus_message_close_container(tm
);
796 r
= sd_bus_message_close_container(tm
);
800 r
= sd_bus_message_close_container(tm
);
804 r
= sd_bus_message_close_container(tm
);
808 /* Auxiliary units */
809 r
= sd_bus_message_append(tm
, "a(sa(sv))", 0);
813 r
= sd_bus_call(container_bus
, tm
, 0, error
, NULL
);
817 slave
= safe_close(slave
);
819 r
= sd_bus_message_new_method_return(message
, &reply
);
823 r
= sd_bus_message_append(reply
, "hs", master
, pty_name
);
827 return sd_bus_send(NULL
, reply
, NULL
);
830 int bus_machine_method_bind_mount(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
831 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
832 char mount_slave
[] = "/tmp/propagate.XXXXXX", *mount_tmp
, *mount_outside
, *p
;
833 bool mount_slave_created
= false, mount_slave_mounted
= false,
834 mount_tmp_created
= false, mount_tmp_mounted
= false,
835 mount_outside_created
= false, mount_outside_mounted
= false;
836 _cleanup_free_
char *chased_src
= NULL
;
837 int read_only
, make_file_or_directory
;
838 const char *dest
, *src
;
839 Machine
*m
= userdata
;
848 if (m
->class != MACHINE_CONTAINER
)
849 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Bind mounting is only supported on container machines.");
851 r
= sd_bus_message_read(message
, "ssbb", &src
, &dest
, &read_only
, &make_file_or_directory
);
855 if (!path_is_absolute(src
) || !path_is_normalized(src
))
856 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Source path must be absolute and not contain ../.");
860 else if (!path_is_absolute(dest
) || !path_is_normalized(dest
))
861 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Destination path must be absolute and not contain ../.");
863 r
= bus_verify_polkit_async(
866 "org.freedesktop.machine1.manage-machines",
870 &m
->manager
->polkit_registry
,
875 return 1; /* Will call us back */
877 r
= machine_get_uid_shift(m
, &uid
);
881 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Can't bind mount on container with user namespacing applied.");
883 /* One day, when bind mounting /proc/self/fd/n works across
884 * namespace boundaries we should rework this logic to make
887 p
= strjoina("/run/systemd/nspawn/propagate/", m
->name
, "/");
888 if (laccess(p
, F_OK
) < 0)
889 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Container does not allow propagation of mount points.");
891 r
= chase_symlinks(src
, NULL
, 0, &chased_src
);
893 return sd_bus_error_set_errnof(error
, r
, "Failed to resolve source path: %m");
895 if (lstat(chased_src
, &st
) < 0)
896 return sd_bus_error_set_errnof(error
, errno
, "Failed to stat() source path: %m");
897 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… */
898 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Source directory can't be a symbolic link");
900 /* Our goal is to install a new bind mount into the container,
901 possibly read-only. This is irritatingly complex
902 unfortunately, currently.
904 First, we start by creating a private playground in /tmp,
905 that we can mount MS_SLAVE. (Which is necessary, since
906 MS_MOVE cannot be applied to mounts with MS_SHARED parent
909 if (!mkdtemp(mount_slave
))
910 return sd_bus_error_set_errnof(error
, errno
, "Failed to create playground %s: %m", mount_slave
);
912 mount_slave_created
= true;
914 if (mount(mount_slave
, mount_slave
, NULL
, MS_BIND
, NULL
) < 0) {
915 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to make bind mount %s: %m", mount_slave
);
919 mount_slave_mounted
= true;
921 if (mount(NULL
, mount_slave
, NULL
, MS_SLAVE
, NULL
) < 0) {
922 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to remount slave %s: %m", mount_slave
);
926 /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */
927 mount_tmp
= strjoina(mount_slave
, "/mount");
928 if (S_ISDIR(st
.st_mode
))
929 r
= mkdir_errno_wrapper(mount_tmp
, 0700);
931 r
= touch(mount_tmp
);
933 sd_bus_error_set_errnof(error
, errno
, "Failed to create temporary mount point %s: %m", mount_tmp
);
937 mount_tmp_created
= true;
939 if (mount(chased_src
, mount_tmp
, NULL
, MS_BIND
, NULL
) < 0) {
940 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to mount %s: %m", chased_src
);
944 mount_tmp_mounted
= true;
946 /* Third, we remount the new bind mount read-only if requested. */
948 if (mount(NULL
, mount_tmp
, NULL
, MS_BIND
|MS_REMOUNT
|MS_RDONLY
, NULL
) < 0) {
949 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to remount read-only %s: %m", mount_tmp
);
953 /* Fourth, we move the new bind mount into the propagation directory. This way it will appear there read-only
956 mount_outside
= strjoina("/run/systemd/nspawn/propagate/", m
->name
, "/XXXXXX");
957 if (S_ISDIR(st
.st_mode
))
958 r
= mkdtemp(mount_outside
) ? 0 : -errno
;
960 r
= mkostemp_safe(mount_outside
);
964 sd_bus_error_set_errnof(error
, errno
, "Cannot create propagation file or directory %s: %m", mount_outside
);
968 mount_outside_created
= true;
970 if (mount(mount_tmp
, mount_outside
, NULL
, MS_MOVE
, NULL
) < 0) {
971 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to move %s to %s: %m", mount_tmp
, mount_outside
);
975 mount_outside_mounted
= true;
976 mount_tmp_mounted
= false;
978 if (S_ISDIR(st
.st_mode
))
979 (void) rmdir(mount_tmp
);
981 (void) unlink(mount_tmp
);
982 mount_tmp_created
= false;
984 (void) umount(mount_slave
);
985 mount_slave_mounted
= false;
987 (void) rmdir(mount_slave
);
988 mount_slave_created
= false;
990 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0) {
991 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
995 r
= safe_fork("(sd-bindmnt)", FORK_RESET_SIGNALS
, &child
);
997 sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
1001 const char *mount_inside
;
1005 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
1007 q
= procfs_file_alloca(m
->leader
, "ns/mnt");
1008 mntfd
= open(q
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1010 r
= log_error_errno(errno
, "Failed to open mount namespace of leader: %m");
1014 if (setns(mntfd
, CLONE_NEWNS
) < 0) {
1015 r
= log_error_errno(errno
, "Failed to join namespace of leader: %m");
1019 if (make_file_or_directory
) {
1020 if (S_ISDIR(st
.st_mode
))
1021 (void) mkdir_p(dest
, 0755);
1023 (void) mkdir_parents(dest
, 0755);
1024 safe_close(open(dest
, O_CREAT
|O_EXCL
|O_WRONLY
|O_CLOEXEC
|O_NOCTTY
, 0600));
1028 /* Fifth, move the mount to the right place inside */
1029 mount_inside
= strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside
));
1030 if (mount(mount_inside
, dest
, NULL
, MS_MOVE
, NULL
) < 0) {
1031 r
= log_error_errno(errno
, "Failed to mount: %m");
1035 _exit(EXIT_SUCCESS
);
1038 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
1039 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1041 _exit(EXIT_FAILURE
);
1044 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1046 r
= wait_for_terminate_and_check("(sd-bindmnt)", child
, 0);
1048 r
= sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
1051 if (r
!= EXIT_SUCCESS
) {
1052 if (read(errno_pipe_fd
[0], &r
, sizeof(r
)) == sizeof(r
))
1053 r
= sd_bus_error_set_errnof(error
, r
, "Failed to mount: %m");
1055 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child failed.");
1059 r
= sd_bus_reply_method_return(message
, NULL
);
1062 if (mount_outside_mounted
)
1063 (void) umount(mount_outside
);
1064 if (mount_outside_created
) {
1065 if (S_ISDIR(st
.st_mode
))
1066 (void) rmdir(mount_outside
);
1068 (void) unlink(mount_outside
);
1071 if (mount_tmp_mounted
)
1072 (void) umount(mount_tmp
);
1073 if (mount_tmp_created
) {
1074 if (S_ISDIR(st
.st_mode
))
1075 (void) rmdir(mount_tmp
);
1077 (void) unlink(mount_tmp
);
1080 if (mount_slave_mounted
)
1081 (void) umount(mount_slave
);
1082 if (mount_slave_created
)
1083 (void) rmdir(mount_slave
);
1088 int bus_machine_method_copy(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1089 const char *src
, *dest
, *host_path
, *container_path
, *host_basename
, *host_dirname
, *container_basename
, *container_dirname
;
1090 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
1091 CopyFlags copy_flags
= COPY_REFLINK
|COPY_MERGE
;
1092 _cleanup_close_
int hostfd
= -1;
1093 Machine
*m
= userdata
;
1103 if (m
->manager
->n_operations
>= OPERATIONS_MAX
)
1104 return sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing copies.");
1106 if (m
->class != MACHINE_CONTAINER
)
1107 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Copying files is only supported on container machines.");
1109 r
= sd_bus_message_read(message
, "ss", &src
, &dest
);
1113 if (!path_is_absolute(src
))
1114 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Source path must be absolute.");
1118 else if (!path_is_absolute(dest
))
1119 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Destination path must be absolute.");
1121 r
= bus_verify_polkit_async(
1124 "org.freedesktop.machine1.manage-machines",
1128 &m
->manager
->polkit_registry
,
1133 return 1; /* Will call us back */
1135 r
= machine_get_uid_shift(m
, &uid_shift
);
1139 copy_from
= strstr(sd_bus_message_get_member(message
), "CopyFrom");
1142 container_path
= src
;
1146 container_path
= dest
;
1149 host_basename
= basename(host_path
);
1150 t
= strdupa(host_path
);
1151 host_dirname
= dirname(t
);
1153 container_basename
= basename(container_path
);
1154 t
= strdupa(container_path
);
1155 container_dirname
= dirname(t
);
1157 hostfd
= open(host_dirname
, O_CLOEXEC
|O_RDONLY
|O_NOCTTY
|O_DIRECTORY
);
1159 return sd_bus_error_set_errnof(error
, errno
, "Failed to open host directory %s: %m", host_dirname
);
1161 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0)
1162 return sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
1164 r
= safe_fork("(sd-copy)", FORK_RESET_SIGNALS
, &child
);
1166 return sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
1172 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
1174 q
= procfs_file_alloca(m
->leader
, "ns/mnt");
1175 mntfd
= open(q
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1177 r
= log_error_errno(errno
, "Failed to open mount namespace of leader: %m");
1181 if (setns(mntfd
, CLONE_NEWNS
) < 0) {
1182 r
= log_error_errno(errno
, "Failed to join namespace of leader: %m");
1186 containerfd
= open(container_dirname
, O_CLOEXEC
|O_RDONLY
|O_NOCTTY
|O_DIRECTORY
);
1187 if (containerfd
< 0) {
1188 r
= log_error_errno(errno
, "Failed top open destination directory: %m");
1192 /* Run the actual copy operation. Note that when an UID shift is set we'll either clamp the UID/GID to
1193 * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
1194 * the UID/GIDs as they are. */
1196 r
= copy_tree_at(containerfd
, container_basename
, hostfd
, host_basename
, uid_shift
== 0 ? UID_INVALID
: 0, uid_shift
== 0 ? GID_INVALID
: 0, copy_flags
);
1198 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
);
1200 hostfd
= safe_close(hostfd
);
1201 containerfd
= safe_close(containerfd
);
1204 r
= log_error_errno(r
, "Failed to copy tree: %m");
1208 _exit(EXIT_SUCCESS
);
1211 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
1212 _exit(EXIT_FAILURE
);
1215 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1217 /* Copying might take a while, hence install a watch on the child, and return */
1219 r
= operation_new(m
->manager
, m
, child
, message
, errno_pipe_fd
[0], NULL
);
1221 (void) sigkill_wait(child
);
1224 errno_pipe_fd
[0] = -1;
1229 int bus_machine_method_open_root_directory(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1230 _cleanup_close_
int fd
= -1;
1231 Machine
*m
= userdata
;
1237 r
= bus_verify_polkit_async(
1240 "org.freedesktop.machine1.manage-machines",
1244 &m
->manager
->polkit_registry
,
1249 return 1; /* Will call us back */
1254 fd
= open("/", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
1260 case MACHINE_CONTAINER
: {
1261 _cleanup_close_
int mntns_fd
= -1, root_fd
= -1;
1262 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1265 r
= namespace_open(m
->leader
, NULL
, &mntns_fd
, NULL
, NULL
, &root_fd
);
1269 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1272 r
= safe_fork("(sd-openroot)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
, &child
);
1274 return sd_bus_error_set_errnof(error
, r
, "Failed to fork(): %m");
1276 _cleanup_close_
int dfd
= -1;
1278 pair
[0] = safe_close(pair
[0]);
1280 r
= namespace_enter(-1, mntns_fd
, -1, -1, root_fd
);
1282 _exit(EXIT_FAILURE
);
1284 dfd
= open("/", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
1286 _exit(EXIT_FAILURE
);
1288 r
= send_one_fd(pair
[1], dfd
, 0);
1289 dfd
= safe_close(dfd
);
1291 _exit(EXIT_FAILURE
);
1293 _exit(EXIT_SUCCESS
);
1296 pair
[1] = safe_close(pair
[1]);
1298 r
= wait_for_terminate_and_check("(sd-openroot)", child
, 0);
1300 return sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
1301 if (r
!= EXIT_SUCCESS
)
1302 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child died abnormally.");
1304 fd
= receive_one_fd(pair
[0], MSG_DONTWAIT
);
1312 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Opening the root directory is only supported on container machines.");
1315 return sd_bus_reply_method_return(message
, "h", fd
);
1318 int bus_machine_method_get_uid_shift(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1319 Machine
*m
= userdata
;
1326 /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but
1327 * we kinda have to for this. */
1329 if (m
->class == MACHINE_HOST
)
1330 return sd_bus_reply_method_return(message
, "u", UINT32_C(0));
1332 if (m
->class != MACHINE_CONTAINER
)
1333 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "UID/GID shift may only be determined for container machines.");
1335 r
= machine_get_uid_shift(m
, &shift
);
1337 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m
->name
);
1341 return sd_bus_reply_method_return(message
, "u", (uint32_t) shift
);
1344 const sd_bus_vtable machine_vtable
[] = {
1345 SD_BUS_VTABLE_START(0),
1346 SD_BUS_PROPERTY("Name", "s", NULL
, offsetof(Machine
, name
), SD_BUS_VTABLE_PROPERTY_CONST
),
1347 SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128
, offsetof(Machine
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
1348 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine
, timestamp
), SD_BUS_VTABLE_PROPERTY_CONST
),
1349 SD_BUS_PROPERTY("Service", "s", NULL
, offsetof(Machine
, service
), SD_BUS_VTABLE_PROPERTY_CONST
),
1350 SD_BUS_PROPERTY("Unit", "s", NULL
, offsetof(Machine
, unit
), SD_BUS_VTABLE_PROPERTY_CONST
),
1351 SD_BUS_PROPERTY("Scope", "s", NULL
, offsetof(Machine
, unit
), SD_BUS_VTABLE_PROPERTY_CONST
|SD_BUS_VTABLE_HIDDEN
),
1352 SD_BUS_PROPERTY("Leader", "u", NULL
, offsetof(Machine
, leader
), SD_BUS_VTABLE_PROPERTY_CONST
),
1353 SD_BUS_PROPERTY("Class", "s", property_get_class
, offsetof(Machine
, class), SD_BUS_VTABLE_PROPERTY_CONST
),
1354 SD_BUS_PROPERTY("RootDirectory", "s", NULL
, offsetof(Machine
, root_directory
), SD_BUS_VTABLE_PROPERTY_CONST
),
1355 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
1356 SD_BUS_PROPERTY("State", "s", property_get_state
, 0, 0),
1357 SD_BUS_METHOD("Terminate", NULL
, NULL
, bus_machine_method_terminate
, SD_BUS_VTABLE_UNPRIVILEGED
),
1358 SD_BUS_METHOD("Kill", "si", NULL
, bus_machine_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
1359 SD_BUS_METHOD("GetAddresses", NULL
, "a(iay)", bus_machine_method_get_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1360 SD_BUS_METHOD("GetOSRelease", NULL
, "a{ss}", bus_machine_method_get_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1361 SD_BUS_METHOD("GetUIDShift", NULL
, "u", bus_machine_method_get_uid_shift
, SD_BUS_VTABLE_UNPRIVILEGED
),
1362 SD_BUS_METHOD("OpenPTY", NULL
, "hs", bus_machine_method_open_pty
, SD_BUS_VTABLE_UNPRIVILEGED
),
1363 SD_BUS_METHOD("OpenLogin", NULL
, "hs", bus_machine_method_open_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1364 SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1365 SD_BUS_METHOD("BindMount", "ssbb", NULL
, bus_machine_method_bind_mount
, SD_BUS_VTABLE_UNPRIVILEGED
),
1366 SD_BUS_METHOD("CopyFrom", "ss", NULL
, bus_machine_method_copy
, SD_BUS_VTABLE_UNPRIVILEGED
),
1367 SD_BUS_METHOD("CopyTo", "ss", NULL
, bus_machine_method_copy
, SD_BUS_VTABLE_UNPRIVILEGED
),
1368 SD_BUS_METHOD("OpenRootDirectory", NULL
, "h", bus_machine_method_open_root_directory
, SD_BUS_VTABLE_UNPRIVILEGED
),
1372 int machine_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
1373 Manager
*m
= userdata
;
1383 if (streq(path
, "/org/freedesktop/machine1/machine/self")) {
1384 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
1385 sd_bus_message
*message
;
1388 message
= sd_bus_get_current_message(bus
);
1392 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
1396 r
= sd_bus_creds_get_pid(creds
, &pid
);
1400 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
1404 _cleanup_free_
char *e
= NULL
;
1407 p
= startswith(path
, "/org/freedesktop/machine1/machine/");
1411 e
= bus_label_unescape(p
);
1415 machine
= hashmap_get(m
->machines
, e
);
1424 char *machine_bus_path(Machine
*m
) {
1425 _cleanup_free_
char *e
= NULL
;
1429 e
= bus_label_escape(m
->name
);
1433 return strappend("/org/freedesktop/machine1/machine/", e
);
1436 int machine_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
1437 _cleanup_strv_free_
char **l
= NULL
;
1438 Machine
*machine
= NULL
;
1439 Manager
*m
= userdata
;
1447 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1450 p
= machine_bus_path(machine
);
1454 r
= strv_consume(&l
, p
);
1465 int machine_send_signal(Machine
*m
, bool new_machine
) {
1466 _cleanup_free_
char *p
= NULL
;
1470 p
= machine_bus_path(m
);
1474 return sd_bus_emit_signal(
1476 "/org/freedesktop/machine1",
1477 "org.freedesktop.machine1.Manager",
1478 new_machine
? "MachineNew" : "MachineRemoved",
1482 int machine_send_create_reply(Machine
*m
, sd_bus_error
*error
) {
1483 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*c
= NULL
;
1484 _cleanup_free_
char *p
= NULL
;
1488 if (!m
->create_message
)
1491 c
= m
->create_message
;
1492 m
->create_message
= NULL
;
1495 return sd_bus_reply_method_error(c
, error
);
1497 /* Update the machine state file before we notify the client
1498 * about the result. */
1501 p
= machine_bus_path(m
);
1505 return sd_bus_reply_method_return(c
, "o", p
);