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