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