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