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