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