]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machine-dbus.c
Merge pull request #2644 from 0xAX/check-alloc-overflow-macro
[thirdparty/systemd.git] / src / machine / machine-dbus.c
CommitLineData
9444b1f2
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2011 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <errno.h>
21#include <string.h>
90adaa25 22#include <sys/mount.h>
9444b1f2 23
0370612e 24/* When we include libgen.h because we need dirname() we immediately
11c9f1e4
SM
25 * undefine basename() since libgen.h defines it as a macro to the POSIX
26 * version which is really broken. We prefer GNU basename(). */
0370612e
LP
27#include <libgen.h>
28#undef basename
29
b5efdb8a 30#include "alloc-util.h"
96aad8d1 31#include "bus-common-errors.h"
3ffd4af2
LP
32#include "bus-internal.h"
33#include "bus-label.h"
34#include "bus-util.h"
717603e3 35#include "copy.h"
3ffd4af2
LP
36#include "env-util.h"
37#include "fd-util.h"
717603e3 38#include "fileio.h"
3ffd4af2 39#include "formats-util.h"
f4f15635 40#include "fs-util.h"
3b653205 41#include "in-addr-util.h"
496a5a69 42#include "local-addresses.h"
003dffde 43#include "machine-dbus.h"
3ffd4af2
LP
44#include "machine.h"
45#include "mkdir.h"
46#include "path-util.h"
0b452006 47#include "process-util.h"
3ffd4af2 48#include "strv.h"
a07c35c3 49#include "terminal-util.h"
ee104e11 50#include "user-util.h"
9444b1f2 51
c3350683
LP
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,
ebcf1f97
LP
58 void *userdata,
59 sd_bus_error *error) {
9444b1f2 60
c3350683 61 Machine *m = userdata;
9444b1f2 62
c3350683
LP
63 assert(bus);
64 assert(reply);
65 assert(m);
66
0f826101 67 return sd_bus_message_append_array(reply, 'y', &m->id, 16);
9444b1f2
LP
68}
69
c3350683
LP
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,
ebcf1f97
LP
76 void *userdata,
77 sd_bus_error *error) {
c3350683
LP
78
79 Machine *m = userdata;
fb6becb4 80 const char *state;
c3350683 81 int r;
fb6becb4 82
c3350683
LP
83 assert(bus);
84 assert(reply);
fb6becb4
LP
85 assert(m);
86
87 state = machine_state_to_string(machine_get_state(m));
88
c3350683
LP
89 r = sd_bus_message_append_basic(reply, 's', state);
90 if (r < 0)
91 return r;
fb6becb4 92
c3350683 93 return 1;
fb6becb4
LP
94}
95
9b5ed6fe
LP
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;
9b5ed6fe
LP
106
107 assert(bus);
108 assert(reply);
109 assert(m);
110
111 assert_cc(sizeof(int) == sizeof(int32_t));
112
0f826101 113 return sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
9b5ed6fe
LP
114}
115
c3350683 116static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
9444b1f2 117
19070062 118int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
119 Machine *m = userdata;
120 int r;
9444b1f2 121
c3350683
LP
122 assert(message);
123 assert(m);
9444b1f2 124
70244d1d
LP
125 r = bus_verify_polkit_async(
126 message,
127 CAP_KILL,
128 "org.freedesktop.machine1.manage-machines",
403ed0e5 129 NULL,
70244d1d 130 false,
c529695e 131 UID_INVALID,
70244d1d
LP
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
c3350683
LP
139 r = machine_stop(m);
140 if (r < 0)
ebcf1f97 141 return r;
9444b1f2 142
df2d202e 143 return sd_bus_reply_method_return(message, NULL);
9444b1f2
LP
144}
145
19070062 146int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
147 Machine *m = userdata;
148 const char *swho;
149 int32_t signo;
150 KillWho who;
9444b1f2
LP
151 int r;
152
9444b1f2 153 assert(message);
c3350683 154 assert(m);
9444b1f2 155
c3350683
LP
156 r = sd_bus_message_read(message, "si", &swho, &signo);
157 if (r < 0)
ebcf1f97 158 return r;
9444b1f2 159
c3350683
LP
160 if (isempty(swho))
161 who = KILL_ALL;
162 else {
163 who = kill_who_from_string(swho);
164 if (who < 0)
ebcf1f97 165 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
9444b1f2
LP
166 }
167
c3350683 168 if (signo <= 0 || signo >= _NSIG)
ebcf1f97 169 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
9444b1f2 170
70244d1d
LP
171 r = bus_verify_polkit_async(
172 message,
173 CAP_KILL,
174 "org.freedesktop.machine1.manage-machines",
403ed0e5 175 NULL,
70244d1d 176 false,
c529695e 177 UID_INVALID,
70244d1d
LP
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
c3350683
LP
185 r = machine_kill(m, who, signo);
186 if (r < 0)
ebcf1f97 187 return r;
9444b1f2 188
df2d202e 189 return sd_bus_reply_method_return(message, NULL);
9444b1f2
LP
190}
191
19070062 192int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 193 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
878cd7e9 194 Machine *m = userdata;
878cd7e9
LP
195 int r;
196
878cd7e9
LP
197 assert(message);
198 assert(m);
199
fbe55073 200 r = sd_bus_message_new_method_return(message, &reply);
878cd7e9 201 if (r < 0)
c7abe32b 202 return r;
878cd7e9 203
fbe55073 204 r = sd_bus_message_open_container(reply, 'a', "(iay)");
878cd7e9 205 if (r < 0)
c7abe32b 206 return r;
878cd7e9 207
fbe55073 208 switch (m->class) {
878cd7e9 209
fbe55073 210 case MACHINE_HOST: {
496a5a69
LP
211 _cleanup_free_ struct local_address *addresses = NULL;
212 struct local_address *a;
fbe55073 213 int n, i;
878cd7e9 214
1d050e1e 215 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
496a5a69 216 if (n < 0)
fbe55073 217 return n;
878cd7e9 218
496a5a69 219 for (a = addresses, i = 0; i < n; a++, i++) {
878cd7e9 220
fbe55073 221 r = sd_bus_message_open_container(reply, 'r', "iay");
878cd7e9 222 if (r < 0)
fbe55073 223 return r;
496a5a69 224
fbe55073
LP
225 r = sd_bus_message_append(reply, "i", addresses[i].family);
226 if (r < 0)
227 return r;
878cd7e9 228
fbe55073
LP
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;
878cd7e9 232
fbe55073
LP
233 r = sd_bus_message_close_container(reply);
234 if (r < 0)
235 return r;
236 }
878cd7e9 237
fbe55073
LP
238 break;
239 }
878cd7e9 240
fbe55073
LP
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;
878cd7e9 248
fbe55073
LP
249 r = readlink_malloc("/proc/self/ns/net", &us);
250 if (r < 0)
251 return r;
878cd7e9 252
fbe55073
LP
253 p = procfs_file_alloca(m->leader, "ns/net");
254 r = readlink_malloc(p, &them);
878cd7e9 255 if (r < 0)
c7abe32b 256 return r;
878cd7e9 257
fbe55073
LP
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);
878cd7e9 262 if (r < 0)
c7abe32b 263 return r;
878cd7e9 264
fbe55073
LP
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);
282
283 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
284 if (n < 0)
285 _exit(EXIT_FAILURE);
878cd7e9 286
fbe55073
LP
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 };
878cd7e9 292
fbe55073
LP
293 r = writev(pair[1], iov, 2);
294 if (r < 0)
295 _exit(EXIT_FAILURE);
296 }
878cd7e9 297
fbe55073 298 pair[1] = safe_close(pair[1]);
878cd7e9 299
fbe55073 300 _exit(EXIT_SUCCESS);
878cd7e9 301 }
878cd7e9 302
fbe55073
LP
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);
878cd7e9 357 if (r < 0)
c0ffce2b 358 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
fbe55073 359 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
c0ffce2b 360 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
fbe55073 361 break;
878cd7e9
LP
362 }
363
fbe55073
LP
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 }
878cd7e9
LP
367
368 r = sd_bus_message_close_container(reply);
369 if (r < 0)
c7abe32b 370 return r;
878cd7e9 371
9030ca46 372 return sd_bus_send(NULL, reply, NULL);
878cd7e9
LP
373}
374
19070062 375int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 376 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
717603e3 377 _cleanup_strv_free_ char **l = NULL;
717603e3
LP
378 Machine *m = userdata;
379 char **k, **v;
717603e3
LP
380 int r;
381
717603e3
LP
382 assert(message);
383 assert(m);
384
fbe55073 385 switch (m->class) {
b4d8ef7c 386
fbe55073
LP
387 case MACHINE_HOST:
388 r = load_env_file_pairs(NULL, "/etc/os-release", NULL, &l);
389 if (r < 0)
390 return r;
717603e3 391
fbe55073 392 break;
717603e3 393
fbe55073
LP
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;
717603e3 400
fbe55073
LP
401 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
402 if (r < 0)
403 return r;
717603e3 404
fbe55073
LP
405 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
406 return -errno;
717603e3 407
fbe55073
LP
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]);
416
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 }
717603e3 427
59f448cf 428 r = copy_bytes(fd, pair[1], (uint64_t) -1, false);
fbe55073 429 if (r < 0)
717603e3 430 _exit(EXIT_FAILURE);
fbe55073
LP
431
432 _exit(EXIT_SUCCESS);
717603e3
LP
433 }
434
fbe55073 435 pair[1] = safe_close(pair[1]);
717603e3 436
fbe55073
LP
437 f = fdopen(pair[0], "re");
438 if (!f)
439 return -errno;
717603e3 440
fbe55073 441 pair[0] = -1;
717603e3 442
fbe55073
LP
443 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
444 if (r < 0)
445 return r;
717603e3 446
fbe55073
LP
447 r = wait_for_terminate(child, &si);
448 if (r < 0)
c0ffce2b 449 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
fbe55073 450 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
c0ffce2b 451 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
717603e3 452
fbe55073
LP
453 break;
454 }
717603e3 455
fbe55073
LP
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 }
717603e3
LP
459
460 r = sd_bus_message_new_method_return(message, &reply);
461 if (r < 0)
40205d70 462 return r;
717603e3
LP
463
464 r = sd_bus_message_open_container(reply, 'a', "{ss}");
465 if (r < 0)
40205d70 466 return r;
717603e3
LP
467
468 STRV_FOREACH_PAIR(k, v, l) {
469 r = sd_bus_message_append(reply, "{ss}", *k, *v);
470 if (r < 0)
40205d70 471 return r;
717603e3
LP
472 }
473
474 r = sd_bus_message_close_container(reply);
475 if (r < 0)
40205d70
LP
476 return r;
477
9030ca46 478 return sd_bus_send(NULL, reply, NULL);
40205d70
LP
479}
480
19070062 481int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 482 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
5f8cc96a 483 _cleanup_free_ char *pty_name = NULL;
40205d70 484 _cleanup_close_ int master = -1;
40205d70 485 Machine *m = userdata;
40205d70
LP
486 int r;
487
40205d70
LP
488 assert(message);
489 assert(m);
490
fbe55073
LP
491 r = bus_verify_polkit_async(
492 message,
493 CAP_SYS_ADMIN,
4289c3a7 494 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty",
403ed0e5 495 NULL,
fbe55073
LP
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 */
b4d8ef7c 504
fbe55073 505 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
5f8cc96a
LP
506 if (master < 0)
507 return master;
508
a07c35c3 509 r = ptsname_namespace(master, &pty_name);
40205d70
LP
510 if (r < 0)
511 return r;
512
5f8cc96a
LP
513 r = sd_bus_message_new_method_return(message, &reply);
514 if (r < 0)
515 return r;
40205d70 516
5f8cc96a
LP
517 r = sd_bus_message_append(reply, "hs", master, pty_name);
518 if (r < 0)
519 return r;
40205d70 520
9030ca46 521 return sd_bus_send(NULL, reply, NULL);
5f8cc96a 522}
40205d70 523
385080c0 524static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) {
49af9e13
LP
525 int r;
526
527 assert(m);
528 assert(ret);
529
fbe55073 530 switch (m->class) {
49af9e13 531
fbe55073
LP
532 case MACHINE_HOST:
533 *ret = NULL;
534 break;
49af9e13 535
fbe55073 536 case MACHINE_CONTAINER: {
4afd3348 537 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
fbe55073 538 char *address;
49af9e13 539
fbe55073
LP
540 r = sd_bus_new(&bus);
541 if (r < 0)
542 return r;
49af9e13 543
fbe55073
LP
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);
385080c0
LP
553 if (r == -ENOENT)
554 return sd_bus_error_set_errnof(error, r, "There is no system bus in container %s.", m->name);
fbe55073
LP
555 if (r < 0)
556 return r;
557
558 *ret = bus;
559 bus = NULL;
560 break;
561 }
562
563 default:
564 return -EOPNOTSUPP;
565 }
49af9e13
LP
566
567 return 0;
568}
569
19070062 570int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 571 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
49af9e13 572 _cleanup_free_ char *pty_name = NULL;
4afd3348 573 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
5f8cc96a 574 _cleanup_close_ int master = -1;
fbe55073 575 sd_bus *container_bus = NULL;
5f8cc96a 576 Machine *m = userdata;
49af9e13 577 const char *p, *getty;
5f8cc96a 578 int r;
40205d70 579
19070062
LP
580 assert(message);
581 assert(m);
582
d04c1fb8
LP
583 r = bus_verify_polkit_async(
584 message,
585 CAP_SYS_ADMIN,
4289c3a7 586 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
403ed0e5 587 NULL,
d04c1fb8 588 false,
c529695e 589 UID_INVALID,
d04c1fb8
LP
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
fbe55073 597 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
5f8cc96a
LP
598 if (master < 0)
599 return master;
40205d70 600
a07c35c3 601 r = ptsname_namespace(master, &pty_name);
40205d70
LP
602 if (r < 0)
603 return r;
40205d70 604
5f8cc96a
LP
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);
40205d70 608
385080c0 609 r = container_bus_new(m, error, &allocated_bus);
5f8cc96a
LP
610 if (r < 0)
611 return r;
40205d70 612
fbe55073
LP
613 container_bus = allocated_bus ?: m->manager->bus;
614
49af9e13
LP
615 getty = strjoina("container-getty@", p, ".service");
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
49af9e13
LP
628 r = sd_bus_message_new_method_return(message, &reply);
629 if (r < 0)
630 return r;
40205d70 631
49af9e13 632 r = sd_bus_message_append(reply, "hs", master, pty_name);
5f8cc96a
LP
633 if (r < 0)
634 return r;
40205d70 635
49af9e13
LP
636 return sd_bus_send(NULL, reply, NULL);
637}
5f8cc96a 638
49af9e13 639int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 640 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *tm = NULL;
49af9e13 641 _cleanup_free_ char *pty_name = NULL;
4afd3348 642 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
fbe55073 643 sd_bus *container_bus = NULL;
40e1f4ea 644 _cleanup_close_ int master = -1, slave = -1;
49af9e13
LP
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
49af9e13
LP
682 r = bus_verify_polkit_async(
683 message,
684 CAP_SYS_ADMIN,
4289c3a7 685 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
403ed0e5 686 NULL,
49af9e13
LP
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
fbe55073 696 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC);
49af9e13
LP
697 if (master < 0)
698 return master;
699
a07c35c3 700 r = ptsname_namespace(master, &pty_name);
49af9e13
LP
701 if (r < 0)
702 return r;
703
704 p = path_startswith(pty_name, "/dev/pts/");
40e1f4ea
LP
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;
49af9e13
LP
710
711 utmp_id = path_startswith(pty_name, "/dev/");
712 assert(utmp_id);
713
385080c0 714 r = container_bus_new(m, error, &allocated_bus);
49af9e13
LP
715 if (r < 0)
716 return r;
717
fbe55073
LP
718 container_bus = allocated_bus ?: m->manager->bus;
719
49af9e13 720 r = sd_bus_message_new_method_call(
5f8cc96a 721 container_bus,
49af9e13 722 &tm,
5f8cc96a
LP
723 "org.freedesktop.systemd1",
724 "/org/freedesktop/systemd1",
725 "org.freedesktop.systemd1.Manager",
49af9e13
LP
726 "StartTransientUnit");
727 if (r < 0)
728 return r;
729
49af9e13 730 /* Name and mode */
fbe55073 731 unit = strjoina("container-shell@", p, ".service", NULL);
49af9e13
LP
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,
40e1f4ea 743 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
49af9e13 744 "Description", "s", description,
40e1f4ea
LP
745 "StandardInputFileDescriptor", "h", slave,
746 "StandardOutputFileDescriptor", "h", slave,
747 "StandardErrorFileDescriptor", "h", slave,
49af9e13
LP
748 "SendSIGHUP", "b", true,
749 "IgnoreSIGPIPE", "b", false,
750 "KillMode", "s", "mixed",
49af9e13
LP
751 "TTYReset", "b", true,
752 "UtmpIdentifier", "s", utmp_id,
753 "UtmpMode", "s", "user",
5f5d8eab
LP
754 "PAMName", "s", "login",
755 "WorkingDirectory", "s", "-~");
49af9e13
LP
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);
ee451d76
LP
848 if (r < 0)
849 return r;
850
40e1f4ea
LP
851 slave = safe_close(slave);
852
40205d70
LP
853 r = sd_bus_message_new_method_return(message, &reply);
854 if (r < 0)
855 return r;
856
ee451d76 857 r = sd_bus_message_append(reply, "hs", master, pty_name);
40205d70
LP
858 if (r < 0)
859 return r;
717603e3 860
9030ca46 861 return sd_bus_send(NULL, reply, NULL);
717603e3
LP
862}
863
19070062 864int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
90adaa25
LP
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
19070062
LP
877 assert(message);
878 assert(m);
879
90adaa25
LP
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))
c7abe32b 893 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
90adaa25 894
70244d1d
LP
895 r = bus_verify_polkit_async(
896 message,
897 CAP_SYS_ADMIN,
898 "org.freedesktop.machine1.manage-machines",
403ed0e5 899 NULL,
70244d1d 900 false,
c529695e 901 UID_INVALID,
70244d1d
LP
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
90adaa25
LP
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
ecb0573d 923 MS_MOVE cannot be applied to mounts with MS_SHARED parent
90adaa25
LP
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) {
c0ffce2b 1049 r = sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
90adaa25
LP
1050 goto finish;
1051 }
1052 if (si.si_code != CLD_EXITED) {
c0ffce2b 1053 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
90adaa25
LP
1054 goto finish;
1055 }
1056 if (si.si_status != EXIT_SUCCESS) {
1057
1058 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
c7abe32b 1059 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
90adaa25 1060 else
c0ffce2b 1061 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child failed.");
90adaa25
LP
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
0370612e 1086static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
4afd3348 1087 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
0370612e
LP
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) {
c0ffce2b 1097 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
0370612e
LP
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
c0ffce2b 1105 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
0370612e
LP
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
19070062 1126int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
0370612e
LP
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
19070062
LP
1137 assert(message);
1138 assert(m);
1139
0370612e
LP
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
d8440176
RM
1150 if (!path_is_absolute(src))
1151 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
0370612e
LP
1152
1153 if (isempty(dest))
1154 dest = src;
d8440176
RM
1155 else if (!path_is_absolute(dest))
1156 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
0370612e 1157
70244d1d
LP
1158 r = bus_verify_polkit_async(
1159 message,
1160 CAP_SYS_ADMIN,
1161 "org.freedesktop.machine1.manage-machines",
403ed0e5 1162 NULL,
70244d1d 1163 false,
c529695e 1164 UID_INVALID,
70244d1d
LP
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
0370612e
LP
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);
858a109f 1191 if (hostfd < 0)
0370612e
LP
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;
1273}
1274
c3350683
LP
1275const sd_bus_vtable machine_vtable[] = {
1276 SD_BUS_VTABLE_START(0),
556089dc
LP
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),
89f7c846
LP
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),
556089dc
LP
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),
9b5ed6fe 1286 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
c3350683 1287 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
70244d1d
LP
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),
0dd25fb9 1290 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 1291 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
fbe55073 1292 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, SD_BUS_VTABLE_UNPRIVILEGED),
d04c1fb8 1293 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
49af9e13 1294 SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell, SD_BUS_VTABLE_UNPRIVILEGED),
70244d1d
LP
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),
717603e3 1298 SD_BUS_VTABLE_END
c3350683 1299};
9444b1f2 1300
f00c3121 1301int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
c3350683
LP
1302 Manager *m = userdata;
1303 Machine *machine;
927b1649 1304 int r;
9444b1f2 1305
c3350683
LP
1306 assert(bus);
1307 assert(path);
1308 assert(interface);
1309 assert(found);
1310 assert(m);
9444b1f2 1311
927b1649 1312 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
4afd3348 1313 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
927b1649
LP
1314 sd_bus_message *message;
1315 pid_t pid;
9444b1f2 1316
19befb2d 1317 message = sd_bus_get_current_message(bus);
927b1649
LP
1318 if (!message)
1319 return 0;
1320
5b12334d 1321 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
927b1649 1322 if (r < 0)
5b12334d
LP
1323 return r;
1324
1325 r = sd_bus_creds_get_pid(creds, &pid);
1326 if (r < 0)
1327 return r;
9444b1f2 1328
927b1649
LP
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
a6278b88 1340 e = bus_label_unescape(p);
927b1649
LP
1341 if (!e)
1342 return -ENOMEM;
1343
1344 machine = hashmap_get(m->machines, e);
1345 if (!machine)
1346 return 0;
1347 }
9444b1f2 1348
c3350683
LP
1349 *found = machine;
1350 return 1;
9444b1f2
LP
1351}
1352
9444b1f2
LP
1353char *machine_bus_path(Machine *m) {
1354 _cleanup_free_ char *e = NULL;
1355
1356 assert(m);
1357
a6278b88 1358 e = bus_label_escape(m->name);
9444b1f2
LP
1359 if (!e)
1360 return NULL;
1361
1ee306e1 1362 return strappend("/org/freedesktop/machine1/machine/", e);
9444b1f2
LP
1363}
1364
f00c3121 1365int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
927b1649
LP
1366 _cleanup_strv_free_ char **l = NULL;
1367 Machine *machine = NULL;
1368 Manager *m = userdata;
1369 Iterator i;
1370 int r;
1371
1372 assert(bus);
1373 assert(path);
1374 assert(nodes);
1375
1376 HASHMAP_FOREACH(machine, m->machines, i) {
1377 char *p;
1378
1379 p = machine_bus_path(machine);
1380 if (!p)
1381 return -ENOMEM;
1382
6e18964d
ZJS
1383 r = strv_consume(&l, p);
1384 if (r < 0)
927b1649 1385 return r;
927b1649
LP
1386 }
1387
1388 *nodes = l;
1389 l = NULL;
1390
1391 return 1;
1392}
1393
9444b1f2 1394int machine_send_signal(Machine *m, bool new_machine) {
9444b1f2
LP
1395 _cleanup_free_ char *p = NULL;
1396
1397 assert(m);
1398
9444b1f2
LP
1399 p = machine_bus_path(m);
1400 if (!p)
1401 return -ENOMEM;
1402
c3350683
LP
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);
9444b1f2
LP
1409}
1410
c3350683 1411int machine_send_create_reply(Machine *m, sd_bus_error *error) {
4afd3348 1412 _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
9444b1f2
LP
1413 _cleanup_free_ char *p = NULL;
1414
1415 assert(m);
1416
fb6becb4
LP
1417 if (!m->create_message)
1418 return 0;
1419
c3350683
LP
1420 c = m->create_message;
1421 m->create_message = NULL;
fb6becb4 1422
a658cafa 1423 if (error)
df2d202e 1424 return sd_bus_reply_method_error(c, error);
a658cafa 1425
76e66585
LP
1426 /* Update the machine state file before we notify the client
1427 * about the result. */
1428 machine_save(m);
1429
c3350683
LP
1430 p = machine_bus_path(m);
1431 if (!p)
1432 return -ENOMEM;
fb6becb4 1433
df2d202e 1434 return sd_bus_reply_method_return(c, "o", p);
fb6becb4 1435}