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