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