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