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