]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/machine/machine-dbus.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / machine / machine-dbus.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include "sd-bus.h"
4
5#include "alloc-util.h"
6#include "bus-common-errors.h"
7#include "bus-get-properties.h"
8#include "bus-label.h"
9#include "bus-object.h"
10#include "bus-polkit.h"
11#include "bus-util.h"
12#include "copy.h"
13#include "env-util.h"
14#include "errno-util.h"
15#include "fd-util.h"
16#include "hashmap.h"
17#include "in-addr-util.h"
18#include "local-addresses.h"
19#include "machine.h"
20#include "machine-dbus.h"
21#include "machined.h"
22#include "mount-util.h"
23#include "operation.h"
24#include "path-util.h"
25#include "signal-util.h"
26#include "string-util.h"
27#include "strv.h"
28
29static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
30static BUS_DEFINE_PROPERTY_GET2(property_get_state, "s", Machine, machine_get_state, machine_state_to_string);
31
32static int property_get_netif(
33 sd_bus *bus,
34 const char *path,
35 const char *interface,
36 const char *property,
37 sd_bus_message *reply,
38 void *userdata,
39 sd_bus_error *error) {
40
41 Machine *m = ASSERT_PTR(userdata);
42
43 assert(bus);
44 assert(reply);
45
46 assert_cc(sizeof(int) == sizeof(int32_t));
47
48 return sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
49}
50
51int bus_machine_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error) {
52 Machine *m = ASSERT_PTR(userdata);
53 int r;
54
55 assert(message);
56
57 const char *details[] = {
58 "machine", m->name,
59 "verb", "unregister",
60 NULL
61 };
62
63 r = bus_verify_polkit_async(
64 message,
65 "org.freedesktop.machine1.manage-machines",
66 details,
67 &m->manager->polkit_registry,
68 error);
69 if (r < 0)
70 return r;
71 if (r == 0)
72 return 1; /* Will call us back */
73
74 r = machine_finalize(m);
75 if (r < 0)
76 return r;
77
78 return sd_bus_reply_method_return(message, NULL);
79}
80
81int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
82 Machine *m = ASSERT_PTR(userdata);
83 int r;
84
85 assert(message);
86
87 const char *details[] = {
88 "machine", m->name,
89 "verb", "terminate",
90 NULL
91 };
92
93 r = bus_verify_polkit_async(
94 message,
95 "org.freedesktop.machine1.manage-machines",
96 details,
97 &m->manager->polkit_registry,
98 error);
99 if (r < 0)
100 return r;
101 if (r == 0)
102 return 1; /* Will call us back */
103
104 r = machine_stop(m);
105 if (r < 0)
106 return r;
107
108 return sd_bus_reply_method_return(message, NULL);
109}
110
111int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
112 Machine *m = ASSERT_PTR(userdata);
113 const char *swho;
114 int32_t signo;
115 KillWhom whom;
116 int r;
117
118 assert(message);
119
120 r = sd_bus_message_read(message, "si", &swho, &signo);
121 if (r < 0)
122 return r;
123
124 if (isempty(swho))
125 whom = KILL_ALL;
126 else {
127 whom = kill_whom_from_string(swho);
128 if (whom < 0)
129 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
130 }
131
132 if (!SIGNAL_VALID(signo))
133 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
134
135 const char *details[] = {
136 "machine", m->name,
137 "verb", "kill",
138 NULL
139 };
140
141 r = bus_verify_polkit_async(
142 message,
143 "org.freedesktop.machine1.manage-machines",
144 details,
145 &m->manager->polkit_registry,
146 error);
147 if (r < 0)
148 return r;
149 if (r == 0)
150 return 1; /* Will call us back */
151
152 r = machine_kill(m, whom, signo);
153 if (r < 0)
154 return r;
155
156 return sd_bus_reply_method_return(message, NULL);
157}
158
159int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
160 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
161 _cleanup_free_ struct local_address *addresses = NULL;
162 Machine *m = ASSERT_PTR(userdata);
163 int r;
164
165 assert(message);
166
167 r = sd_bus_message_new_method_return(message, &reply);
168 if (r < 0)
169 return r;
170
171 r = sd_bus_message_open_container(reply, 'a', "(iay)");
172 if (r < 0)
173 return r;
174
175 int n = machine_get_addresses(m, &addresses);
176 if (n == -ENONET)
177 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
178 if (ERRNO_IS_NEG_NOT_SUPPORTED(n))
179 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
180 if (n < 0)
181 return sd_bus_error_set_errnof(error, n, "Failed to get addresses: %m");
182
183 for (int i = 0; i < n; i++) {
184 r = sd_bus_message_open_container(reply, 'r', "iay");
185 if (r < 0)
186 return r;
187
188 r = sd_bus_message_append(reply, "i", addresses[i].family);
189 if (r < 0)
190 return r;
191
192 r = sd_bus_message_append_array(reply, 'y', &addresses[i].address, FAMILY_ADDRESS_SIZE(addresses[i].family));
193 if (r < 0)
194 return r;
195
196 r = sd_bus_message_close_container(reply);
197 if (r < 0)
198 return r;
199 }
200
201 r = sd_bus_message_close_container(reply);
202 if (r < 0)
203 return r;
204
205 return sd_bus_message_send(reply);
206}
207
208int bus_machine_method_get_ssh_info(sd_bus_message *message, void *userdata, sd_bus_error *error) {
209 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
210 Machine *m = ASSERT_PTR(userdata);
211 int r;
212
213 assert(message);
214
215 r = sd_bus_message_new_method_return(message, &reply);
216 if (r < 0)
217 return r;
218
219 if (!m->ssh_address || !m->ssh_private_key_path)
220 return -ENOENT;
221
222 r = sd_bus_message_append(reply, "ss", m->ssh_address, m->ssh_private_key_path);
223 if (r < 0)
224 return r;
225
226 return sd_bus_message_send(reply);
227}
228
229int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
230 _cleanup_strv_free_ char **l = NULL;
231 Machine *m = ASSERT_PTR(userdata);
232 int r;
233
234 assert(message);
235
236 r = machine_get_os_release(m, &l);
237 if (r == -ENONET)
238 return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Machine does not contain OS release information.");
239 if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
240 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
241 if (r < 0)
242 return sd_bus_error_set_errnof(error, r, "Failed to get OS release: %m");
243
244 return bus_reply_pair_array(message, l);
245}
246
247int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
248 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
249 _cleanup_free_ char *pty_name = NULL;
250 _cleanup_close_ int master = -EBADF;
251 Machine *m = ASSERT_PTR(userdata);
252 int r;
253
254 assert(message);
255
256 const char *details[] = {
257 "machine", m->name,
258 NULL
259 };
260
261 r = bus_verify_polkit_async(
262 message,
263 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty",
264 details,
265 &m->manager->polkit_registry,
266 error);
267 if (r < 0)
268 return r;
269 if (r == 0)
270 return 1; /* Will call us back */
271
272 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
273 if (master < 0)
274 return master;
275
276 r = sd_bus_message_new_method_return(message, &reply);
277 if (r < 0)
278 return r;
279
280 r = sd_bus_message_append(reply, "hs", master, pty_name);
281 if (r < 0)
282 return r;
283
284 return sd_bus_message_send(reply);
285}
286
287int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
288 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
289 _cleanup_free_ char *pty_name = NULL;
290 _cleanup_close_ int master = -EBADF;
291 Machine *m = ASSERT_PTR(userdata);
292 int r;
293
294 assert(message);
295
296 const char *details[] = {
297 "machine", m->name,
298 "verb", "login",
299 NULL
300 };
301
302 r = bus_verify_polkit_async(
303 message,
304 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
305 details,
306 &m->manager->polkit_registry,
307 error);
308 if (r < 0)
309 return r;
310 if (r == 0)
311 return 1; /* Will call us back */
312
313 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
314 if (master < 0)
315 return master;
316
317 r = machine_start_getty(m, pty_name, error);
318 if (r < 0)
319 return r;
320
321 r = sd_bus_message_new_method_return(message, &reply);
322 if (r < 0)
323 return r;
324
325 r = sd_bus_message_append(reply, "hs", master, pty_name);
326 if (r < 0)
327 return r;
328
329 return sd_bus_message_send(reply);
330}
331
332int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
333 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
334 _cleanup_free_ char *pty_name = NULL;
335 _cleanup_close_ int master = -EBADF;
336 _cleanup_strv_free_ char **env = NULL, **args_wire = NULL, **args = NULL;
337 _cleanup_free_ char *command_line = NULL;
338 Machine *m = ASSERT_PTR(userdata);
339 const char *user, *path;
340 int r;
341
342 assert(message);
343
344 r = sd_bus_message_read(message, "ss", &user, &path);
345 if (r < 0)
346 return r;
347 user = isempty(user) ? "root" : user;
348 r = sd_bus_message_read_strv(message, &args_wire);
349 if (r < 0)
350 return r;
351 if (isempty(path)) {
352 path = machine_default_shell_path();
353 args = machine_default_shell_args(user);
354 if (!args)
355 return -ENOMEM;
356 } else {
357 if (!path_is_absolute(path))
358 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified path '%s' is not absolute", path);
359 args = TAKE_PTR(args_wire);
360 if (strv_isempty(args)) {
361 args = strv_free(args);
362
363 args = strv_new(path);
364 if (!args)
365 return -ENOMEM;
366 }
367 }
368
369 r = sd_bus_message_read_strv(message, &env);
370 if (r < 0)
371 return r;
372 if (!strv_env_is_valid(env))
373 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
374
375 command_line = strv_join(args, " ");
376 if (!command_line)
377 return -ENOMEM;
378 const char *details[] = {
379 "machine", m->name,
380 "user", user,
381 "program", path,
382 "command_line", command_line,
383 NULL
384 };
385
386 r = bus_verify_polkit_async(
387 message,
388 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
389 details,
390 &m->manager->polkit_registry,
391 error);
392 if (r < 0)
393 return r;
394 if (r == 0)
395 return 1; /* Will call us back */
396
397 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
398 if (master < 0)
399 return master;
400
401 r = machine_start_shell(m, master, pty_name, user, path, args, env, error);
402 if (r < 0)
403 return r;
404
405 r = sd_bus_message_new_method_return(message, &reply);
406 if (r < 0)
407 return r;
408
409 r = sd_bus_message_append(reply, "hs", master, pty_name);
410 if (r < 0)
411 return r;
412
413 return sd_bus_message_send(reply);
414}
415
416int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
417 int read_only, make_file_or_directory;
418 const char *dest, *src, *propagate_directory;
419 Machine *m = ASSERT_PTR(userdata);
420 MountInNamespaceFlags flags = 0;
421 uid_t uid;
422 int r;
423
424 assert(message);
425
426 if (m->class != MACHINE_CONTAINER)
427 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
428
429 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory);
430 if (r < 0)
431 return r;
432
433 if (!path_is_absolute(src) || !path_is_normalized(src))
434 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized.");
435
436 if (isempty(dest))
437 dest = src;
438 else if (!path_is_absolute(dest) || !path_is_normalized(dest))
439 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized.");
440
441 const char *details[] = {
442 "machine", m->name,
443 "verb", "bind",
444 "src", src,
445 "dest", dest,
446 NULL
447 };
448
449 r = bus_verify_polkit_async(
450 message,
451 "org.freedesktop.machine1.manage-machines",
452 details,
453 &m->manager->polkit_registry,
454 error);
455 if (r < 0)
456 return r;
457 if (r == 0)
458 return 1; /* Will call us back */
459
460 r = machine_get_uid_shift(m, &uid);
461 if (r < 0)
462 return r;
463 if (uid != 0)
464 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied.");
465
466 if (read_only)
467 flags |= MOUNT_IN_NAMESPACE_READ_ONLY;
468 if (make_file_or_directory)
469 flags |= MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY;
470
471 propagate_directory = strjoina("/run/systemd/nspawn/propagate/", m->name);
472 r = bind_mount_in_namespace(
473 &m->leader,
474 propagate_directory,
475 "/run/host/incoming/",
476 src, dest,
477 flags);
478 if (r < 0)
479 return sd_bus_error_set_errnof(error, r, "Failed to mount %s on %s in machine's namespace: %m", src, dest);
480
481 return sd_bus_reply_method_return(message, NULL);
482}
483
484int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
485 const char *src, *dest, *host_path, *container_path;
486 CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS;
487 Machine *m = ASSERT_PTR(userdata);
488 Manager *manager = m->manager;
489 bool copy_from;
490 int r;
491
492 assert(message);
493
494 if (m->manager->n_operations >= OPERATIONS_MAX)
495 return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
496
497 if (m->class != MACHINE_CONTAINER)
498 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
499
500 r = sd_bus_message_read(message, "ss", &src, &dest);
501 if (r < 0)
502 return r;
503
504 if (endswith(sd_bus_message_get_member(message), "WithFlags")) {
505 uint64_t raw_flags;
506
507 r = sd_bus_message_read(message, "t", &raw_flags);
508 if (r < 0)
509 return r;
510
511 if ((raw_flags & ~_MACHINE_COPY_FLAGS_MASK_PUBLIC) != 0)
512 return -EINVAL;
513
514 if (raw_flags & MACHINE_COPY_REPLACE)
515 copy_flags |= COPY_REPLACE;
516 }
517
518 if (!path_is_absolute(src))
519 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
520
521 if (isempty(dest))
522 dest = src;
523 else if (!path_is_absolute(dest))
524 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
525
526 const char *details[] = {
527 "machine", m->name,
528 "verb", "copy",
529 "src", src,
530 "dest", dest,
531 NULL
532 };
533
534 r = bus_verify_polkit_async(
535 message,
536 "org.freedesktop.machine1.manage-machines",
537 details,
538 &manager->polkit_registry,
539 error);
540 if (r < 0)
541 return r;
542 if (r == 0)
543 return 1; /* Will call us back */
544
545 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
546
547 if (copy_from) {
548 container_path = src;
549 host_path = dest;
550 } else {
551 host_path = src;
552 container_path = dest;
553 }
554
555 Operation *op;
556 r = machine_copy_from_to_operation(manager, m, host_path, container_path, copy_from, copy_flags, &op);
557 if (r < 0)
558 return sd_bus_error_set_errnof(error, r, "Failed to copy from/to machine '%s': %m", m->name);
559
560 operation_attach_bus_reply(op, message);
561 return 1;
562}
563
564int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
565 _cleanup_close_ int fd = -EBADF;
566 Machine *m = ASSERT_PTR(userdata);
567 int r;
568
569 assert(message);
570
571 const char *details[] = {
572 "machine", m->name,
573 "verb", "open_root_directory",
574 NULL
575 };
576
577 r = bus_verify_polkit_async(
578 message,
579 "org.freedesktop.machine1.manage-machines",
580 details,
581 &m->manager->polkit_registry,
582 error);
583 if (r < 0)
584 return r;
585 if (r == 0)
586 return 1; /* Will call us back */
587
588 fd = machine_open_root_directory(m);
589 if (ERRNO_IS_NEG_NOT_SUPPORTED(fd))
590 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
591 if (fd < 0)
592 return sd_bus_error_set_errnof(error, fd, "Failed to open root directory of machine '%s': %m", m->name);
593
594 return sd_bus_reply_method_return(message, "h", fd);
595}
596
597int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
598 Machine *m = ASSERT_PTR(userdata);
599 uid_t shift = 0;
600 int r;
601
602 assert(message);
603
604 /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but
605 * we kinda have to for this. */
606
607 if (m->class == MACHINE_HOST)
608 return sd_bus_reply_method_return(message, "u", UINT32_C(0));
609
610 if (m->class != MACHINE_CONTAINER)
611 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines.");
612
613 r = machine_get_uid_shift(m, &shift);
614 if (r == -ENXIO)
615 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m->name);
616 if (r < 0)
617 return r;
618
619 return sd_bus_reply_method_return(message, "u", (uint32_t) shift);
620}
621
622static int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
623 Manager *m = ASSERT_PTR(userdata);
624 Machine *machine;
625 int r;
626
627 assert(bus);
628 assert(path);
629 assert(interface);
630 assert(found);
631
632 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
633 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
634 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
635 sd_bus_message *message;
636
637 message = sd_bus_get_current_message(bus);
638 if (!message)
639 return 0;
640
641 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID|SD_BUS_CREDS_PIDFD, &creds);
642 if (r < 0)
643 return r;
644
645 r = bus_creds_get_pidref(creds, &pidref);
646 if (r < 0)
647 return r;
648
649 r = manager_get_machine_by_pidref(m, &pidref, &machine);
650 if (r <= 0)
651 return 0;
652 } else {
653 _cleanup_free_ char *e = NULL;
654 const char *p;
655
656 p = startswith(path, "/org/freedesktop/machine1/machine/");
657 if (!p)
658 return 0;
659
660 e = bus_label_unescape(p);
661 if (!e)
662 return -ENOMEM;
663
664 machine = hashmap_get(m->machines, e);
665 if (!machine)
666 return 0;
667 }
668
669 *found = machine;
670 return 1;
671}
672
673char* machine_bus_path(Machine *m) {
674 _cleanup_free_ char *e = NULL;
675
676 assert(m);
677
678 e = bus_label_escape(m->name);
679 if (!e)
680 return NULL;
681
682 return strjoin("/org/freedesktop/machine1/machine/", e);
683}
684
685static int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
686 _cleanup_strv_free_ char **l = NULL;
687 Machine *machine = NULL;
688 Manager *m = userdata;
689 int r;
690
691 assert(bus);
692 assert(path);
693 assert(nodes);
694
695 HASHMAP_FOREACH(machine, m->machines) {
696 char *p;
697
698 p = machine_bus_path(machine);
699 if (!p)
700 return -ENOMEM;
701
702 r = strv_consume(&l, p);
703 if (r < 0)
704 return r;
705 }
706
707 *nodes = TAKE_PTR(l);
708
709 return 1;
710}
711
712static const sd_bus_vtable machine_vtable[] = {
713 SD_BUS_VTABLE_START(0),
714 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
715 SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST),
716 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
717 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
718 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
719 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
720 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Machine, leader.pid), SD_BUS_VTABLE_PROPERTY_CONST),
721 SD_BUS_PROPERTY("LeaderPIDFDId", "t", bus_property_get_pidfdid, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
722 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
723 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
724 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
725 SD_BUS_PROPERTY("VSockCID", "u", NULL, offsetof(Machine, vsock_cid), SD_BUS_VTABLE_PROPERTY_CONST),
726 SD_BUS_PROPERTY("SSHAddress", "s", NULL, offsetof(Machine, ssh_address), SD_BUS_VTABLE_PROPERTY_CONST),
727 SD_BUS_PROPERTY("SSHPrivateKeyPath", "s", NULL, offsetof(Machine, ssh_private_key_path), SD_BUS_VTABLE_PROPERTY_CONST),
728 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
729
730 SD_BUS_METHOD("Terminate",
731 NULL,
732 NULL,
733 bus_machine_method_terminate,
734 SD_BUS_VTABLE_UNPRIVILEGED),
735 SD_BUS_METHOD_WITH_ARGS("Kill",
736 SD_BUS_ARGS("s", whom, "i", signal),
737 SD_BUS_NO_RESULT,
738 bus_machine_method_kill,
739 SD_BUS_VTABLE_UNPRIVILEGED),
740 SD_BUS_METHOD_WITH_ARGS("GetAddresses",
741 SD_BUS_NO_ARGS,
742 SD_BUS_RESULT("a(iay)", addresses),
743 bus_machine_method_get_addresses,
744 SD_BUS_VTABLE_UNPRIVILEGED),
745 SD_BUS_METHOD_WITH_ARGS("GetSSHInfo",
746 SD_BUS_NO_ARGS,
747 SD_BUS_RESULT("s", ssh_address, "s", ssh_private_key_path),
748 bus_machine_method_get_ssh_info,
749 SD_BUS_VTABLE_UNPRIVILEGED),
750 SD_BUS_METHOD_WITH_ARGS("GetOSRelease",
751 SD_BUS_NO_ARGS,
752 SD_BUS_RESULT("a{ss}", fields),
753 bus_machine_method_get_os_release,
754 SD_BUS_VTABLE_UNPRIVILEGED),
755 SD_BUS_METHOD_WITH_ARGS("GetUIDShift",
756 SD_BUS_NO_ARGS,
757 SD_BUS_RESULT("u", shift),
758 bus_machine_method_get_uid_shift,
759 SD_BUS_VTABLE_UNPRIVILEGED),
760 SD_BUS_METHOD_WITH_ARGS("OpenPTY",
761 SD_BUS_NO_ARGS,
762 SD_BUS_RESULT("h", pty, "s", pty_path),
763 bus_machine_method_open_pty,
764 SD_BUS_VTABLE_UNPRIVILEGED),
765 SD_BUS_METHOD_WITH_ARGS("OpenLogin",
766 SD_BUS_NO_ARGS,
767 SD_BUS_RESULT("h", pty, "s", pty_path),
768 bus_machine_method_open_login,
769 SD_BUS_VTABLE_UNPRIVILEGED),
770 SD_BUS_METHOD_WITH_ARGS("OpenShell",
771 SD_BUS_ARGS("s", user, "s", path, "as", args, "as", environment),
772 SD_BUS_RESULT("h", pty, "s", pty_path),
773 bus_machine_method_open_shell,
774 SD_BUS_VTABLE_UNPRIVILEGED),
775 SD_BUS_METHOD_WITH_ARGS("BindMount",
776 SD_BUS_ARGS("s", source, "s", destination, "b", read_only, "b", mkdir),
777 SD_BUS_NO_RESULT,
778 bus_machine_method_bind_mount,
779 SD_BUS_VTABLE_UNPRIVILEGED),
780 SD_BUS_METHOD_WITH_ARGS("CopyFrom",
781 SD_BUS_ARGS("s", source, "s", destination),
782 SD_BUS_NO_RESULT,
783 bus_machine_method_copy,
784 SD_BUS_VTABLE_UNPRIVILEGED),
785 SD_BUS_METHOD_WITH_ARGS("CopyTo",
786 SD_BUS_ARGS("s", source, "s", destination),
787 SD_BUS_NO_RESULT,
788 bus_machine_method_copy,
789 SD_BUS_VTABLE_UNPRIVILEGED),
790 SD_BUS_METHOD_WITH_ARGS("CopyFromWithFlags",
791 SD_BUS_ARGS("s", source, "s", destination, "t", flags),
792 SD_BUS_NO_RESULT,
793 bus_machine_method_copy,
794 SD_BUS_VTABLE_UNPRIVILEGED),
795 SD_BUS_METHOD_WITH_ARGS("CopyToWithFlags",
796 SD_BUS_ARGS("s", source, "s", destination, "t", flags),
797 SD_BUS_NO_RESULT,
798 bus_machine_method_copy,
799 SD_BUS_VTABLE_UNPRIVILEGED),
800 SD_BUS_METHOD_WITH_ARGS("OpenRootDirectory",
801 SD_BUS_NO_ARGS,
802 SD_BUS_RESULT("h", fd),
803 bus_machine_method_open_root_directory,
804 SD_BUS_VTABLE_UNPRIVILEGED),
805
806 SD_BUS_VTABLE_END
807};
808
809const BusObjectImplementation machine_object = {
810 "/org/freedesktop/machine1/machine",
811 "org.freedesktop.machine1.Machine",
812 .fallback_vtables = BUS_FALLBACK_VTABLES({machine_vtable, machine_object_find}),
813 .node_enumerator = machine_node_enumerator,
814};
815
816int machine_send_signal(Machine *m, bool new_machine) {
817 _cleanup_free_ char *p = NULL;
818
819 assert(m);
820
821 p = machine_bus_path(m);
822 if (!p)
823 return -ENOMEM;
824
825 return sd_bus_emit_signal(
826 m->manager->bus,
827 "/org/freedesktop/machine1",
828 "org.freedesktop.machine1.Manager",
829 new_machine ? "MachineNew" : "MachineRemoved",
830 "so", m->name, p);
831}
832
833int machine_send_create_reply(Machine *m, sd_bus_error *error) {
834 _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
835 _cleanup_free_ char *p = NULL;
836
837 assert(m);
838
839 if (!m->create_message)
840 return 0;
841
842 c = TAKE_PTR(m->create_message);
843
844 if (error)
845 return sd_bus_reply_method_error(c, error);
846
847 /* Update the machine state file before we notify the client
848 * about the result. */
849 machine_save(m);
850
851 p = machine_bus_path(m);
852 if (!p)
853 return -ENOMEM;
854
855 return sd_bus_reply_method_return(c, "o", p);
856}