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