]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machine-dbus.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[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
1cc6c93a 525 *ret = TAKE_PTR(bus);
fbe55073
LP
526 break;
527 }
528
529 default:
530 return -EOPNOTSUPP;
531 }
49af9e13
LP
532
533 return 0;
534}
535
19070062 536int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 537 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
49af9e13 538 _cleanup_free_ char *pty_name = NULL;
4afd3348 539 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
5f8cc96a 540 _cleanup_close_ int master = -1;
fbe55073 541 sd_bus *container_bus = NULL;
5f8cc96a 542 Machine *m = userdata;
49af9e13 543 const char *p, *getty;
5f8cc96a 544 int r;
40205d70 545
19070062
LP
546 assert(message);
547 assert(m);
548
d04c1fb8
LP
549 r = bus_verify_polkit_async(
550 message,
551 CAP_SYS_ADMIN,
4289c3a7 552 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
403ed0e5 553 NULL,
d04c1fb8 554 false,
c529695e 555 UID_INVALID,
d04c1fb8
LP
556 &m->manager->polkit_registry,
557 error);
558 if (r < 0)
559 return r;
560 if (r == 0)
561 return 1; /* Will call us back */
562
fbe55073 563 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
5f8cc96a
LP
564 if (master < 0)
565 return master;
40205d70 566
a07c35c3 567 r = ptsname_namespace(master, &pty_name);
40205d70
LP
568 if (r < 0)
569 return r;
40205d70 570
5f8cc96a
LP
571 p = path_startswith(pty_name, "/dev/pts/");
572 if (!p)
573 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
40205d70 574
385080c0 575 r = container_bus_new(m, error, &allocated_bus);
5f8cc96a
LP
576 if (r < 0)
577 return r;
40205d70 578
fbe55073
LP
579 container_bus = allocated_bus ?: m->manager->bus;
580
49af9e13
LP
581 getty = strjoina("container-getty@", p, ".service");
582
583 r = sd_bus_call_method(
584 container_bus,
585 "org.freedesktop.systemd1",
586 "/org/freedesktop/systemd1",
587 "org.freedesktop.systemd1.Manager",
588 "StartUnit",
589 error, NULL,
590 "ss", getty, "replace");
591 if (r < 0)
592 return r;
593
49af9e13
LP
594 r = sd_bus_message_new_method_return(message, &reply);
595 if (r < 0)
596 return r;
40205d70 597
49af9e13 598 r = sd_bus_message_append(reply, "hs", master, pty_name);
5f8cc96a
LP
599 if (r < 0)
600 return r;
40205d70 601
49af9e13
LP
602 return sd_bus_send(NULL, reply, NULL);
603}
5f8cc96a 604
49af9e13 605int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 606 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *tm = NULL;
49af9e13 607 _cleanup_free_ char *pty_name = NULL;
4afd3348 608 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
fbe55073 609 sd_bus *container_bus = NULL;
40e1f4ea 610 _cleanup_close_ int master = -1, slave = -1;
c46bc7e2 611 _cleanup_strv_free_ char **env = NULL, **args_wire = NULL, **args = NULL;
49af9e13
LP
612 Machine *m = userdata;
613 const char *p, *unit, *user, *path, *description, *utmp_id;
614 int r;
615
616 assert(message);
617 assert(m);
618
619 r = sd_bus_message_read(message, "ss", &user, &path);
620 if (r < 0)
621 return r;
3c6f7c34 622 user = empty_to_null(user);
c46bc7e2 623 r = sd_bus_message_read_strv(message, &args_wire);
49af9e13
LP
624 if (r < 0)
625 return r;
c46bc7e2
SL
626 if (isempty(path)) {
627 path = "/bin/sh";
49af9e13 628
c46bc7e2 629 args = new0(char*, 3 + 1);
49af9e13
LP
630 if (!args)
631 return -ENOMEM;
c46bc7e2
SL
632 args[0] = strdup("sh");
633 if (!args[0])
634 return -ENOMEM;
635 args[1] = strdup("-c");
636 if (!args[1])
637 return -ENOMEM;
638 r = asprintf(&args[2],
639 "shell=$(getent passwd %s 2>/dev/null | { IFS=: read _ _ _ _ _ _ x; echo \"$x\"; })\n"\
640 "exec \"${shell:-/bin/sh}\" -l", /* -l is means --login */
641 isempty(user) ? "root" : user);
642 if (r < 0) {
643 args[2] = NULL;
644 return -ENOMEM;
645 }
646 } else {
647 if (!path_is_absolute(path))
648 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified path '%s' is not absolute", path);
1cc6c93a 649 args = TAKE_PTR(args_wire);
c46bc7e2
SL
650 if (strv_isempty(args)) {
651 args = strv_free(args);
652
653 args = strv_new(path, NULL);
654 if (!args)
655 return -ENOMEM;
656 }
49af9e13
LP
657 }
658
659 r = sd_bus_message_read_strv(message, &env);
660 if (r < 0)
661 return r;
662 if (!strv_env_is_valid(env))
663 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
664
49af9e13
LP
665 r = bus_verify_polkit_async(
666 message,
667 CAP_SYS_ADMIN,
4289c3a7 668 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
403ed0e5 669 NULL,
49af9e13
LP
670 false,
671 UID_INVALID,
672 &m->manager->polkit_registry,
673 error);
674 if (r < 0)
675 return r;
676 if (r == 0)
677 return 1; /* Will call us back */
678
fbe55073 679 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
49af9e13
LP
680 if (master < 0)
681 return master;
682
a07c35c3 683 r = ptsname_namespace(master, &pty_name);
49af9e13
LP
684 if (r < 0)
685 return r;
686
687 p = path_startswith(pty_name, "/dev/pts/");
40e1f4ea
LP
688 assert(p);
689
690 slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
691 if (slave < 0)
692 return slave;
49af9e13
LP
693
694 utmp_id = path_startswith(pty_name, "/dev/");
695 assert(utmp_id);
696
385080c0 697 r = container_bus_new(m, error, &allocated_bus);
49af9e13
LP
698 if (r < 0)
699 return r;
700
fbe55073
LP
701 container_bus = allocated_bus ?: m->manager->bus;
702
49af9e13 703 r = sd_bus_message_new_method_call(
5f8cc96a 704 container_bus,
49af9e13 705 &tm,
5f8cc96a
LP
706 "org.freedesktop.systemd1",
707 "/org/freedesktop/systemd1",
708 "org.freedesktop.systemd1.Manager",
49af9e13
LP
709 "StartTransientUnit");
710 if (r < 0)
711 return r;
712
49af9e13 713 /* Name and mode */
81d62103 714 unit = strjoina("container-shell@", p, ".service");
49af9e13
LP
715 r = sd_bus_message_append(tm, "ss", unit, "fail");
716 if (r < 0)
717 return r;
718
719 /* Properties */
720 r = sd_bus_message_open_container(tm, 'a', "(sv)");
721 if (r < 0)
722 return r;
723
724 description = strjoina("Shell for User ", isempty(user) ? "root" : user);
725 r = sd_bus_message_append(tm,
40e1f4ea 726 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
49af9e13 727 "Description", "s", description,
40e1f4ea
LP
728 "StandardInputFileDescriptor", "h", slave,
729 "StandardOutputFileDescriptor", "h", slave,
730 "StandardErrorFileDescriptor", "h", slave,
49af9e13
LP
731 "SendSIGHUP", "b", true,
732 "IgnoreSIGPIPE", "b", false,
733 "KillMode", "s", "mixed",
49af9e13
LP
734 "TTYReset", "b", true,
735 "UtmpIdentifier", "s", utmp_id,
736 "UtmpMode", "s", "user",
5f5d8eab
LP
737 "PAMName", "s", "login",
738 "WorkingDirectory", "s", "-~");
49af9e13
LP
739 if (r < 0)
740 return r;
741
742 r = sd_bus_message_append(tm, "(sv)", "User", "s", isempty(user) ? "root" : user);
743 if (r < 0)
744 return r;
745
746 if (!strv_isempty(env)) {
747 r = sd_bus_message_open_container(tm, 'r', "sv");
748 if (r < 0)
749 return r;
750
751 r = sd_bus_message_append(tm, "s", "Environment");
752 if (r < 0)
753 return r;
754
755 r = sd_bus_message_open_container(tm, 'v', "as");
756 if (r < 0)
757 return r;
758
759 r = sd_bus_message_append_strv(tm, env);
760 if (r < 0)
761 return r;
762
763 r = sd_bus_message_close_container(tm);
764 if (r < 0)
765 return r;
766
767 r = sd_bus_message_close_container(tm);
768 if (r < 0)
769 return r;
770 }
771
772 /* Exec container */
773 r = sd_bus_message_open_container(tm, 'r', "sv");
774 if (r < 0)
775 return r;
776
777 r = sd_bus_message_append(tm, "s", "ExecStart");
778 if (r < 0)
779 return r;
780
781 r = sd_bus_message_open_container(tm, 'v', "a(sasb)");
782 if (r < 0)
783 return r;
784
785 r = sd_bus_message_open_container(tm, 'a', "(sasb)");
786 if (r < 0)
787 return r;
788
789 r = sd_bus_message_open_container(tm, 'r', "sasb");
790 if (r < 0)
791 return r;
792
793 r = sd_bus_message_append(tm, "s", path);
794 if (r < 0)
795 return r;
796
797 r = sd_bus_message_append_strv(tm, args);
798 if (r < 0)
799 return r;
800
801 r = sd_bus_message_append(tm, "b", true);
802 if (r < 0)
803 return r;
804
805 r = sd_bus_message_close_container(tm);
806 if (r < 0)
807 return r;
808
809 r = sd_bus_message_close_container(tm);
810 if (r < 0)
811 return r;
812
813 r = sd_bus_message_close_container(tm);
814 if (r < 0)
815 return r;
816
817 r = sd_bus_message_close_container(tm);
818 if (r < 0)
819 return r;
820
821 r = sd_bus_message_close_container(tm);
822 if (r < 0)
823 return r;
824
825 /* Auxiliary units */
826 r = sd_bus_message_append(tm, "a(sa(sv))", 0);
827 if (r < 0)
828 return r;
829
830 r = sd_bus_call(container_bus, tm, 0, error, NULL);
ee451d76
LP
831 if (r < 0)
832 return r;
833
40e1f4ea
LP
834 slave = safe_close(slave);
835
40205d70
LP
836 r = sd_bus_message_new_method_return(message, &reply);
837 if (r < 0)
838 return r;
839
ee451d76 840 r = sd_bus_message_append(reply, "hs", master, pty_name);
40205d70
LP
841 if (r < 0)
842 return r;
717603e3 843
9030ca46 844 return sd_bus_send(NULL, reply, NULL);
717603e3
LP
845}
846
19070062 847int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
90adaa25
LP
848 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
849 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
850 bool mount_slave_created = false, mount_slave_mounted = false,
851 mount_tmp_created = false, mount_tmp_mounted = false,
852 mount_outside_created = false, mount_outside_mounted = false;
d3590ace
LP
853 _cleanup_free_ char *chased_src = NULL;
854 int read_only, make_file_or_directory;
90adaa25
LP
855 const char *dest, *src;
856 Machine *m = userdata;
d3590ace 857 struct stat st;
d3590ace 858 pid_t child;
7f43928b 859 uid_t uid;
90adaa25
LP
860 int r;
861
19070062
LP
862 assert(message);
863 assert(m);
864
90adaa25
LP
865 if (m->class != MACHINE_CONTAINER)
866 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
867
d3590ace 868 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory);
90adaa25
LP
869 if (r < 0)
870 return r;
871
99be45a4 872 if (!path_is_absolute(src) || !path_is_normalized(src))
90adaa25
LP
873 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
874
875 if (isempty(dest))
876 dest = src;
99be45a4 877 else if (!path_is_absolute(dest) || !path_is_normalized(dest))
c7abe32b 878 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
90adaa25 879
70244d1d
LP
880 r = bus_verify_polkit_async(
881 message,
882 CAP_SYS_ADMIN,
883 "org.freedesktop.machine1.manage-machines",
403ed0e5 884 NULL,
70244d1d 885 false,
c529695e 886 UID_INVALID,
70244d1d
LP
887 &m->manager->polkit_registry,
888 error);
889 if (r < 0)
890 return r;
891 if (r == 0)
892 return 1; /* Will call us back */
893
7f43928b
LP
894 r = machine_get_uid_shift(m, &uid);
895 if (r < 0)
896 return r;
897 if (uid != 0)
898 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied.");
899
90adaa25
LP
900 /* One day, when bind mounting /proc/self/fd/n works across
901 * namespace boundaries we should rework this logic to make
902 * use of it... */
903
904 p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
905 if (laccess(p, F_OK) < 0)
906 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
907
62570f6f 908 r = chase_symlinks(src, NULL, CHASE_TRAIL_SLASH, &chased_src);
d3590ace
LP
909 if (r < 0)
910 return sd_bus_error_set_errnof(error, r, "Failed to resolve source path: %m");
911
912 if (lstat(chased_src, &st) < 0)
913 return sd_bus_error_set_errnof(error, errno, "Failed to stat() source path: %m");
914 if (S_ISLNK(st.st_mode)) /* This shouldn't really happen, given that we just chased the symlinks above, but let's better be safe… */
915 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Source directory can't be a symbolic link");
916
90adaa25
LP
917 /* Our goal is to install a new bind mount into the container,
918 possibly read-only. This is irritatingly complex
919 unfortunately, currently.
920
921 First, we start by creating a private playground in /tmp,
922 that we can mount MS_SLAVE. (Which is necessary, since
ecb0573d 923 MS_MOVE cannot be applied to mounts with MS_SHARED parent
90adaa25
LP
924 mounts.) */
925
926 if (!mkdtemp(mount_slave))
927 return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
928
929 mount_slave_created = true;
930
931 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
932 r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
933 goto finish;
934 }
935
936 mount_slave_mounted = true;
937
938 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
939 r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
940 goto finish;
941 }
942
d3590ace 943 /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */
90adaa25 944 mount_tmp = strjoina(mount_slave, "/mount");
d3590ace 945 if (S_ISDIR(st.st_mode))
dae8b82e 946 r = mkdir_errno_wrapper(mount_tmp, 0700);
d3590ace
LP
947 else
948 r = touch(mount_tmp);
949 if (r < 0) {
950 sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
90adaa25
LP
951 goto finish;
952 }
953
954 mount_tmp_created = true;
955
d3590ace
LP
956 if (mount(chased_src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
957 r = sd_bus_error_set_errnof(error, errno, "Failed to mount %s: %m", chased_src);
90adaa25
LP
958 goto finish;
959 }
960
961 mount_tmp_mounted = true;
962
963 /* Third, we remount the new bind mount read-only if requested. */
964 if (read_only)
965 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
966 r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
967 goto finish;
968 }
969
d3590ace 970 /* Fourth, we move the new bind mount into the propagation directory. This way it will appear there read-only
90adaa25
LP
971 * right-away. */
972
973 mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
d3590ace
LP
974 if (S_ISDIR(st.st_mode))
975 r = mkdtemp(mount_outside) ? 0 : -errno;
976 else {
977 r = mkostemp_safe(mount_outside);
978 safe_close(r);
979 }
980 if (r < 0) {
981 sd_bus_error_set_errnof(error, errno, "Cannot create propagation file or directory %s: %m", mount_outside);
90adaa25
LP
982 goto finish;
983 }
984
985 mount_outside_created = true;
986
987 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
988 r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
989 goto finish;
990 }
991
992 mount_outside_mounted = true;
993 mount_tmp_mounted = false;
994
d3590ace
LP
995 if (S_ISDIR(st.st_mode))
996 (void) rmdir(mount_tmp);
997 else
998 (void) unlink(mount_tmp);
90adaa25
LP
999 mount_tmp_created = false;
1000
1001 (void) umount(mount_slave);
1002 mount_slave_mounted = false;
1003
1004 (void) rmdir(mount_slave);
1005 mount_slave_created = false;
1006
1007 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
1008 r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
1009 goto finish;
1010 }
1011
4c253ed1
LP
1012 r = safe_fork("(sd-bindmnt)", FORK_RESET_SIGNALS, &child);
1013 if (r < 0) {
1014 sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
90adaa25
LP
1015 goto finish;
1016 }
4c253ed1 1017 if (r == 0) {
90adaa25
LP
1018 const char *mount_inside;
1019 int mntfd;
1020 const char *q;
1021
1022 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1023
1024 q = procfs_file_alloca(m->leader, "ns/mnt");
1025 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1026 if (mntfd < 0) {
1027 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1028 goto child_fail;
1029 }
1030
1031 if (setns(mntfd, CLONE_NEWNS) < 0) {
1032 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1033 goto child_fail;
1034 }
1035
d3590ace
LP
1036 if (make_file_or_directory) {
1037 if (S_ISDIR(st.st_mode))
1038 (void) mkdir_p(dest, 0755);
1039 else {
1040 (void) mkdir_parents(dest, 0755);
1041 safe_close(open(dest, O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600));
1042 }
1043 }
90adaa25
LP
1044
1045 /* Fifth, move the mount to the right place inside */
1046 mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
1047 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
1048 r = log_error_errno(errno, "Failed to mount: %m");
1049 goto child_fail;
1050 }
1051
1052 _exit(EXIT_SUCCESS);
1053
1054 child_fail:
1055 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1056 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1057
1058 _exit(EXIT_FAILURE);
1059 }
1060
1061 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1062
2e87a1fd 1063 r = wait_for_terminate_and_check("(sd-bindmnt)", child, 0);
90adaa25 1064 if (r < 0) {
c0ffce2b 1065 r = sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
90adaa25
LP
1066 goto finish;
1067 }
2e87a1fd 1068 if (r != EXIT_SUCCESS) {
90adaa25 1069 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
c7abe32b 1070 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
90adaa25 1071 else
c0ffce2b 1072 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child failed.");
90adaa25
LP
1073 goto finish;
1074 }
1075
1076 r = sd_bus_reply_method_return(message, NULL);
1077
1078finish:
1079 if (mount_outside_mounted)
d3590ace
LP
1080 (void) umount(mount_outside);
1081 if (mount_outside_created) {
1082 if (S_ISDIR(st.st_mode))
1083 (void) rmdir(mount_outside);
1084 else
1085 (void) unlink(mount_outside);
1086 }
90adaa25
LP
1087
1088 if (mount_tmp_mounted)
d3590ace
LP
1089 (void) umount(mount_tmp);
1090 if (mount_tmp_created) {
1091 if (S_ISDIR(st.st_mode))
1092 (void) rmdir(mount_tmp);
1093 else
1094 (void) unlink(mount_tmp);
1095 }
90adaa25
LP
1096
1097 if (mount_slave_mounted)
d3590ace 1098 (void) umount(mount_slave);
90adaa25 1099 if (mount_slave_created)
d3590ace 1100 (void) rmdir(mount_slave);
90adaa25
LP
1101
1102 return r;
1103}
1104
19070062 1105int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
0370612e
LP
1106 const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
1107 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
d01cd401 1108 CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE;
0370612e
LP
1109 _cleanup_close_ int hostfd = -1;
1110 Machine *m = userdata;
0370612e
LP
1111 bool copy_from;
1112 pid_t child;
d01cd401 1113 uid_t uid_shift;
0370612e
LP
1114 char *t;
1115 int r;
1116
19070062
LP
1117 assert(message);
1118 assert(m);
1119
795c5d31 1120 if (m->manager->n_operations >= OPERATIONS_MAX)
0370612e
LP
1121 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
1122
1123 if (m->class != MACHINE_CONTAINER)
1124 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
1125
1126 r = sd_bus_message_read(message, "ss", &src, &dest);
1127 if (r < 0)
1128 return r;
1129
d8440176
RM
1130 if (!path_is_absolute(src))
1131 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
0370612e
LP
1132
1133 if (isempty(dest))
1134 dest = src;
d8440176
RM
1135 else if (!path_is_absolute(dest))
1136 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
0370612e 1137
70244d1d
LP
1138 r = bus_verify_polkit_async(
1139 message,
1140 CAP_SYS_ADMIN,
1141 "org.freedesktop.machine1.manage-machines",
403ed0e5 1142 NULL,
70244d1d 1143 false,
c529695e 1144 UID_INVALID,
70244d1d
LP
1145 &m->manager->polkit_registry,
1146 error);
1147 if (r < 0)
1148 return r;
1149 if (r == 0)
1150 return 1; /* Will call us back */
1151
d01cd401
LP
1152 r = machine_get_uid_shift(m, &uid_shift);
1153 if (r < 0)
1154 return r;
1155
0370612e
LP
1156 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
1157
1158 if (copy_from) {
1159 container_path = src;
1160 host_path = dest;
1161 } else {
1162 host_path = src;
1163 container_path = dest;
1164 }
1165
1166 host_basename = basename(host_path);
1167 t = strdupa(host_path);
1168 host_dirname = dirname(t);
1169
1170 container_basename = basename(container_path);
1171 t = strdupa(container_path);
1172 container_dirname = dirname(t);
1173
1174 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
858a109f 1175 if (hostfd < 0)
0370612e
LP
1176 return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
1177
1178 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
1179 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
1180
4c253ed1
LP
1181 r = safe_fork("(sd-copy)", FORK_RESET_SIGNALS, &child);
1182 if (r < 0)
1183 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
1184 if (r == 0) {
0370612e
LP
1185 int containerfd;
1186 const char *q;
1187 int mntfd;
1188
1189 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1190
1191 q = procfs_file_alloca(m->leader, "ns/mnt");
1192 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1193 if (mntfd < 0) {
1194 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1195 goto child_fail;
1196 }
1197
1198 if (setns(mntfd, CLONE_NEWNS) < 0) {
1199 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1200 goto child_fail;
1201 }
1202
1203 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1204 if (containerfd < 0) {
fe4a1d0f 1205 r = log_error_errno(errno, "Failed to open destination directory: %m");
0370612e
LP
1206 goto child_fail;
1207 }
1208
d01cd401
LP
1209 /* Run the actual copy operation. Note that when an UID shift is set we'll either clamp the UID/GID to
1210 * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
1211 * the UID/GIDs as they are. */
0370612e 1212 if (copy_from)
d01cd401 1213 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags);
0370612e 1214 else
d01cd401 1215 r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags);
0370612e
LP
1216
1217 hostfd = safe_close(hostfd);
1218 containerfd = safe_close(containerfd);
1219
1220 if (r < 0) {
1221 r = log_error_errno(r, "Failed to copy tree: %m");
1222 goto child_fail;
1223 }
1224
1225 _exit(EXIT_SUCCESS);
1226
1227 child_fail:
1228 (void) write(errno_pipe_fd[1], &r, sizeof(r));
0370612e
LP
1229 _exit(EXIT_FAILURE);
1230 }
1231
1232 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1233
795c5d31 1234 /* Copying might take a while, hence install a watch on the child, and return */
0370612e 1235
03c2b288 1236 r = operation_new(m->manager, m, child, message, errno_pipe_fd[0], NULL);
0370612e 1237 if (r < 0) {
795c5d31
LP
1238 (void) sigkill_wait(child);
1239 return r;
0370612e 1240 }
795c5d31 1241 errno_pipe_fd[0] = -1;
0370612e
LP
1242
1243 return 1;
1244}
1245
ae203207
LP
1246int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1247 _cleanup_close_ int fd = -1;
1248 Machine *m = userdata;
1249 int r;
1250
1251 assert(message);
1252 assert(m);
1253
1254 r = bus_verify_polkit_async(
1255 message,
1256 CAP_SYS_ADMIN,
1257 "org.freedesktop.machine1.manage-machines",
1258 NULL,
1259 false,
1260 UID_INVALID,
1261 &m->manager->polkit_registry,
1262 error);
1263 if (r < 0)
1264 return r;
1265 if (r == 0)
1266 return 1; /* Will call us back */
1267
1268 switch (m->class) {
1269
1270 case MACHINE_HOST:
1271 fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1272 if (fd < 0)
1273 return -errno;
1274
1275 break;
1276
1277 case MACHINE_CONTAINER: {
1278 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
1279 _cleanup_close_pair_ int pair[2] = { -1, -1 };
ae203207
LP
1280 pid_t child;
1281
1282 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
1283 if (r < 0)
1284 return r;
1285
1286 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1287 return -errno;
1288
4c253ed1
LP
1289 r = safe_fork("(sd-openroot)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
1290 if (r < 0)
1291 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
1292 if (r == 0) {
ae203207
LP
1293 _cleanup_close_ int dfd = -1;
1294
1295 pair[0] = safe_close(pair[0]);
1296
1297 r = namespace_enter(-1, mntns_fd, -1, -1, root_fd);
1298 if (r < 0)
1299 _exit(EXIT_FAILURE);
1300
1301 dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1302 if (dfd < 0)
1303 _exit(EXIT_FAILURE);
1304
1305 r = send_one_fd(pair[1], dfd, 0);
1306 dfd = safe_close(dfd);
1307 if (r < 0)
1308 _exit(EXIT_FAILURE);
1309
1310 _exit(EXIT_SUCCESS);
1311 }
1312
1313 pair[1] = safe_close(pair[1]);
1314
2e87a1fd 1315 r = wait_for_terminate_and_check("(sd-openroot)", child, 0);
ae203207
LP
1316 if (r < 0)
1317 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
2e87a1fd 1318 if (r != EXIT_SUCCESS)
ae203207
LP
1319 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
1320
1321 fd = receive_one_fd(pair[0], MSG_DONTWAIT);
1322 if (fd < 0)
1323 return fd;
1324
1325 break;
1326 }
1327
1328 default:
1329 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
1330 }
1331
1332 return sd_bus_reply_method_return(message, "h", fd);
1333}
1334
3401419b
LP
1335int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1336 Machine *m = userdata;
1337 uid_t shift = 0;
1338 int r;
1339
1340 assert(message);
1341 assert(m);
1342
1343 /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but
1344 * we kinda have to for this. */
1345
1346 if (m->class == MACHINE_HOST)
1347 return sd_bus_reply_method_return(message, "u", UINT32_C(0));
1348
1349 if (m->class != MACHINE_CONTAINER)
1350 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines.");
1351
1352 r = machine_get_uid_shift(m, &shift);
1353 if (r == -ENXIO)
1354 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m->name);
1355 if (r < 0)
1356 return r;
1357
1358 return sd_bus_reply_method_return(message, "u", (uint32_t) shift);
1359}
1360
c3350683
LP
1361const sd_bus_vtable machine_vtable[] = {
1362 SD_BUS_VTABLE_START(0),
556089dc 1363 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
766c94ad 1364 SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
1365 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1366 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
89f7c846
LP
1367 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
1368 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
556089dc
LP
1369 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
1370 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
1371 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
9b5ed6fe 1372 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
c3350683 1373 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
70244d1d
LP
1374 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
1375 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
0dd25fb9 1376 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 1377 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
3401419b 1378 SD_BUS_METHOD("GetUIDShift", NULL, "u", bus_machine_method_get_uid_shift, SD_BUS_VTABLE_UNPRIVILEGED),
fbe55073 1379 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, SD_BUS_VTABLE_UNPRIVILEGED),
d04c1fb8 1380 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
49af9e13 1381 SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell, SD_BUS_VTABLE_UNPRIVILEGED),
70244d1d
LP
1382 SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
1383 SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
1384 SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
ae203207 1385 SD_BUS_METHOD("OpenRootDirectory", NULL, "h", bus_machine_method_open_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 1386 SD_BUS_VTABLE_END
c3350683 1387};
9444b1f2 1388
f00c3121 1389int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
c3350683
LP
1390 Manager *m = userdata;
1391 Machine *machine;
927b1649 1392 int r;
9444b1f2 1393
c3350683
LP
1394 assert(bus);
1395 assert(path);
1396 assert(interface);
1397 assert(found);
1398 assert(m);
9444b1f2 1399
927b1649 1400 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
4afd3348 1401 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
927b1649
LP
1402 sd_bus_message *message;
1403 pid_t pid;
9444b1f2 1404
19befb2d 1405 message = sd_bus_get_current_message(bus);
927b1649
LP
1406 if (!message)
1407 return 0;
1408
5b12334d 1409 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
927b1649 1410 if (r < 0)
5b12334d
LP
1411 return r;
1412
1413 r = sd_bus_creds_get_pid(creds, &pid);
1414 if (r < 0)
1415 return r;
9444b1f2 1416
927b1649
LP
1417 r = manager_get_machine_by_pid(m, pid, &machine);
1418 if (r <= 0)
1419 return 0;
1420 } else {
1421 _cleanup_free_ char *e = NULL;
1422 const char *p;
1423
1424 p = startswith(path, "/org/freedesktop/machine1/machine/");
1425 if (!p)
1426 return 0;
1427
a6278b88 1428 e = bus_label_unescape(p);
927b1649
LP
1429 if (!e)
1430 return -ENOMEM;
1431
1432 machine = hashmap_get(m->machines, e);
1433 if (!machine)
1434 return 0;
1435 }
9444b1f2 1436
c3350683
LP
1437 *found = machine;
1438 return 1;
9444b1f2
LP
1439}
1440
9444b1f2
LP
1441char *machine_bus_path(Machine *m) {
1442 _cleanup_free_ char *e = NULL;
1443
1444 assert(m);
1445
a6278b88 1446 e = bus_label_escape(m->name);
9444b1f2
LP
1447 if (!e)
1448 return NULL;
1449
1ee306e1 1450 return strappend("/org/freedesktop/machine1/machine/", e);
9444b1f2
LP
1451}
1452
f00c3121 1453int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
927b1649
LP
1454 _cleanup_strv_free_ char **l = NULL;
1455 Machine *machine = NULL;
1456 Manager *m = userdata;
1457 Iterator i;
1458 int r;
1459
1460 assert(bus);
1461 assert(path);
1462 assert(nodes);
1463
1464 HASHMAP_FOREACH(machine, m->machines, i) {
1465 char *p;
1466
1467 p = machine_bus_path(machine);
1468 if (!p)
1469 return -ENOMEM;
1470
6e18964d
ZJS
1471 r = strv_consume(&l, p);
1472 if (r < 0)
927b1649 1473 return r;
927b1649
LP
1474 }
1475
ae2a15bc 1476 *nodes = TAKE_PTR(l);
927b1649
LP
1477
1478 return 1;
1479}
1480
9444b1f2 1481int machine_send_signal(Machine *m, bool new_machine) {
9444b1f2
LP
1482 _cleanup_free_ char *p = NULL;
1483
1484 assert(m);
1485
9444b1f2
LP
1486 p = machine_bus_path(m);
1487 if (!p)
1488 return -ENOMEM;
1489
c3350683
LP
1490 return sd_bus_emit_signal(
1491 m->manager->bus,
1492 "/org/freedesktop/machine1",
1493 "org.freedesktop.machine1.Manager",
1494 new_machine ? "MachineNew" : "MachineRemoved",
1495 "so", m->name, p);
9444b1f2
LP
1496}
1497
c3350683 1498int machine_send_create_reply(Machine *m, sd_bus_error *error) {
4afd3348 1499 _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
9444b1f2
LP
1500 _cleanup_free_ char *p = NULL;
1501
1502 assert(m);
1503
fb6becb4
LP
1504 if (!m->create_message)
1505 return 0;
1506
1cc6c93a 1507 c = TAKE_PTR(m->create_message);
fb6becb4 1508
a658cafa 1509 if (error)
df2d202e 1510 return sd_bus_reply_method_error(c, error);
a658cafa 1511
76e66585
LP
1512 /* Update the machine state file before we notify the client
1513 * about the result. */
1514 machine_save(m);
1515
c3350683
LP
1516 p = machine_bus_path(m);
1517 if (!p)
1518 return -ENOMEM;
fb6becb4 1519
df2d202e 1520 return sd_bus_reply_method_return(c, "o", p);
fb6becb4 1521}