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