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