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