]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machine-dbus.c
core: allow setting WorkingDirectory= to the special value ~
[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)
c0ffce2b 356 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
fbe55073 357 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
c0ffce2b 358 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
fbe55073 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)
c0ffce2b 447 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
fbe55073 448 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
c0ffce2b 449 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child 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,
5f5d8eab 738 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
49af9e13
LP
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",
5f5d8eab
LP
751 "PAMName", "s", "login",
752 "WorkingDirectory", "s", "-~");
49af9e13
LP
753 if (r < 0)
754 return r;
755
756 r = sd_bus_message_append(tm, "(sv)", "User", "s", isempty(user) ? "root" : user);
757 if (r < 0)
758 return r;
759
760 if (!strv_isempty(env)) {
761 r = sd_bus_message_open_container(tm, 'r', "sv");
762 if (r < 0)
763 return r;
764
765 r = sd_bus_message_append(tm, "s", "Environment");
766 if (r < 0)
767 return r;
768
769 r = sd_bus_message_open_container(tm, 'v', "as");
770 if (r < 0)
771 return r;
772
773 r = sd_bus_message_append_strv(tm, env);
774 if (r < 0)
775 return r;
776
777 r = sd_bus_message_close_container(tm);
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
786 /* Exec container */
787 r = sd_bus_message_open_container(tm, 'r', "sv");
788 if (r < 0)
789 return r;
790
791 r = sd_bus_message_append(tm, "s", "ExecStart");
792 if (r < 0)
793 return r;
794
795 r = sd_bus_message_open_container(tm, 'v', "a(sasb)");
796 if (r < 0)
797 return r;
798
799 r = sd_bus_message_open_container(tm, 'a', "(sasb)");
800 if (r < 0)
801 return r;
802
803 r = sd_bus_message_open_container(tm, 'r', "sasb");
804 if (r < 0)
805 return r;
806
807 r = sd_bus_message_append(tm, "s", path);
808 if (r < 0)
809 return r;
810
811 r = sd_bus_message_append_strv(tm, args);
812 if (r < 0)
813 return r;
814
815 r = sd_bus_message_append(tm, "b", true);
816 if (r < 0)
817 return r;
818
819 r = sd_bus_message_close_container(tm);
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 /* Auxiliary units */
840 r = sd_bus_message_append(tm, "a(sa(sv))", 0);
841 if (r < 0)
842 return r;
843
844 r = sd_bus_call(container_bus, tm, 0, error, NULL);
ee451d76
LP
845 if (r < 0)
846 return r;
847
40205d70
LP
848 r = sd_bus_message_new_method_return(message, &reply);
849 if (r < 0)
850 return r;
851
ee451d76 852 r = sd_bus_message_append(reply, "hs", master, pty_name);
40205d70
LP
853 if (r < 0)
854 return r;
717603e3 855
9030ca46 856 return sd_bus_send(NULL, reply, NULL);
717603e3
LP
857}
858
19070062 859int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
90adaa25
LP
860 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
861 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
862 bool mount_slave_created = false, mount_slave_mounted = false,
863 mount_tmp_created = false, mount_tmp_mounted = false,
864 mount_outside_created = false, mount_outside_mounted = false;
865 const char *dest, *src;
866 Machine *m = userdata;
867 int read_only, make_directory;
868 pid_t child;
869 siginfo_t si;
870 int r;
871
19070062
LP
872 assert(message);
873 assert(m);
874
90adaa25
LP
875 if (m->class != MACHINE_CONTAINER)
876 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
877
878 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_directory);
879 if (r < 0)
880 return r;
881
882 if (!path_is_absolute(src) || !path_is_safe(src))
883 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
884
885 if (isempty(dest))
886 dest = src;
887 else if (!path_is_absolute(dest) || !path_is_safe(dest))
c7abe32b 888 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
90adaa25 889
70244d1d
LP
890 r = bus_verify_polkit_async(
891 message,
892 CAP_SYS_ADMIN,
893 "org.freedesktop.machine1.manage-machines",
403ed0e5 894 NULL,
70244d1d 895 false,
c529695e 896 UID_INVALID,
70244d1d
LP
897 &m->manager->polkit_registry,
898 error);
899 if (r < 0)
900 return r;
901 if (r == 0)
902 return 1; /* Will call us back */
903
90adaa25
LP
904 /* One day, when bind mounting /proc/self/fd/n works across
905 * namespace boundaries we should rework this logic to make
906 * use of it... */
907
908 p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
909 if (laccess(p, F_OK) < 0)
910 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
911
912 /* Our goal is to install a new bind mount into the container,
913 possibly read-only. This is irritatingly complex
914 unfortunately, currently.
915
916 First, we start by creating a private playground in /tmp,
917 that we can mount MS_SLAVE. (Which is necessary, since
918 MS_MOUNT cannot be applied to mounts with MS_SHARED parent
919 mounts.) */
920
921 if (!mkdtemp(mount_slave))
922 return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
923
924 mount_slave_created = true;
925
926 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
927 r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
928 goto finish;
929 }
930
931 mount_slave_mounted = true;
932
933 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
934 r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
935 goto finish;
936 }
937
938 /* Second, we mount the source directory to a directory inside
939 of our MS_SLAVE playground. */
940 mount_tmp = strjoina(mount_slave, "/mount");
941 if (mkdir(mount_tmp, 0700) < 0) {
942 r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
943 goto finish;
944 }
945
946 mount_tmp_created = true;
947
948 if (mount(src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
949 r = sd_bus_error_set_errnof(error, errno, "Failed to overmount %s: %m", mount_tmp);
950 goto finish;
951 }
952
953 mount_tmp_mounted = true;
954
955 /* Third, we remount the new bind mount read-only if requested. */
956 if (read_only)
957 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
958 r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
959 goto finish;
960 }
961
962 /* Fourth, we move the new bind mount into the propagation
963 * directory. This way it will appear there read-only
964 * right-away. */
965
966 mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
967 if (!mkdtemp(mount_outside)) {
968 r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
969 goto finish;
970 }
971
972 mount_outside_created = true;
973
974 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
975 r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
976 goto finish;
977 }
978
979 mount_outside_mounted = true;
980 mount_tmp_mounted = false;
981
982 (void) rmdir(mount_tmp);
983 mount_tmp_created = false;
984
985 (void) umount(mount_slave);
986 mount_slave_mounted = false;
987
988 (void) rmdir(mount_slave);
989 mount_slave_created = false;
990
991 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
992 r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
993 goto finish;
994 }
995
996 child = fork();
997 if (child < 0) {
998 r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
999 goto finish;
1000 }
1001
1002 if (child == 0) {
1003 const char *mount_inside;
1004 int mntfd;
1005 const char *q;
1006
1007 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1008
1009 q = procfs_file_alloca(m->leader, "ns/mnt");
1010 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1011 if (mntfd < 0) {
1012 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1013 goto child_fail;
1014 }
1015
1016 if (setns(mntfd, CLONE_NEWNS) < 0) {
1017 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1018 goto child_fail;
1019 }
1020
1021 if (make_directory)
1022 (void) mkdir_p(dest, 0755);
1023
1024 /* Fifth, move the mount to the right place inside */
1025 mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
1026 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
1027 r = log_error_errno(errno, "Failed to mount: %m");
1028 goto child_fail;
1029 }
1030
1031 _exit(EXIT_SUCCESS);
1032
1033 child_fail:
1034 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1035 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1036
1037 _exit(EXIT_FAILURE);
1038 }
1039
1040 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1041
1042 r = wait_for_terminate(child, &si);
1043 if (r < 0) {
c0ffce2b 1044 r = sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
90adaa25
LP
1045 goto finish;
1046 }
1047 if (si.si_code != CLD_EXITED) {
c0ffce2b 1048 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
90adaa25
LP
1049 goto finish;
1050 }
1051 if (si.si_status != EXIT_SUCCESS) {
1052
1053 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
c7abe32b 1054 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
90adaa25 1055 else
c0ffce2b 1056 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child failed.");
90adaa25
LP
1057 goto finish;
1058 }
1059
1060 r = sd_bus_reply_method_return(message, NULL);
1061
1062finish:
1063 if (mount_outside_mounted)
1064 umount(mount_outside);
1065 if (mount_outside_created)
1066 rmdir(mount_outside);
1067
1068 if (mount_tmp_mounted)
1069 umount(mount_tmp);
1070 if (mount_tmp_created)
1071 rmdir(mount_tmp);
1072
1073 if (mount_slave_mounted)
1074 umount(mount_slave);
1075 if (mount_slave_created)
1076 rmdir(mount_slave);
1077
1078 return r;
1079}
1080
0370612e
LP
1081static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
1082 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1083 MachineOperation *o = userdata;
1084 int r;
1085
1086 assert(o);
1087 assert(si);
1088
1089 o->pid = 0;
1090
1091 if (si->si_code != CLD_EXITED) {
c0ffce2b 1092 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
0370612e
LP
1093 goto fail;
1094 }
1095
1096 if (si->si_status != EXIT_SUCCESS) {
1097 if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
1098 r = sd_bus_error_set_errnof(&error, r, "%m");
1099 else
c0ffce2b 1100 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
0370612e
LP
1101
1102 goto fail;
1103 }
1104
1105 r = sd_bus_reply_method_return(o->message, NULL);
1106 if (r < 0)
1107 log_error_errno(r, "Failed to reply to message: %m");
1108
1109 machine_operation_unref(o);
1110 return 0;
1111
1112fail:
1113 r = sd_bus_reply_method_error(o->message, &error);
1114 if (r < 0)
1115 log_error_errno(r, "Failed to reply to message: %m");
1116
1117 machine_operation_unref(o);
1118 return 0;
1119}
1120
19070062 1121int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
0370612e
LP
1122 const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
1123 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
1124 _cleanup_close_ int hostfd = -1;
1125 Machine *m = userdata;
1126 MachineOperation *o;
1127 bool copy_from;
1128 pid_t child;
1129 char *t;
1130 int r;
1131
19070062
LP
1132 assert(message);
1133 assert(m);
1134
0370612e
LP
1135 if (m->n_operations >= MACHINE_OPERATIONS_MAX)
1136 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
1137
1138 if (m->class != MACHINE_CONTAINER)
1139 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
1140
1141 r = sd_bus_message_read(message, "ss", &src, &dest);
1142 if (r < 0)
1143 return r;
1144
d8440176
RM
1145 if (!path_is_absolute(src))
1146 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
0370612e
LP
1147
1148 if (isempty(dest))
1149 dest = src;
d8440176
RM
1150 else if (!path_is_absolute(dest))
1151 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
0370612e 1152
70244d1d
LP
1153 r = bus_verify_polkit_async(
1154 message,
1155 CAP_SYS_ADMIN,
1156 "org.freedesktop.machine1.manage-machines",
403ed0e5 1157 NULL,
70244d1d 1158 false,
c529695e 1159 UID_INVALID,
70244d1d
LP
1160 &m->manager->polkit_registry,
1161 error);
1162 if (r < 0)
1163 return r;
1164 if (r == 0)
1165 return 1; /* Will call us back */
1166
0370612e
LP
1167 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
1168
1169 if (copy_from) {
1170 container_path = src;
1171 host_path = dest;
1172 } else {
1173 host_path = src;
1174 container_path = dest;
1175 }
1176
1177 host_basename = basename(host_path);
1178 t = strdupa(host_path);
1179 host_dirname = dirname(t);
1180
1181 container_basename = basename(container_path);
1182 t = strdupa(container_path);
1183 container_dirname = dirname(t);
1184
1185 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
858a109f 1186 if (hostfd < 0)
0370612e
LP
1187 return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
1188
1189 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
1190 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
1191
1192 child = fork();
1193 if (child < 0)
1194 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
1195
1196 if (child == 0) {
1197 int containerfd;
1198 const char *q;
1199 int mntfd;
1200
1201 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1202
1203 q = procfs_file_alloca(m->leader, "ns/mnt");
1204 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1205 if (mntfd < 0) {
1206 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1207 goto child_fail;
1208 }
1209
1210 if (setns(mntfd, CLONE_NEWNS) < 0) {
1211 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1212 goto child_fail;
1213 }
1214
1215 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1216 if (containerfd < 0) {
1217 r = log_error_errno(errno, "Failed top open destination directory: %m");
1218 goto child_fail;
1219 }
1220
1221 if (copy_from)
1222 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
1223 else
1224 r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
1225
1226 hostfd = safe_close(hostfd);
1227 containerfd = safe_close(containerfd);
1228
1229 if (r < 0) {
1230 r = log_error_errno(r, "Failed to copy tree: %m");
1231 goto child_fail;
1232 }
1233
1234 _exit(EXIT_SUCCESS);
1235
1236 child_fail:
1237 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1238 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1239
1240 _exit(EXIT_FAILURE);
1241 }
1242
1243 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1244
1245 /* Copying might take a while, hence install a watch the
1246 * child, and return */
1247
1248 o = new0(MachineOperation, 1);
1249 if (!o)
1250 return log_oom();
1251
1252 o->pid = child;
1253 o->message = sd_bus_message_ref(message);
1254 o->errno_fd = errno_pipe_fd[0];
1255 errno_pipe_fd[0] = -1;
1256
1257 r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
1258 if (r < 0) {
1259 machine_operation_unref(o);
1260 return log_oom();
1261 }
1262
1263 LIST_PREPEND(operations, m->operations, o);
1264 m->n_operations++;
1265 o->machine = m;
1266
1267 return 1;
1268}
1269
c3350683
LP
1270const sd_bus_vtable machine_vtable[] = {
1271 SD_BUS_VTABLE_START(0),
556089dc
LP
1272 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
1273 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1274 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1275 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
89f7c846
LP
1276 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
1277 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
556089dc
LP
1278 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
1279 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
1280 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
9b5ed6fe 1281 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
c3350683 1282 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
70244d1d
LP
1283 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
1284 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
0dd25fb9 1285 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 1286 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
fbe55073 1287 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, SD_BUS_VTABLE_UNPRIVILEGED),
d04c1fb8 1288 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
49af9e13 1289 SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell, SD_BUS_VTABLE_UNPRIVILEGED),
70244d1d
LP
1290 SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
1291 SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
1292 SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 1293 SD_BUS_VTABLE_END
c3350683 1294};
9444b1f2 1295
f00c3121 1296int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
c3350683
LP
1297 Manager *m = userdata;
1298 Machine *machine;
927b1649 1299 int r;
9444b1f2 1300
c3350683
LP
1301 assert(bus);
1302 assert(path);
1303 assert(interface);
1304 assert(found);
1305 assert(m);
9444b1f2 1306
927b1649 1307 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
5b12334d 1308 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
927b1649
LP
1309 sd_bus_message *message;
1310 pid_t pid;
9444b1f2 1311
19befb2d 1312 message = sd_bus_get_current_message(bus);
927b1649
LP
1313 if (!message)
1314 return 0;
1315
5b12334d 1316 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
927b1649 1317 if (r < 0)
5b12334d
LP
1318 return r;
1319
1320 r = sd_bus_creds_get_pid(creds, &pid);
1321 if (r < 0)
1322 return r;
9444b1f2 1323
927b1649
LP
1324 r = manager_get_machine_by_pid(m, pid, &machine);
1325 if (r <= 0)
1326 return 0;
1327 } else {
1328 _cleanup_free_ char *e = NULL;
1329 const char *p;
1330
1331 p = startswith(path, "/org/freedesktop/machine1/machine/");
1332 if (!p)
1333 return 0;
1334
a6278b88 1335 e = bus_label_unescape(p);
927b1649
LP
1336 if (!e)
1337 return -ENOMEM;
1338
1339 machine = hashmap_get(m->machines, e);
1340 if (!machine)
1341 return 0;
1342 }
9444b1f2 1343
c3350683
LP
1344 *found = machine;
1345 return 1;
9444b1f2
LP
1346}
1347
9444b1f2
LP
1348char *machine_bus_path(Machine *m) {
1349 _cleanup_free_ char *e = NULL;
1350
1351 assert(m);
1352
a6278b88 1353 e = bus_label_escape(m->name);
9444b1f2
LP
1354 if (!e)
1355 return NULL;
1356
1ee306e1 1357 return strappend("/org/freedesktop/machine1/machine/", e);
9444b1f2
LP
1358}
1359
f00c3121 1360int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
927b1649
LP
1361 _cleanup_strv_free_ char **l = NULL;
1362 Machine *machine = NULL;
1363 Manager *m = userdata;
1364 Iterator i;
1365 int r;
1366
1367 assert(bus);
1368 assert(path);
1369 assert(nodes);
1370
1371 HASHMAP_FOREACH(machine, m->machines, i) {
1372 char *p;
1373
1374 p = machine_bus_path(machine);
1375 if (!p)
1376 return -ENOMEM;
1377
6e18964d
ZJS
1378 r = strv_consume(&l, p);
1379 if (r < 0)
927b1649 1380 return r;
927b1649
LP
1381 }
1382
1383 *nodes = l;
1384 l = NULL;
1385
1386 return 1;
1387}
1388
9444b1f2 1389int machine_send_signal(Machine *m, bool new_machine) {
9444b1f2
LP
1390 _cleanup_free_ char *p = NULL;
1391
1392 assert(m);
1393
9444b1f2
LP
1394 p = machine_bus_path(m);
1395 if (!p)
1396 return -ENOMEM;
1397
c3350683
LP
1398 return sd_bus_emit_signal(
1399 m->manager->bus,
1400 "/org/freedesktop/machine1",
1401 "org.freedesktop.machine1.Manager",
1402 new_machine ? "MachineNew" : "MachineRemoved",
1403 "so", m->name, p);
9444b1f2
LP
1404}
1405
c3350683
LP
1406int machine_send_create_reply(Machine *m, sd_bus_error *error) {
1407 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
9444b1f2
LP
1408 _cleanup_free_ char *p = NULL;
1409
1410 assert(m);
1411
fb6becb4
LP
1412 if (!m->create_message)
1413 return 0;
1414
c3350683
LP
1415 c = m->create_message;
1416 m->create_message = NULL;
fb6becb4 1417
a658cafa 1418 if (error)
df2d202e 1419 return sd_bus_reply_method_error(c, error);
a658cafa 1420
76e66585
LP
1421 /* Update the machine state file before we notify the client
1422 * about the result. */
1423 machine_save(m);
1424
c3350683
LP
1425 p = machine_bus_path(m);
1426 if (!p)
1427 return -ENOMEM;
fb6becb4 1428
df2d202e 1429 return sd_bus_reply_method_return(c, "o", p);
fb6becb4 1430}