]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machine-dbus.c
9f026beb1325ca99c171fb3465c94b787dffc0bf
[thirdparty/systemd.git] / src / machine / machine-dbus.c
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>
24 #include <sys/mount.h>
25
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 POSIX
28 * version which is really broken. We prefer GNU basename(). */
29 #include <libgen.h>
30 #undef basename
31
32 #include "bus-util.h"
33 #include "bus-label.h"
34 #include "strv.h"
35 #include "bus-common-errors.h"
36 #include "copy.h"
37 #include "fileio.h"
38 #include "in-addr-util.h"
39 #include "local-addresses.h"
40 #include "path-util.h"
41 #include "mkdir.h"
42 #include "bus-internal.h"
43 #include "machine.h"
44 #include "machine-dbus.h"
45 #include "formats-util.h"
46 #include "process-util.h"
47
48 static 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,
54 void *userdata,
55 sd_bus_error *error) {
56
57 Machine *m = userdata;
58 int r;
59
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;
67
68 return 1;
69 }
70
71 static 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,
77 void *userdata,
78 sd_bus_error *error) {
79
80 Machine *m = userdata;
81 const char *state;
82 int r;
83
84 assert(bus);
85 assert(reply);
86 assert(m);
87
88 state = machine_state_to_string(machine_get_state(m));
89
90 r = sd_bus_message_append_basic(reply, 's', state);
91 if (r < 0)
92 return r;
93
94 return 1;
95 }
96
97 static 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
122 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
123
124 int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
125 Machine *m = userdata;
126 int r;
127
128 assert(message);
129 assert(m);
130
131 r = bus_verify_polkit_async(
132 message,
133 CAP_KILL,
134 "org.freedesktop.machine1.manage-machines",
135 false,
136 UID_INVALID,
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
144 r = machine_stop(m);
145 if (r < 0)
146 return r;
147
148 return sd_bus_reply_method_return(message, NULL);
149 }
150
151 int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
152 Machine *m = userdata;
153 const char *swho;
154 int32_t signo;
155 KillWho who;
156 int r;
157
158 assert(message);
159 assert(m);
160
161 r = sd_bus_message_read(message, "si", &swho, &signo);
162 if (r < 0)
163 return r;
164
165 if (isempty(swho))
166 who = KILL_ALL;
167 else {
168 who = kill_who_from_string(swho);
169 if (who < 0)
170 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
171 }
172
173 if (signo <= 0 || signo >= _NSIG)
174 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
175
176 r = bus_verify_polkit_async(
177 message,
178 CAP_KILL,
179 "org.freedesktop.machine1.manage-machines",
180 false,
181 UID_INVALID,
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
189 r = machine_kill(m, who, signo);
190 if (r < 0)
191 return r;
192
193 return sd_bus_reply_method_return(message, NULL);
194 }
195
196 int bus_machine_method_get_addresses(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(message);
208 assert(m);
209
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
213 r = readlink_malloc("/proc/self/ns/net", &us);
214 if (r < 0)
215 return r;
216
217 p = procfs_file_alloca(m->leader, "ns/net");
218 r = readlink_malloc(p, &them);
219 if (r < 0)
220 return r;
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)
227 return r;
228
229 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
230 return -errno;
231
232 child = fork();
233 if (child < 0)
234 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
235
236 if (child == 0) {
237 _cleanup_free_ struct local_address *addresses = NULL;
238 struct local_address *a;
239 int i, n;
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
247 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
248 if (n < 0)
249 _exit(EXIT_FAILURE);
250
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) },
254 { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
255 };
256
257 r = writev(pair[1], iov, 2);
258 if (r < 0)
259 _exit(EXIT_FAILURE);
260 }
261
262 pair[1] = safe_close(pair[1]);
263
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)
271 return r;
272
273 r = sd_bus_message_open_container(reply, 'a', "(iay)");
274 if (r < 0)
275 return r;
276
277 for (;;) {
278 int family;
279 ssize_t n;
280 union in_addr_union in_addr;
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
290 n = recvmsg(pair[0], &mh, 0);
291 if (n < 0)
292 return -errno;
293 if ((size_t) n < sizeof(family))
294 break;
295
296 r = sd_bus_message_open_container(reply, 'r', "iay");
297 if (r < 0)
298 return r;
299
300 r = sd_bus_message_append(reply, "i", family);
301 if (r < 0)
302 return r;
303
304 switch (family) {
305
306 case AF_INET:
307 if (n != sizeof(struct in_addr) + sizeof(family))
308 return -EIO;
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))
315 return -EIO;
316
317 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
318 break;
319 }
320 if (r < 0)
321 return r;
322
323 r = sd_bus_message_close_container(reply);
324 if (r < 0)
325 return r;
326 }
327
328 r = wait_for_terminate(child, &si);
329 if (r < 0)
330 return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
331 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
332 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
333
334 r = sd_bus_message_close_container(reply);
335 if (r < 0)
336 return r;
337
338 return sd_bus_send(NULL, reply, NULL);
339 }
340
341 int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
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
353 assert(message);
354 assert(m);
355
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
359 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
360 if (r < 0)
361 return r;
362
363 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
364 return -errno;
365
366 child = fork();
367 if (child < 0)
368 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
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
386 r = copy_bytes(fd, pair[1], (off_t) -1, false);
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)
397 return -errno;
398
399 pair[0] = -1;
400
401 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
402 if (r < 0)
403 return r;
404
405 r = wait_for_terminate(child, &si);
406 if (r < 0)
407 return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
408 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
409 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
410
411 r = sd_bus_message_new_method_return(message, &reply);
412 if (r < 0)
413 return r;
414
415 r = sd_bus_message_open_container(reply, 'a', "{ss}");
416 if (r < 0)
417 return r;
418
419 STRV_FOREACH_PAIR(k, v, l) {
420 r = sd_bus_message_append(reply, "{ss}", *k, *v);
421 if (r < 0)
422 return r;
423 }
424
425 r = sd_bus_message_close_container(reply);
426 if (r < 0)
427 return r;
428
429 return sd_bus_send(NULL, reply, NULL);
430 }
431
432 int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
433 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
434 _cleanup_free_ char *pty_name = NULL;
435 _cleanup_close_ int master = -1;
436 Machine *m = userdata;
437 int r;
438
439 assert(message);
440 assert(m);
441
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
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);
450 if (r < 0)
451 return r;
452
453 r = sd_bus_message_new_method_return(message, &reply);
454 if (r < 0)
455 return r;
456
457 r = sd_bus_message_append(reply, "hs", master, pty_name);
458 if (r < 0)
459 return r;
460
461 return sd_bus_send(NULL, reply, NULL);
462 }
463
464 int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
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;
471 char *address;
472 int r;
473
474 assert(message);
475 assert(m);
476
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
480 r = bus_verify_polkit_async(
481 message,
482 CAP_SYS_ADMIN,
483 "org.freedesktop.machine1.login",
484 false,
485 UID_INVALID,
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
493 master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
494 if (master < 0)
495 return master;
496
497 r = ptsname_malloc(master, &pty_name);
498 if (r < 0)
499 return r;
500
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);
504
505 if (unlockpt(master) < 0)
506 return -errno;
507
508 r = sd_bus_new(&container_bus);
509 if (r < 0)
510 return r;
511
512 #ifdef ENABLE_KDBUS
513 # define ADDRESS_FMT "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI
514 #else
515 # define ADDRESS_FMT "x-machine-unix:pid=%1$" PID_PRI
516 #endif
517 if (asprintf(&address, ADDRESS_FMT, m->leader) < 0)
518 return log_oom();
519
520 container_bus->address = address;
521 container_bus->bus_client = true;
522 container_bus->trusted = false;
523 container_bus->is_system = true;
524
525 r = sd_bus_start(container_bus);
526 if (r < 0)
527 return r;
528
529 getty = strjoin("container-getty@", p, ".service", NULL);
530 if (!getty)
531 return log_oom();
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");
541 if (r < 0)
542 return r;
543
544 container_bus = sd_bus_unref(container_bus);
545
546 r = sd_bus_message_new_method_return(message, &reply);
547 if (r < 0)
548 return r;
549
550 r = sd_bus_message_append(reply, "hs", master, pty_name);
551 if (r < 0)
552 return r;
553
554 return sd_bus_send(NULL, reply, NULL);
555 }
556
557 int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
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
570 assert(message);
571 assert(m);
572
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))
586 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
587
588 r = bus_verify_polkit_async(
589 message,
590 CAP_SYS_ADMIN,
591 "org.freedesktop.machine1.manage-machines",
592 false,
593 UID_INVALID,
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
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) {
741 r = sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
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))
751 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
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
759 finish:
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
778 static 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
809 fail:
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
818 int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
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
829 assert(message);
830 assert(m);
831
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
850 r = bus_verify_polkit_async(
851 message,
852 CAP_SYS_ADMIN,
853 "org.freedesktop.machine1.manage-machines",
854 false,
855 UID_INVALID,
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
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);
882 if (hostfd < 0)
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
966 const sd_bus_vtable machine_vtable[] = {
967 SD_BUS_VTABLE_START(0),
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),
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),
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),
977 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
978 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
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),
981 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
982 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
983 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0),
984 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
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),
988 SD_BUS_VTABLE_END
989 };
990
991 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
992 Manager *m = userdata;
993 Machine *machine;
994 int r;
995
996 assert(bus);
997 assert(path);
998 assert(interface);
999 assert(found);
1000 assert(m);
1001
1002 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
1003 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1004 sd_bus_message *message;
1005 pid_t pid;
1006
1007 message = sd_bus_get_current_message(bus);
1008 if (!message)
1009 return 0;
1010
1011 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
1012 if (r < 0)
1013 return r;
1014
1015 r = sd_bus_creds_get_pid(creds, &pid);
1016 if (r < 0)
1017 return r;
1018
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
1030 e = bus_label_unescape(p);
1031 if (!e)
1032 return -ENOMEM;
1033
1034 machine = hashmap_get(m->machines, e);
1035 if (!machine)
1036 return 0;
1037 }
1038
1039 *found = machine;
1040 return 1;
1041 }
1042
1043 char *machine_bus_path(Machine *m) {
1044 _cleanup_free_ char *e = NULL;
1045
1046 assert(m);
1047
1048 e = bus_label_escape(m->name);
1049 if (!e)
1050 return NULL;
1051
1052 return strappend("/org/freedesktop/machine1/machine/", e);
1053 }
1054
1055 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
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
1073 r = strv_consume(&l, p);
1074 if (r < 0)
1075 return r;
1076 }
1077
1078 *nodes = l;
1079 l = NULL;
1080
1081 return 1;
1082 }
1083
1084 int machine_send_signal(Machine *m, bool new_machine) {
1085 _cleanup_free_ char *p = NULL;
1086
1087 assert(m);
1088
1089 p = machine_bus_path(m);
1090 if (!p)
1091 return -ENOMEM;
1092
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);
1099 }
1100
1101 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
1102 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
1103 _cleanup_free_ char *p = NULL;
1104
1105 assert(m);
1106
1107 if (!m->create_message)
1108 return 0;
1109
1110 c = m->create_message;
1111 m->create_message = NULL;
1112
1113 if (error)
1114 return sd_bus_reply_method_error(c, error);
1115
1116 /* Update the machine state file before we notify the client
1117 * about the result. */
1118 machine_save(m);
1119
1120 p = machine_bus_path(m);
1121 if (!p)
1122 return -ENOMEM;
1123
1124 return sd_bus_reply_method_return(c, "o", p);
1125 }