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