]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machine-dbus.c
Add SPDX license identifiers to source files under the LGPL
[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;
231 siginfo_t si;
232 pid_t child;
878cd7e9 233
fbe55073
LP
234 r = readlink_malloc("/proc/self/ns/net", &us);
235 if (r < 0)
236 return r;
878cd7e9 237
fbe55073
LP
238 p = procfs_file_alloca(m->leader, "ns/net");
239 r = readlink_malloc(p, &them);
878cd7e9 240 if (r < 0)
c7abe32b 241 return r;
878cd7e9 242
fbe55073
LP
243 if (streq(us, them))
244 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
245
246 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL, NULL);
878cd7e9 247 if (r < 0)
c7abe32b 248 return r;
878cd7e9 249
fbe55073
LP
250 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
251 return -errno;
252
253 child = fork();
254 if (child < 0)
255 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
256
257 if (child == 0) {
258 _cleanup_free_ struct local_address *addresses = NULL;
259 struct local_address *a;
260 int i, n;
261
262 pair[0] = safe_close(pair[0]);
263
264 r = namespace_enter(-1, -1, netns_fd, -1, -1);
265 if (r < 0)
266 _exit(EXIT_FAILURE);
267
268 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
269 if (n < 0)
270 _exit(EXIT_FAILURE);
878cd7e9 271
fbe55073
LP
272 for (a = addresses, i = 0; i < n; a++, i++) {
273 struct iovec iov[2] = {
274 { .iov_base = &a->family, .iov_len = sizeof(a->family) },
275 { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
276 };
878cd7e9 277
fbe55073
LP
278 r = writev(pair[1], iov, 2);
279 if (r < 0)
280 _exit(EXIT_FAILURE);
281 }
878cd7e9 282
fbe55073 283 pair[1] = safe_close(pair[1]);
878cd7e9 284
fbe55073 285 _exit(EXIT_SUCCESS);
878cd7e9 286 }
878cd7e9 287
fbe55073
LP
288 pair[1] = safe_close(pair[1]);
289
290 for (;;) {
291 int family;
292 ssize_t n;
293 union in_addr_union in_addr;
294 struct iovec iov[2];
295 struct msghdr mh = {
296 .msg_iov = iov,
297 .msg_iovlen = 2,
298 };
299
300 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
301 iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
302
303 n = recvmsg(pair[0], &mh, 0);
304 if (n < 0)
305 return -errno;
306 if ((size_t) n < sizeof(family))
307 break;
308
309 r = sd_bus_message_open_container(reply, 'r', "iay");
310 if (r < 0)
311 return r;
312
313 r = sd_bus_message_append(reply, "i", family);
314 if (r < 0)
315 return r;
316
317 switch (family) {
318
319 case AF_INET:
320 if (n != sizeof(struct in_addr) + sizeof(family))
321 return -EIO;
322
323 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
324 break;
325
326 case AF_INET6:
327 if (n != sizeof(struct in6_addr) + sizeof(family))
328 return -EIO;
329
330 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
331 break;
332 }
333 if (r < 0)
334 return r;
335
336 r = sd_bus_message_close_container(reply);
337 if (r < 0)
338 return r;
339 }
340
341 r = wait_for_terminate(child, &si);
878cd7e9 342 if (r < 0)
c0ffce2b 343 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
fbe55073 344 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
c0ffce2b 345 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
fbe55073 346 break;
878cd7e9
LP
347 }
348
fbe55073
LP
349 default:
350 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
351 }
878cd7e9
LP
352
353 r = sd_bus_message_close_container(reply);
354 if (r < 0)
c7abe32b 355 return r;
878cd7e9 356
9030ca46 357 return sd_bus_send(NULL, reply, NULL);
878cd7e9
LP
358}
359
9153b02b
LP
360#define EXIT_NOT_FOUND 2
361
19070062 362int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
717603e3 363 _cleanup_strv_free_ char **l = NULL;
717603e3 364 Machine *m = userdata;
717603e3
LP
365 int r;
366
717603e3
LP
367 assert(message);
368 assert(m);
369
fbe55073 370 switch (m->class) {
b4d8ef7c 371
fbe55073
LP
372 case MACHINE_HOST:
373 r = load_env_file_pairs(NULL, "/etc/os-release", NULL, &l);
374 if (r < 0)
375 return r;
717603e3 376
fbe55073 377 break;
717603e3 378
fbe55073
LP
379 case MACHINE_CONTAINER: {
380 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
381 _cleanup_close_pair_ int pair[2] = { -1, -1 };
382 _cleanup_fclose_ FILE *f = NULL;
383 siginfo_t si;
384 pid_t child;
717603e3 385
fbe55073
LP
386 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
387 if (r < 0)
388 return r;
717603e3 389
fbe55073
LP
390 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
391 return -errno;
717603e3 392
fbe55073
LP
393 child = fork();
394 if (child < 0)
395 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
396
397 if (child == 0) {
9153b02b 398 int fd = -1;
fbe55073
LP
399
400 pair[0] = safe_close(pair[0]);
401
402 r = namespace_enter(-1, mntns_fd, -1, -1, root_fd);
403 if (r < 0)
404 _exit(EXIT_FAILURE);
405
9153b02b
LP
406 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC|O_NOCTTY);
407 if (fd < 0 && errno == ENOENT) {
408 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC|O_NOCTTY);
409 if (fd < 0 && errno == ENOENT)
410 _exit(EXIT_NOT_FOUND);
fbe55073 411 }
9153b02b
LP
412 if (fd < 0)
413 _exit(EXIT_FAILURE);
717603e3 414
1c876927 415 r = copy_bytes(fd, pair[1], (uint64_t) -1, 0);
fbe55073 416 if (r < 0)
717603e3 417 _exit(EXIT_FAILURE);
fbe55073
LP
418
419 _exit(EXIT_SUCCESS);
717603e3
LP
420 }
421
fbe55073 422 pair[1] = safe_close(pair[1]);
717603e3 423
fbe55073
LP
424 f = fdopen(pair[0], "re");
425 if (!f)
426 return -errno;
717603e3 427
fbe55073 428 pair[0] = -1;
717603e3 429
fbe55073
LP
430 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
431 if (r < 0)
432 return r;
717603e3 433
fbe55073
LP
434 r = wait_for_terminate(child, &si);
435 if (r < 0)
c0ffce2b 436 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
9153b02b
LP
437 if (si.si_code == CLD_EXITED && si.si_status == EXIT_NOT_FOUND)
438 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Machine does not contain OS release information");
fbe55073 439 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
c0ffce2b 440 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
717603e3 441
fbe55073
LP
442 break;
443 }
717603e3 444
fbe55073
LP
445 default:
446 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
447 }
717603e3 448
9153b02b 449 return bus_reply_pair_array(message, l);
40205d70
LP
450}
451
19070062 452int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 453 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
5f8cc96a 454 _cleanup_free_ char *pty_name = NULL;
40205d70 455 _cleanup_close_ int master = -1;
40205d70 456 Machine *m = userdata;
40205d70
LP
457 int r;
458
40205d70
LP
459 assert(message);
460 assert(m);
461
fbe55073
LP
462 r = bus_verify_polkit_async(
463 message,
464 CAP_SYS_ADMIN,
4289c3a7 465 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty",
403ed0e5 466 NULL,
fbe55073
LP
467 false,
468 UID_INVALID,
469 &m->manager->polkit_registry,
470 error);
471 if (r < 0)
472 return r;
473 if (r == 0)
474 return 1; /* Will call us back */
b4d8ef7c 475
fbe55073 476 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
5f8cc96a
LP
477 if (master < 0)
478 return master;
479
a07c35c3 480 r = ptsname_namespace(master, &pty_name);
40205d70
LP
481 if (r < 0)
482 return r;
483
5f8cc96a
LP
484 r = sd_bus_message_new_method_return(message, &reply);
485 if (r < 0)
486 return r;
40205d70 487
5f8cc96a
LP
488 r = sd_bus_message_append(reply, "hs", master, pty_name);
489 if (r < 0)
490 return r;
40205d70 491
9030ca46 492 return sd_bus_send(NULL, reply, NULL);
5f8cc96a 493}
40205d70 494
385080c0 495static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) {
49af9e13
LP
496 int r;
497
498 assert(m);
499 assert(ret);
500
fbe55073 501 switch (m->class) {
49af9e13 502
fbe55073
LP
503 case MACHINE_HOST:
504 *ret = NULL;
505 break;
49af9e13 506
fbe55073 507 case MACHINE_CONTAINER: {
4afd3348 508 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
fbe55073 509 char *address;
49af9e13 510
fbe55073
LP
511 r = sd_bus_new(&bus);
512 if (r < 0)
513 return r;
49af9e13 514
fbe55073
LP
515 if (asprintf(&address, "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI, m->leader) < 0)
516 return -ENOMEM;
517
518 bus->address = address;
519 bus->bus_client = true;
520 bus->trusted = false;
521 bus->is_system = true;
522
523 r = sd_bus_start(bus);
385080c0
LP
524 if (r == -ENOENT)
525 return sd_bus_error_set_errnof(error, r, "There is no system bus in container %s.", m->name);
fbe55073
LP
526 if (r < 0)
527 return r;
528
529 *ret = bus;
530 bus = NULL;
531 break;
532 }
533
534 default:
535 return -EOPNOTSUPP;
536 }
49af9e13
LP
537
538 return 0;
539}
540
19070062 541int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 542 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
49af9e13 543 _cleanup_free_ char *pty_name = NULL;
4afd3348 544 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
5f8cc96a 545 _cleanup_close_ int master = -1;
fbe55073 546 sd_bus *container_bus = NULL;
5f8cc96a 547 Machine *m = userdata;
49af9e13 548 const char *p, *getty;
5f8cc96a 549 int r;
40205d70 550
19070062
LP
551 assert(message);
552 assert(m);
553
d04c1fb8
LP
554 r = bus_verify_polkit_async(
555 message,
556 CAP_SYS_ADMIN,
4289c3a7 557 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
403ed0e5 558 NULL,
d04c1fb8 559 false,
c529695e 560 UID_INVALID,
d04c1fb8
LP
561 &m->manager->polkit_registry,
562 error);
563 if (r < 0)
564 return r;
565 if (r == 0)
566 return 1; /* Will call us back */
567
fbe55073 568 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
5f8cc96a
LP
569 if (master < 0)
570 return master;
40205d70 571
a07c35c3 572 r = ptsname_namespace(master, &pty_name);
40205d70
LP
573 if (r < 0)
574 return r;
40205d70 575
5f8cc96a
LP
576 p = path_startswith(pty_name, "/dev/pts/");
577 if (!p)
578 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
40205d70 579
385080c0 580 r = container_bus_new(m, error, &allocated_bus);
5f8cc96a
LP
581 if (r < 0)
582 return r;
40205d70 583
fbe55073
LP
584 container_bus = allocated_bus ?: m->manager->bus;
585
49af9e13
LP
586 getty = strjoina("container-getty@", p, ".service");
587
588 r = sd_bus_call_method(
589 container_bus,
590 "org.freedesktop.systemd1",
591 "/org/freedesktop/systemd1",
592 "org.freedesktop.systemd1.Manager",
593 "StartUnit",
594 error, NULL,
595 "ss", getty, "replace");
596 if (r < 0)
597 return r;
598
49af9e13
LP
599 r = sd_bus_message_new_method_return(message, &reply);
600 if (r < 0)
601 return r;
40205d70 602
49af9e13 603 r = sd_bus_message_append(reply, "hs", master, pty_name);
5f8cc96a
LP
604 if (r < 0)
605 return r;
40205d70 606
49af9e13
LP
607 return sd_bus_send(NULL, reply, NULL);
608}
5f8cc96a 609
49af9e13 610int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 611 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *tm = NULL;
49af9e13 612 _cleanup_free_ char *pty_name = NULL;
4afd3348 613 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
fbe55073 614 sd_bus *container_bus = NULL;
40e1f4ea 615 _cleanup_close_ int master = -1, slave = -1;
49af9e13
LP
616 _cleanup_strv_free_ char **env = NULL, **args = NULL;
617 Machine *m = userdata;
618 const char *p, *unit, *user, *path, *description, *utmp_id;
619 int r;
620
621 assert(message);
622 assert(m);
623
624 r = sd_bus_message_read(message, "ss", &user, &path);
625 if (r < 0)
626 return r;
3c6f7c34 627 user = empty_to_null(user);
49af9e13
LP
628 if (isempty(path))
629 path = "/bin/sh";
630 if (!path_is_absolute(path))
631 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified path '%s' is not absolute", path);
632
633 r = sd_bus_message_read_strv(message, &args);
634 if (r < 0)
635 return r;
636 if (strv_isempty(args)) {
637 args = strv_free(args);
638
639 args = strv_new(path, NULL);
640 if (!args)
641 return -ENOMEM;
642
643 args[0][0] = '-'; /* Tell /bin/sh that this shall be a login shell */
644 }
645
646 r = sd_bus_message_read_strv(message, &env);
647 if (r < 0)
648 return r;
649 if (!strv_env_is_valid(env))
650 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
651
49af9e13
LP
652 r = bus_verify_polkit_async(
653 message,
654 CAP_SYS_ADMIN,
4289c3a7 655 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
403ed0e5 656 NULL,
49af9e13
LP
657 false,
658 UID_INVALID,
659 &m->manager->polkit_registry,
660 error);
661 if (r < 0)
662 return r;
663 if (r == 0)
664 return 1; /* Will call us back */
665
fbe55073 666 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
49af9e13
LP
667 if (master < 0)
668 return master;
669
a07c35c3 670 r = ptsname_namespace(master, &pty_name);
49af9e13
LP
671 if (r < 0)
672 return r;
673
674 p = path_startswith(pty_name, "/dev/pts/");
40e1f4ea
LP
675 assert(p);
676
677 slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
678 if (slave < 0)
679 return slave;
49af9e13
LP
680
681 utmp_id = path_startswith(pty_name, "/dev/");
682 assert(utmp_id);
683
385080c0 684 r = container_bus_new(m, error, &allocated_bus);
49af9e13
LP
685 if (r < 0)
686 return r;
687
fbe55073
LP
688 container_bus = allocated_bus ?: m->manager->bus;
689
49af9e13 690 r = sd_bus_message_new_method_call(
5f8cc96a 691 container_bus,
49af9e13 692 &tm,
5f8cc96a
LP
693 "org.freedesktop.systemd1",
694 "/org/freedesktop/systemd1",
695 "org.freedesktop.systemd1.Manager",
49af9e13
LP
696 "StartTransientUnit");
697 if (r < 0)
698 return r;
699
49af9e13 700 /* Name and mode */
81d62103 701 unit = strjoina("container-shell@", p, ".service");
49af9e13
LP
702 r = sd_bus_message_append(tm, "ss", unit, "fail");
703 if (r < 0)
704 return r;
705
706 /* Properties */
707 r = sd_bus_message_open_container(tm, 'a', "(sv)");
708 if (r < 0)
709 return r;
710
711 description = strjoina("Shell for User ", isempty(user) ? "root" : user);
712 r = sd_bus_message_append(tm,
40e1f4ea 713 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
49af9e13 714 "Description", "s", description,
40e1f4ea
LP
715 "StandardInputFileDescriptor", "h", slave,
716 "StandardOutputFileDescriptor", "h", slave,
717 "StandardErrorFileDescriptor", "h", slave,
49af9e13
LP
718 "SendSIGHUP", "b", true,
719 "IgnoreSIGPIPE", "b", false,
720 "KillMode", "s", "mixed",
49af9e13
LP
721 "TTYReset", "b", true,
722 "UtmpIdentifier", "s", utmp_id,
723 "UtmpMode", "s", "user",
5f5d8eab
LP
724 "PAMName", "s", "login",
725 "WorkingDirectory", "s", "-~");
49af9e13
LP
726 if (r < 0)
727 return r;
728
729 r = sd_bus_message_append(tm, "(sv)", "User", "s", isempty(user) ? "root" : user);
730 if (r < 0)
731 return r;
732
733 if (!strv_isempty(env)) {
734 r = sd_bus_message_open_container(tm, 'r', "sv");
735 if (r < 0)
736 return r;
737
738 r = sd_bus_message_append(tm, "s", "Environment");
739 if (r < 0)
740 return r;
741
742 r = sd_bus_message_open_container(tm, 'v', "as");
743 if (r < 0)
744 return r;
745
746 r = sd_bus_message_append_strv(tm, env);
747 if (r < 0)
748 return r;
749
750 r = sd_bus_message_close_container(tm);
751 if (r < 0)
752 return r;
753
754 r = sd_bus_message_close_container(tm);
755 if (r < 0)
756 return r;
757 }
758
759 /* Exec container */
760 r = sd_bus_message_open_container(tm, 'r', "sv");
761 if (r < 0)
762 return r;
763
764 r = sd_bus_message_append(tm, "s", "ExecStart");
765 if (r < 0)
766 return r;
767
768 r = sd_bus_message_open_container(tm, 'v', "a(sasb)");
769 if (r < 0)
770 return r;
771
772 r = sd_bus_message_open_container(tm, 'a', "(sasb)");
773 if (r < 0)
774 return r;
775
776 r = sd_bus_message_open_container(tm, 'r', "sasb");
777 if (r < 0)
778 return r;
779
780 r = sd_bus_message_append(tm, "s", path);
781 if (r < 0)
782 return r;
783
784 r = sd_bus_message_append_strv(tm, args);
785 if (r < 0)
786 return r;
787
788 r = sd_bus_message_append(tm, "b", true);
789 if (r < 0)
790 return r;
791
792 r = sd_bus_message_close_container(tm);
793 if (r < 0)
794 return r;
795
796 r = sd_bus_message_close_container(tm);
797 if (r < 0)
798 return r;
799
800 r = sd_bus_message_close_container(tm);
801 if (r < 0)
802 return r;
803
804 r = sd_bus_message_close_container(tm);
805 if (r < 0)
806 return r;
807
808 r = sd_bus_message_close_container(tm);
809 if (r < 0)
810 return r;
811
812 /* Auxiliary units */
813 r = sd_bus_message_append(tm, "a(sa(sv))", 0);
814 if (r < 0)
815 return r;
816
817 r = sd_bus_call(container_bus, tm, 0, error, NULL);
ee451d76
LP
818 if (r < 0)
819 return r;
820
40e1f4ea
LP
821 slave = safe_close(slave);
822
40205d70
LP
823 r = sd_bus_message_new_method_return(message, &reply);
824 if (r < 0)
825 return r;
826
ee451d76 827 r = sd_bus_message_append(reply, "hs", master, pty_name);
40205d70
LP
828 if (r < 0)
829 return r;
717603e3 830
9030ca46 831 return sd_bus_send(NULL, reply, NULL);
717603e3
LP
832}
833
19070062 834int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
90adaa25
LP
835 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
836 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
837 bool mount_slave_created = false, mount_slave_mounted = false,
838 mount_tmp_created = false, mount_tmp_mounted = false,
839 mount_outside_created = false, mount_outside_mounted = false;
d3590ace
LP
840 _cleanup_free_ char *chased_src = NULL;
841 int read_only, make_file_or_directory;
90adaa25
LP
842 const char *dest, *src;
843 Machine *m = userdata;
d3590ace 844 struct stat st;
90adaa25 845 siginfo_t si;
d3590ace 846 pid_t child;
7f43928b 847 uid_t uid;
90adaa25
LP
848 int r;
849
19070062
LP
850 assert(message);
851 assert(m);
852
90adaa25
LP
853 if (m->class != MACHINE_CONTAINER)
854 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
855
d3590ace 856 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory);
90adaa25
LP
857 if (r < 0)
858 return r;
859
860 if (!path_is_absolute(src) || !path_is_safe(src))
861 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
862
863 if (isempty(dest))
864 dest = src;
865 else if (!path_is_absolute(dest) || !path_is_safe(dest))
c7abe32b 866 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
90adaa25 867
70244d1d
LP
868 r = bus_verify_polkit_async(
869 message,
870 CAP_SYS_ADMIN,
871 "org.freedesktop.machine1.manage-machines",
403ed0e5 872 NULL,
70244d1d 873 false,
c529695e 874 UID_INVALID,
70244d1d
LP
875 &m->manager->polkit_registry,
876 error);
877 if (r < 0)
878 return r;
879 if (r == 0)
880 return 1; /* Will call us back */
881
7f43928b
LP
882 r = machine_get_uid_shift(m, &uid);
883 if (r < 0)
884 return r;
885 if (uid != 0)
886 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied.");
887
90adaa25
LP
888 /* One day, when bind mounting /proc/self/fd/n works across
889 * namespace boundaries we should rework this logic to make
890 * use of it... */
891
892 p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
893 if (laccess(p, F_OK) < 0)
894 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
895
d3590ace
LP
896 r = chase_symlinks(src, NULL, 0, &chased_src);
897 if (r < 0)
898 return sd_bus_error_set_errnof(error, r, "Failed to resolve source path: %m");
899
900 if (lstat(chased_src, &st) < 0)
901 return sd_bus_error_set_errnof(error, errno, "Failed to stat() source path: %m");
902 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… */
903 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Source directory can't be a symbolic link");
904
90adaa25
LP
905 /* Our goal is to install a new bind mount into the container,
906 possibly read-only. This is irritatingly complex
907 unfortunately, currently.
908
909 First, we start by creating a private playground in /tmp,
910 that we can mount MS_SLAVE. (Which is necessary, since
ecb0573d 911 MS_MOVE cannot be applied to mounts with MS_SHARED parent
90adaa25
LP
912 mounts.) */
913
914 if (!mkdtemp(mount_slave))
915 return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
916
917 mount_slave_created = true;
918
919 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
920 r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
921 goto finish;
922 }
923
924 mount_slave_mounted = true;
925
926 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
927 r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
928 goto finish;
929 }
930
d3590ace 931 /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */
90adaa25 932 mount_tmp = strjoina(mount_slave, "/mount");
d3590ace
LP
933 if (S_ISDIR(st.st_mode))
934 r = mkdir(mount_tmp, 0700) < 0 ? -errno : 0;
935 else
936 r = touch(mount_tmp);
937 if (r < 0) {
938 sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
90adaa25
LP
939 goto finish;
940 }
941
942 mount_tmp_created = true;
943
d3590ace
LP
944 if (mount(chased_src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
945 r = sd_bus_error_set_errnof(error, errno, "Failed to mount %s: %m", chased_src);
90adaa25
LP
946 goto finish;
947 }
948
949 mount_tmp_mounted = true;
950
951 /* Third, we remount the new bind mount read-only if requested. */
952 if (read_only)
953 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
954 r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
955 goto finish;
956 }
957
d3590ace 958 /* Fourth, we move the new bind mount into the propagation directory. This way it will appear there read-only
90adaa25
LP
959 * right-away. */
960
961 mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
d3590ace
LP
962 if (S_ISDIR(st.st_mode))
963 r = mkdtemp(mount_outside) ? 0 : -errno;
964 else {
965 r = mkostemp_safe(mount_outside);
966 safe_close(r);
967 }
968 if (r < 0) {
969 sd_bus_error_set_errnof(error, errno, "Cannot create propagation file or directory %s: %m", mount_outside);
90adaa25
LP
970 goto finish;
971 }
972
973 mount_outside_created = true;
974
975 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
976 r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
977 goto finish;
978 }
979
980 mount_outside_mounted = true;
981 mount_tmp_mounted = false;
982
d3590ace
LP
983 if (S_ISDIR(st.st_mode))
984 (void) rmdir(mount_tmp);
985 else
986 (void) unlink(mount_tmp);
90adaa25
LP
987 mount_tmp_created = false;
988
989 (void) umount(mount_slave);
990 mount_slave_mounted = false;
991
992 (void) rmdir(mount_slave);
993 mount_slave_created = false;
994
995 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
996 r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
997 goto finish;
998 }
999
1000 child = fork();
1001 if (child < 0) {
1002 r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
1003 goto finish;
1004 }
1005
1006 if (child == 0) {
1007 const char *mount_inside;
1008 int mntfd;
1009 const char *q;
1010
1011 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1012
1013 q = procfs_file_alloca(m->leader, "ns/mnt");
1014 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1015 if (mntfd < 0) {
1016 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1017 goto child_fail;
1018 }
1019
1020 if (setns(mntfd, CLONE_NEWNS) < 0) {
1021 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1022 goto child_fail;
1023 }
1024
d3590ace
LP
1025 if (make_file_or_directory) {
1026 if (S_ISDIR(st.st_mode))
1027 (void) mkdir_p(dest, 0755);
1028 else {
1029 (void) mkdir_parents(dest, 0755);
1030 safe_close(open(dest, O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600));
1031 }
1032 }
90adaa25
LP
1033
1034 /* Fifth, move the mount to the right place inside */
1035 mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
1036 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
1037 r = log_error_errno(errno, "Failed to mount: %m");
1038 goto child_fail;
1039 }
1040
1041 _exit(EXIT_SUCCESS);
1042
1043 child_fail:
1044 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1045 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1046
1047 _exit(EXIT_FAILURE);
1048 }
1049
1050 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1051
1052 r = wait_for_terminate(child, &si);
1053 if (r < 0) {
c0ffce2b 1054 r = sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
90adaa25
LP
1055 goto finish;
1056 }
1057 if (si.si_code != CLD_EXITED) {
c0ffce2b 1058 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
90adaa25
LP
1059 goto finish;
1060 }
1061 if (si.si_status != EXIT_SUCCESS) {
1062
1063 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
c7abe32b 1064 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
90adaa25 1065 else
c0ffce2b 1066 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child failed.");
90adaa25
LP
1067 goto finish;
1068 }
1069
1070 r = sd_bus_reply_method_return(message, NULL);
1071
1072finish:
1073 if (mount_outside_mounted)
d3590ace
LP
1074 (void) umount(mount_outside);
1075 if (mount_outside_created) {
1076 if (S_ISDIR(st.st_mode))
1077 (void) rmdir(mount_outside);
1078 else
1079 (void) unlink(mount_outside);
1080 }
90adaa25
LP
1081
1082 if (mount_tmp_mounted)
d3590ace
LP
1083 (void) umount(mount_tmp);
1084 if (mount_tmp_created) {
1085 if (S_ISDIR(st.st_mode))
1086 (void) rmdir(mount_tmp);
1087 else
1088 (void) unlink(mount_tmp);
1089 }
90adaa25
LP
1090
1091 if (mount_slave_mounted)
d3590ace 1092 (void) umount(mount_slave);
90adaa25 1093 if (mount_slave_created)
d3590ace 1094 (void) rmdir(mount_slave);
90adaa25
LP
1095
1096 return r;
1097}
1098
19070062 1099int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
0370612e
LP
1100 const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
1101 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
d01cd401 1102 CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE;
0370612e
LP
1103 _cleanup_close_ int hostfd = -1;
1104 Machine *m = userdata;
0370612e
LP
1105 bool copy_from;
1106 pid_t child;
d01cd401 1107 uid_t uid_shift;
0370612e
LP
1108 char *t;
1109 int r;
1110
19070062
LP
1111 assert(message);
1112 assert(m);
1113
795c5d31 1114 if (m->manager->n_operations >= OPERATIONS_MAX)
0370612e
LP
1115 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
1116
1117 if (m->class != MACHINE_CONTAINER)
1118 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
1119
1120 r = sd_bus_message_read(message, "ss", &src, &dest);
1121 if (r < 0)
1122 return r;
1123
d8440176
RM
1124 if (!path_is_absolute(src))
1125 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
0370612e
LP
1126
1127 if (isempty(dest))
1128 dest = src;
d8440176
RM
1129 else if (!path_is_absolute(dest))
1130 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
0370612e 1131
70244d1d
LP
1132 r = bus_verify_polkit_async(
1133 message,
1134 CAP_SYS_ADMIN,
1135 "org.freedesktop.machine1.manage-machines",
403ed0e5 1136 NULL,
70244d1d 1137 false,
c529695e 1138 UID_INVALID,
70244d1d
LP
1139 &m->manager->polkit_registry,
1140 error);
1141 if (r < 0)
1142 return r;
1143 if (r == 0)
1144 return 1; /* Will call us back */
1145
d01cd401
LP
1146 r = machine_get_uid_shift(m, &uid_shift);
1147 if (r < 0)
1148 return r;
1149
0370612e
LP
1150 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
1151
1152 if (copy_from) {
1153 container_path = src;
1154 host_path = dest;
1155 } else {
1156 host_path = src;
1157 container_path = dest;
1158 }
1159
1160 host_basename = basename(host_path);
1161 t = strdupa(host_path);
1162 host_dirname = dirname(t);
1163
1164 container_basename = basename(container_path);
1165 t = strdupa(container_path);
1166 container_dirname = dirname(t);
1167
1168 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
858a109f 1169 if (hostfd < 0)
0370612e
LP
1170 return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
1171
1172 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
1173 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
1174
1175 child = fork();
1176 if (child < 0)
1177 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
1178
1179 if (child == 0) {
1180 int containerfd;
1181 const char *q;
1182 int mntfd;
1183
1184 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1185
1186 q = procfs_file_alloca(m->leader, "ns/mnt");
1187 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1188 if (mntfd < 0) {
1189 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1190 goto child_fail;
1191 }
1192
1193 if (setns(mntfd, CLONE_NEWNS) < 0) {
1194 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1195 goto child_fail;
1196 }
1197
1198 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1199 if (containerfd < 0) {
1200 r = log_error_errno(errno, "Failed top open destination directory: %m");
1201 goto child_fail;
1202 }
1203
d01cd401
LP
1204 /* Run the actual copy operation. Note that when an UID shift is set we'll either clamp the UID/GID to
1205 * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
1206 * the UID/GIDs as they are. */
0370612e 1207 if (copy_from)
d01cd401 1208 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 1209 else
d01cd401 1210 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
1211
1212 hostfd = safe_close(hostfd);
1213 containerfd = safe_close(containerfd);
1214
1215 if (r < 0) {
1216 r = log_error_errno(r, "Failed to copy tree: %m");
1217 goto child_fail;
1218 }
1219
1220 _exit(EXIT_SUCCESS);
1221
1222 child_fail:
1223 (void) write(errno_pipe_fd[1], &r, sizeof(r));
0370612e
LP
1224 _exit(EXIT_FAILURE);
1225 }
1226
1227 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1228
795c5d31 1229 /* Copying might take a while, hence install a watch on the child, and return */
0370612e 1230
03c2b288 1231 r = operation_new(m->manager, m, child, message, errno_pipe_fd[0], NULL);
0370612e 1232 if (r < 0) {
795c5d31
LP
1233 (void) sigkill_wait(child);
1234 return r;
0370612e 1235 }
795c5d31 1236 errno_pipe_fd[0] = -1;
0370612e
LP
1237
1238 return 1;
1239}
1240
ae203207
LP
1241int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1242 _cleanup_close_ int fd = -1;
1243 Machine *m = userdata;
1244 int r;
1245
1246 assert(message);
1247 assert(m);
1248
1249 r = bus_verify_polkit_async(
1250 message,
1251 CAP_SYS_ADMIN,
1252 "org.freedesktop.machine1.manage-machines",
1253 NULL,
1254 false,
1255 UID_INVALID,
1256 &m->manager->polkit_registry,
1257 error);
1258 if (r < 0)
1259 return r;
1260 if (r == 0)
1261 return 1; /* Will call us back */
1262
1263 switch (m->class) {
1264
1265 case MACHINE_HOST:
1266 fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1267 if (fd < 0)
1268 return -errno;
1269
1270 break;
1271
1272 case MACHINE_CONTAINER: {
1273 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
1274 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1275 siginfo_t si;
1276 pid_t child;
1277
1278 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
1279 if (r < 0)
1280 return r;
1281
1282 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1283 return -errno;
1284
1285 child = fork();
1286 if (child < 0)
1287 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
1288
1289 if (child == 0) {
1290 _cleanup_close_ int dfd = -1;
1291
1292 pair[0] = safe_close(pair[0]);
1293
1294 r = namespace_enter(-1, mntns_fd, -1, -1, root_fd);
1295 if (r < 0)
1296 _exit(EXIT_FAILURE);
1297
1298 dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1299 if (dfd < 0)
1300 _exit(EXIT_FAILURE);
1301
1302 r = send_one_fd(pair[1], dfd, 0);
1303 dfd = safe_close(dfd);
1304 if (r < 0)
1305 _exit(EXIT_FAILURE);
1306
1307 _exit(EXIT_SUCCESS);
1308 }
1309
1310 pair[1] = safe_close(pair[1]);
1311
1312 r = wait_for_terminate(child, &si);
1313 if (r < 0)
1314 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
1315 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1316 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
1317
1318 fd = receive_one_fd(pair[0], MSG_DONTWAIT);
1319 if (fd < 0)
1320 return fd;
1321
1322 break;
1323 }
1324
1325 default:
1326 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
1327 }
1328
1329 return sd_bus_reply_method_return(message, "h", fd);
1330}
1331
3401419b
LP
1332int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1333 Machine *m = userdata;
1334 uid_t shift = 0;
1335 int r;
1336
1337 assert(message);
1338 assert(m);
1339
1340 /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but
1341 * we kinda have to for this. */
1342
1343 if (m->class == MACHINE_HOST)
1344 return sd_bus_reply_method_return(message, "u", UINT32_C(0));
1345
1346 if (m->class != MACHINE_CONTAINER)
1347 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines.");
1348
1349 r = machine_get_uid_shift(m, &shift);
1350 if (r == -ENXIO)
1351 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m->name);
1352 if (r < 0)
1353 return r;
1354
1355 return sd_bus_reply_method_return(message, "u", (uint32_t) shift);
1356}
1357
c3350683
LP
1358const sd_bus_vtable machine_vtable[] = {
1359 SD_BUS_VTABLE_START(0),
556089dc 1360 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
766c94ad 1361 SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
1362 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1363 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
89f7c846
LP
1364 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
1365 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
556089dc
LP
1366 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
1367 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
1368 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
9b5ed6fe 1369 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
c3350683 1370 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
70244d1d
LP
1371 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
1372 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
0dd25fb9 1373 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 1374 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
3401419b 1375 SD_BUS_METHOD("GetUIDShift", NULL, "u", bus_machine_method_get_uid_shift, SD_BUS_VTABLE_UNPRIVILEGED),
fbe55073 1376 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, SD_BUS_VTABLE_UNPRIVILEGED),
d04c1fb8 1377 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
49af9e13 1378 SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell, SD_BUS_VTABLE_UNPRIVILEGED),
70244d1d
LP
1379 SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
1380 SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
1381 SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
ae203207 1382 SD_BUS_METHOD("OpenRootDirectory", NULL, "h", bus_machine_method_open_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 1383 SD_BUS_VTABLE_END
c3350683 1384};
9444b1f2 1385
f00c3121 1386int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
c3350683
LP
1387 Manager *m = userdata;
1388 Machine *machine;
927b1649 1389 int r;
9444b1f2 1390
c3350683
LP
1391 assert(bus);
1392 assert(path);
1393 assert(interface);
1394 assert(found);
1395 assert(m);
9444b1f2 1396
927b1649 1397 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
4afd3348 1398 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
927b1649
LP
1399 sd_bus_message *message;
1400 pid_t pid;
9444b1f2 1401
19befb2d 1402 message = sd_bus_get_current_message(bus);
927b1649
LP
1403 if (!message)
1404 return 0;
1405
5b12334d 1406 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
927b1649 1407 if (r < 0)
5b12334d
LP
1408 return r;
1409
1410 r = sd_bus_creds_get_pid(creds, &pid);
1411 if (r < 0)
1412 return r;
9444b1f2 1413
927b1649
LP
1414 r = manager_get_machine_by_pid(m, pid, &machine);
1415 if (r <= 0)
1416 return 0;
1417 } else {
1418 _cleanup_free_ char *e = NULL;
1419 const char *p;
1420
1421 p = startswith(path, "/org/freedesktop/machine1/machine/");
1422 if (!p)
1423 return 0;
1424
a6278b88 1425 e = bus_label_unescape(p);
927b1649
LP
1426 if (!e)
1427 return -ENOMEM;
1428
1429 machine = hashmap_get(m->machines, e);
1430 if (!machine)
1431 return 0;
1432 }
9444b1f2 1433
c3350683
LP
1434 *found = machine;
1435 return 1;
9444b1f2
LP
1436}
1437
9444b1f2
LP
1438char *machine_bus_path(Machine *m) {
1439 _cleanup_free_ char *e = NULL;
1440
1441 assert(m);
1442
a6278b88 1443 e = bus_label_escape(m->name);
9444b1f2
LP
1444 if (!e)
1445 return NULL;
1446
1ee306e1 1447 return strappend("/org/freedesktop/machine1/machine/", e);
9444b1f2
LP
1448}
1449
f00c3121 1450int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
927b1649
LP
1451 _cleanup_strv_free_ char **l = NULL;
1452 Machine *machine = NULL;
1453 Manager *m = userdata;
1454 Iterator i;
1455 int r;
1456
1457 assert(bus);
1458 assert(path);
1459 assert(nodes);
1460
1461 HASHMAP_FOREACH(machine, m->machines, i) {
1462 char *p;
1463
1464 p = machine_bus_path(machine);
1465 if (!p)
1466 return -ENOMEM;
1467
6e18964d
ZJS
1468 r = strv_consume(&l, p);
1469 if (r < 0)
927b1649 1470 return r;
927b1649
LP
1471 }
1472
1473 *nodes = l;
1474 l = NULL;
1475
1476 return 1;
1477}
1478
9444b1f2 1479int machine_send_signal(Machine *m, bool new_machine) {
9444b1f2
LP
1480 _cleanup_free_ char *p = NULL;
1481
1482 assert(m);
1483
9444b1f2
LP
1484 p = machine_bus_path(m);
1485 if (!p)
1486 return -ENOMEM;
1487
c3350683
LP
1488 return sd_bus_emit_signal(
1489 m->manager->bus,
1490 "/org/freedesktop/machine1",
1491 "org.freedesktop.machine1.Manager",
1492 new_machine ? "MachineNew" : "MachineRemoved",
1493 "so", m->name, p);
9444b1f2
LP
1494}
1495
c3350683 1496int machine_send_create_reply(Machine *m, sd_bus_error *error) {
4afd3348 1497 _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
9444b1f2
LP
1498 _cleanup_free_ char *p = NULL;
1499
1500 assert(m);
1501
fb6becb4
LP
1502 if (!m->create_message)
1503 return 0;
1504
c3350683
LP
1505 c = m->create_message;
1506 m->create_message = NULL;
fb6becb4 1507
a658cafa 1508 if (error)
df2d202e 1509 return sd_bus_reply_method_error(c, error);
a658cafa 1510
76e66585
LP
1511 /* Update the machine state file before we notify the client
1512 * about the result. */
1513 machine_save(m);
1514
c3350683
LP
1515 p = machine_bus_path(m);
1516 if (!p)
1517 return -ENOMEM;
fb6becb4 1518
df2d202e 1519 return sd_bus_reply_method_return(c, "o", p);
fb6becb4 1520}