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