]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machine-dbus.c
Merge pull request #24570 from topimiettinen/nft-sets-v2
[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, "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, 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, &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) < 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(m->leader,
884 propagate_directory,
885 "/run/host/incoming/",
886 src, dest, read_only, make_file_or_directory);
887 if (r < 0)
888 return sd_bus_error_set_errnof(error, r, "Failed to mount %s on %s in machine's namespace: %m", src, dest);
889
890 return sd_bus_reply_method_return(message, NULL);
891 }
892
893 int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
894 _cleanup_free_ char *host_basename = NULL, *container_basename = NULL;
895 const char *src, *dest, *host_path, *container_path;
896 _cleanup_close_pair_ int errno_pipe_fd[2] = PIPE_EBADF;
897 CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS;
898 _cleanup_close_ int hostfd = -EBADF;
899 Machine *m = ASSERT_PTR(userdata);
900 bool copy_from;
901 pid_t child;
902 uid_t uid_shift;
903 int r;
904
905 assert(message);
906
907 if (m->manager->n_operations >= OPERATIONS_MAX)
908 return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
909
910 if (m->class != MACHINE_CONTAINER)
911 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
912
913 r = sd_bus_message_read(message, "ss", &src, &dest);
914 if (r < 0)
915 return r;
916
917 if (endswith(sd_bus_message_get_member(message), "WithFlags")) {
918 uint64_t raw_flags;
919
920 r = sd_bus_message_read(message, "t", &raw_flags);
921 if (r < 0)
922 return r;
923
924 if ((raw_flags & ~_MACHINE_COPY_FLAGS_MASK_PUBLIC) != 0)
925 return -EINVAL;
926
927 if (raw_flags & MACHINE_COPY_REPLACE)
928 copy_flags |= COPY_REPLACE;
929 }
930
931 if (!path_is_absolute(src))
932 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
933
934 if (isempty(dest))
935 dest = src;
936 else if (!path_is_absolute(dest))
937 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
938
939 const char *details[] = {
940 "machine", m->name,
941 "verb", "copy",
942 "src", src,
943 "dest", dest,
944 NULL
945 };
946
947 r = bus_verify_polkit_async(
948 message,
949 CAP_SYS_ADMIN,
950 "org.freedesktop.machine1.manage-machines",
951 details,
952 false,
953 UID_INVALID,
954 &m->manager->polkit_registry,
955 error);
956 if (r < 0)
957 return r;
958 if (r == 0)
959 return 1; /* Will call us back */
960
961 r = machine_get_uid_shift(m, &uid_shift);
962 if (r < 0)
963 return r;
964
965 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
966
967 if (copy_from) {
968 container_path = src;
969 host_path = dest;
970 } else {
971 host_path = src;
972 container_path = dest;
973 }
974
975 r = path_extract_filename(host_path, &host_basename);
976 if (r < 0)
977 return sd_bus_error_set_errnof(error, r, "Failed to extract file name of '%s' path: %m", host_path);
978
979 r = path_extract_filename(container_path, &container_basename);
980 if (r < 0)
981 return sd_bus_error_set_errnof(error, r, "Failed to extract file name of '%s' path: %m", container_path);
982
983 hostfd = open_parent(host_path, O_CLOEXEC, 0);
984 if (hostfd < 0)
985 return sd_bus_error_set_errnof(error, hostfd, "Failed to open host directory %s: %m", host_path);
986
987 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
988 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
989
990 r = safe_fork("(sd-copy)", FORK_RESET_SIGNALS, &child);
991 if (r < 0)
992 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
993 if (r == 0) {
994 int containerfd;
995 const char *q;
996 int mntfd;
997
998 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
999
1000 q = procfs_file_alloca(m->leader, "ns/mnt");
1001 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1002 if (mntfd < 0) {
1003 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1004 goto child_fail;
1005 }
1006
1007 if (setns(mntfd, CLONE_NEWNS) < 0) {
1008 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
1009 goto child_fail;
1010 }
1011
1012 containerfd = open_parent(container_path, O_CLOEXEC, 0);
1013 if (containerfd < 0) {
1014 r = log_error_errno(containerfd, "Failed to open destination directory: %m");
1015 goto child_fail;
1016 }
1017
1018 /* Run the actual copy operation. Note that when a UID shift is set we'll either clamp the UID/GID to
1019 * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
1020 * the UID/GIDs as they are. */
1021 if (copy_from)
1022 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);
1023 else
1024 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);
1025
1026 hostfd = safe_close(hostfd);
1027 containerfd = safe_close(containerfd);
1028
1029 if (r < 0) {
1030 r = log_error_errno(r, "Failed to copy tree: %m");
1031 goto child_fail;
1032 }
1033
1034 _exit(EXIT_SUCCESS);
1035
1036 child_fail:
1037 (void) write(errno_pipe_fd[1], &r, sizeof(r));
1038 _exit(EXIT_FAILURE);
1039 }
1040
1041 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1042
1043 /* Copying might take a while, hence install a watch on the child, and return */
1044
1045 r = operation_new(m->manager, m, child, message, errno_pipe_fd[0], NULL);
1046 if (r < 0) {
1047 (void) sigkill_wait(child);
1048 return r;
1049 }
1050 errno_pipe_fd[0] = -EBADF;
1051
1052 return 1;
1053 }
1054
1055 int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1056 _cleanup_close_ int fd = -EBADF;
1057 Machine *m = ASSERT_PTR(userdata);
1058 int r;
1059
1060 assert(message);
1061
1062 const char *details[] = {
1063 "machine", m->name,
1064 "verb", "open_root_directory",
1065 NULL
1066 };
1067
1068 r = bus_verify_polkit_async(
1069 message,
1070 CAP_SYS_ADMIN,
1071 "org.freedesktop.machine1.manage-machines",
1072 details,
1073 false,
1074 UID_INVALID,
1075 &m->manager->polkit_registry,
1076 error);
1077 if (r < 0)
1078 return r;
1079 if (r == 0)
1080 return 1; /* Will call us back */
1081
1082 switch (m->class) {
1083
1084 case MACHINE_HOST:
1085 fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1086 if (fd < 0)
1087 return -errno;
1088
1089 break;
1090
1091 case MACHINE_CONTAINER: {
1092 _cleanup_close_ int mntns_fd = -EBADF, root_fd = -EBADF;
1093 _cleanup_close_pair_ int pair[2] = PIPE_EBADF;
1094 pid_t child;
1095
1096 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
1097 if (r < 0)
1098 return r;
1099
1100 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1101 return -errno;
1102
1103 r = namespace_fork("(sd-openrootns)", "(sd-openroot)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG,
1104 -1, mntns_fd, -1, -1, root_fd, &child);
1105 if (r < 0)
1106 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
1107 if (r == 0) {
1108 _cleanup_close_ int dfd = -EBADF;
1109
1110 pair[0] = safe_close(pair[0]);
1111
1112 dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1113 if (dfd < 0)
1114 _exit(EXIT_FAILURE);
1115
1116 r = send_one_fd(pair[1], dfd, 0);
1117 dfd = safe_close(dfd);
1118 if (r < 0)
1119 _exit(EXIT_FAILURE);
1120
1121 _exit(EXIT_SUCCESS);
1122 }
1123
1124 pair[1] = safe_close(pair[1]);
1125
1126 r = wait_for_terminate_and_check("(sd-openrootns)", child, 0);
1127 if (r < 0)
1128 return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
1129 if (r != EXIT_SUCCESS)
1130 return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
1131
1132 fd = receive_one_fd(pair[0], MSG_DONTWAIT);
1133 if (fd < 0)
1134 return fd;
1135
1136 break;
1137 }
1138
1139 default:
1140 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
1141 }
1142
1143 return sd_bus_reply_method_return(message, "h", fd);
1144 }
1145
1146 int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1147 Machine *m = ASSERT_PTR(userdata);
1148 uid_t shift = 0;
1149 int r;
1150
1151 assert(message);
1152
1153 /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but
1154 * we kinda have to for this. */
1155
1156 if (m->class == MACHINE_HOST)
1157 return sd_bus_reply_method_return(message, "u", UINT32_C(0));
1158
1159 if (m->class != MACHINE_CONTAINER)
1160 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines.");
1161
1162 r = machine_get_uid_shift(m, &shift);
1163 if (r == -ENXIO)
1164 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m->name);
1165 if (r < 0)
1166 return r;
1167
1168 return sd_bus_reply_method_return(message, "u", (uint32_t) shift);
1169 }
1170
1171 static int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
1172 Manager *m = ASSERT_PTR(userdata);
1173 Machine *machine;
1174 int r;
1175
1176 assert(bus);
1177 assert(path);
1178 assert(interface);
1179 assert(found);
1180
1181 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
1182 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
1183 sd_bus_message *message;
1184 pid_t pid;
1185
1186 message = sd_bus_get_current_message(bus);
1187 if (!message)
1188 return 0;
1189
1190 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
1191 if (r < 0)
1192 return r;
1193
1194 r = sd_bus_creds_get_pid(creds, &pid);
1195 if (r < 0)
1196 return r;
1197
1198 r = manager_get_machine_by_pid(m, pid, &machine);
1199 if (r <= 0)
1200 return 0;
1201 } else {
1202 _cleanup_free_ char *e = NULL;
1203 const char *p;
1204
1205 p = startswith(path, "/org/freedesktop/machine1/machine/");
1206 if (!p)
1207 return 0;
1208
1209 e = bus_label_unescape(p);
1210 if (!e)
1211 return -ENOMEM;
1212
1213 machine = hashmap_get(m->machines, e);
1214 if (!machine)
1215 return 0;
1216 }
1217
1218 *found = machine;
1219 return 1;
1220 }
1221
1222 char *machine_bus_path(Machine *m) {
1223 _cleanup_free_ char *e = NULL;
1224
1225 assert(m);
1226
1227 e = bus_label_escape(m->name);
1228 if (!e)
1229 return NULL;
1230
1231 return strjoin("/org/freedesktop/machine1/machine/", e);
1232 }
1233
1234 static int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
1235 _cleanup_strv_free_ char **l = NULL;
1236 Machine *machine = NULL;
1237 Manager *m = userdata;
1238 int r;
1239
1240 assert(bus);
1241 assert(path);
1242 assert(nodes);
1243
1244 HASHMAP_FOREACH(machine, m->machines) {
1245 char *p;
1246
1247 p = machine_bus_path(machine);
1248 if (!p)
1249 return -ENOMEM;
1250
1251 r = strv_consume(&l, p);
1252 if (r < 0)
1253 return r;
1254 }
1255
1256 *nodes = TAKE_PTR(l);
1257
1258 return 1;
1259 }
1260
1261 static const sd_bus_vtable machine_vtable[] = {
1262 SD_BUS_VTABLE_START(0),
1263 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
1264 SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST),
1265 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
1266 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
1267 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
1268 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1269 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
1270 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
1271 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
1272 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1273 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
1274
1275 SD_BUS_METHOD("Terminate",
1276 NULL,
1277 NULL,
1278 bus_machine_method_terminate,
1279 SD_BUS_VTABLE_UNPRIVILEGED),
1280 SD_BUS_METHOD_WITH_ARGS("Kill",
1281 SD_BUS_ARGS("s", who, "i", signal),
1282 SD_BUS_NO_RESULT,
1283 bus_machine_method_kill,
1284 SD_BUS_VTABLE_UNPRIVILEGED),
1285 SD_BUS_METHOD_WITH_ARGS("GetAddresses",
1286 SD_BUS_NO_ARGS,
1287 SD_BUS_RESULT("a(iay)", addresses),
1288 bus_machine_method_get_addresses,
1289 SD_BUS_VTABLE_UNPRIVILEGED),
1290 SD_BUS_METHOD_WITH_ARGS("GetOSRelease",
1291 SD_BUS_NO_ARGS,
1292 SD_BUS_RESULT("a{ss}", fields),
1293 bus_machine_method_get_os_release,
1294 SD_BUS_VTABLE_UNPRIVILEGED),
1295 SD_BUS_METHOD_WITH_ARGS("GetUIDShift",
1296 SD_BUS_NO_ARGS,
1297 SD_BUS_RESULT("u", shift),
1298 bus_machine_method_get_uid_shift,
1299 SD_BUS_VTABLE_UNPRIVILEGED),
1300 SD_BUS_METHOD_WITH_ARGS("OpenPTY",
1301 SD_BUS_NO_ARGS,
1302 SD_BUS_RESULT("h", pty, "s", pty_path),
1303 bus_machine_method_open_pty,
1304 SD_BUS_VTABLE_UNPRIVILEGED),
1305 SD_BUS_METHOD_WITH_ARGS("OpenLogin",
1306 SD_BUS_NO_ARGS,
1307 SD_BUS_RESULT("h", pty, "s", pty_path),
1308 bus_machine_method_open_login,
1309 SD_BUS_VTABLE_UNPRIVILEGED),
1310 SD_BUS_METHOD_WITH_ARGS("OpenShell",
1311 SD_BUS_ARGS("s", user, "s", path, "as", args, "as", environment),
1312 SD_BUS_RESULT("h", pty, "s", pty_path),
1313 bus_machine_method_open_shell,
1314 SD_BUS_VTABLE_UNPRIVILEGED),
1315 SD_BUS_METHOD_WITH_ARGS("BindMount",
1316 SD_BUS_ARGS("s", source, "s", destination, "b", read_only, "b", mkdir),
1317 SD_BUS_NO_RESULT,
1318 bus_machine_method_bind_mount,
1319 SD_BUS_VTABLE_UNPRIVILEGED),
1320 SD_BUS_METHOD_WITH_ARGS("CopyFrom",
1321 SD_BUS_ARGS("s", source, "s", destination),
1322 SD_BUS_NO_RESULT,
1323 bus_machine_method_copy,
1324 SD_BUS_VTABLE_UNPRIVILEGED),
1325 SD_BUS_METHOD_WITH_ARGS("CopyTo",
1326 SD_BUS_ARGS("s", source, "s", destination),
1327 SD_BUS_NO_RESULT,
1328 bus_machine_method_copy,
1329 SD_BUS_VTABLE_UNPRIVILEGED),
1330 SD_BUS_METHOD_WITH_ARGS("CopyFromWithFlags",
1331 SD_BUS_ARGS("s", source, "s", destination, "t", flags),
1332 SD_BUS_NO_RESULT,
1333 bus_machine_method_copy,
1334 SD_BUS_VTABLE_UNPRIVILEGED),
1335 SD_BUS_METHOD_WITH_ARGS("CopyToWithFlags",
1336 SD_BUS_ARGS("s", source, "s", destination, "t", flags),
1337 SD_BUS_NO_RESULT,
1338 bus_machine_method_copy,
1339 SD_BUS_VTABLE_UNPRIVILEGED),
1340 SD_BUS_METHOD_WITH_ARGS("OpenRootDirectory",
1341 SD_BUS_NO_ARGS,
1342 SD_BUS_RESULT("h", fd),
1343 bus_machine_method_open_root_directory,
1344 SD_BUS_VTABLE_UNPRIVILEGED),
1345
1346 SD_BUS_VTABLE_END
1347 };
1348
1349 const BusObjectImplementation machine_object = {
1350 "/org/freedesktop/machine1/machine",
1351 "org.freedesktop.machine1.Machine",
1352 .fallback_vtables = BUS_FALLBACK_VTABLES({machine_vtable, machine_object_find}),
1353 .node_enumerator = machine_node_enumerator,
1354 };
1355
1356 int machine_send_signal(Machine *m, bool new_machine) {
1357 _cleanup_free_ char *p = NULL;
1358
1359 assert(m);
1360
1361 p = machine_bus_path(m);
1362 if (!p)
1363 return -ENOMEM;
1364
1365 return sd_bus_emit_signal(
1366 m->manager->bus,
1367 "/org/freedesktop/machine1",
1368 "org.freedesktop.machine1.Manager",
1369 new_machine ? "MachineNew" : "MachineRemoved",
1370 "so", m->name, p);
1371 }
1372
1373 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
1374 _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
1375 _cleanup_free_ char *p = NULL;
1376
1377 assert(m);
1378
1379 if (!m->create_message)
1380 return 0;
1381
1382 c = TAKE_PTR(m->create_message);
1383
1384 if (error)
1385 return sd_bus_reply_method_error(c, error);
1386
1387 /* Update the machine state file before we notify the client
1388 * about the result. */
1389 machine_save(m);
1390
1391 p = machine_bus_path(m);
1392 if (!p)
1393 return -ENOMEM;
1394
1395 return sd_bus_reply_method_return(c, "o", p);
1396 }