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