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