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