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