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