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