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