]> git.ipfire.org Git - thirdparty/systemd.git/blame - 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
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
9444b1f2 2
64943cac 3#include "sd-bus.h"
9444b1f2 4
b5efdb8a 5#include "alloc-util.h"
96aad8d1 6#include "bus-common-errors.h"
40af3d02 7#include "bus-get-properties.h"
3ffd4af2 8#include "bus-label.h"
64943cac 9#include "bus-object.h"
269e4d2d 10#include "bus-polkit.h"
ff43267c 11#include "bus-util.h"
717603e3 12#include "copy.h"
3ffd4af2 13#include "env-util.h"
64943cac 14#include "errno-util.h"
3ffd4af2 15#include "fd-util.h"
64943cac 16#include "hashmap.h"
3b653205 17#include "in-addr-util.h"
496a5a69 18#include "local-addresses.h"
3ffd4af2 19#include "machine.h"
1cf40697 20#include "machine-dbus.h"
ff43267c 21#include "machined.h"
21935150 22#include "mount-util.h"
ff43267c 23#include "operation.h"
3ffd4af2 24#include "path-util.h"
6eb7c172 25#include "signal-util.h"
64943cac 26#include "string-util.h"
3ffd4af2 27#include "strv.h"
9444b1f2 28
74c308ae
YW
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);
fb6becb4 31
9b5ed6fe
LP
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
99534007 41 Machine *m = ASSERT_PTR(userdata);
9b5ed6fe
LP
42
43 assert(bus);
44 assert(reply);
9b5ed6fe
LP
45
46 assert_cc(sizeof(int) == sizeof(int32_t));
47
0f826101 48 return sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
9b5ed6fe
LP
49}
50
ef8ff92e 51int bus_machine_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error) {
99534007 52 Machine *m = ASSERT_PTR(userdata);
ef8ff92e
ZJS
53 int r;
54
55 assert(message);
ef8ff92e 56
8dd3f6a3
LN
57 const char *details[] = {
58 "machine", m->name,
59 "verb", "unregister",
60 NULL
61 };
62
ef8ff92e
ZJS
63 r = bus_verify_polkit_async(
64 message,
ef8ff92e 65 "org.freedesktop.machine1.manage-machines",
8dd3f6a3 66 details,
ef8ff92e
ZJS
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
19070062 81int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
99534007 82 Machine *m = ASSERT_PTR(userdata);
c3350683 83 int r;
9444b1f2 84
c3350683 85 assert(message);
9444b1f2 86
8dd3f6a3
LN
87 const char *details[] = {
88 "machine", m->name,
89 "verb", "terminate",
90 NULL
91 };
92
70244d1d
LP
93 r = bus_verify_polkit_async(
94 message,
70244d1d 95 "org.freedesktop.machine1.manage-machines",
8dd3f6a3 96 details,
70244d1d
LP
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
c3350683
LP
104 r = machine_stop(m);
105 if (r < 0)
ebcf1f97 106 return r;
9444b1f2 107
df2d202e 108 return sd_bus_reply_method_return(message, NULL);
9444b1f2
LP
109}
110
19070062 111int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
99534007 112 Machine *m = ASSERT_PTR(userdata);
c3350683
LP
113 const char *swho;
114 int32_t signo;
cd2fb049 115 KillWhom whom;
9444b1f2
LP
116 int r;
117
9444b1f2
LP
118 assert(message);
119
c3350683
LP
120 r = sd_bus_message_read(message, "si", &swho, &signo);
121 if (r < 0)
ebcf1f97 122 return r;
9444b1f2 123
c3350683 124 if (isempty(swho))
cd2fb049 125 whom = KILL_ALL;
c3350683 126 else {
cd2fb049
ZJS
127 whom = kill_whom_from_string(swho);
128 if (whom < 0)
ebcf1f97 129 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
9444b1f2
LP
130 }
131
6eb7c172 132 if (!SIGNAL_VALID(signo))
ebcf1f97 133 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
9444b1f2 134
8dd3f6a3
LN
135 const char *details[] = {
136 "machine", m->name,
137 "verb", "kill",
138 NULL
139 };
140
70244d1d
LP
141 r = bus_verify_polkit_async(
142 message,
70244d1d 143 "org.freedesktop.machine1.manage-machines",
8dd3f6a3 144 details,
70244d1d
LP
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
cd2fb049 152 r = machine_kill(m, whom, signo);
c3350683 153 if (r < 0)
ebcf1f97 154 return r;
9444b1f2 155
df2d202e 156 return sd_bus_reply_method_return(message, NULL);
9444b1f2
LP
157}
158
19070062 159int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 160 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f1daf9fb 161 _cleanup_free_ struct local_address *addresses = NULL;
99534007 162 Machine *m = ASSERT_PTR(userdata);
878cd7e9
LP
163 int r;
164
878cd7e9 165 assert(message);
878cd7e9 166
fbe55073 167 r = sd_bus_message_new_method_return(message, &reply);
878cd7e9 168 if (r < 0)
c7abe32b 169 return r;
878cd7e9 170
fbe55073 171 r = sd_bus_message_open_container(reply, 'a', "(iay)");
878cd7e9 172 if (r < 0)
c7abe32b 173 return r;
878cd7e9 174
f1daf9fb
IK
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");
878cd7e9 182
f1daf9fb
IK
183 for (int i = 0; i < n; i++) {
184 r = sd_bus_message_open_container(reply, 'r', "iay");
fbe55073
LP
185 if (r < 0)
186 return r;
f1daf9fb
IK
187
188 r = sd_bus_message_append(reply, "i", addresses[i].family);
878cd7e9 189 if (r < 0)
c7abe32b 190 return r;
878cd7e9 191
f1daf9fb 192 r = sd_bus_message_append_array(reply, 'y', &addresses[i].address, FAMILY_ADDRESS_SIZE(addresses[i].family));
4c253ed1 193 if (r < 0)
f1daf9fb 194 return r;
878cd7e9 195
f1daf9fb
IK
196 r = sd_bus_message_close_container(reply);
197 if (r < 0)
198 return r;
fbe55073 199 }
878cd7e9
LP
200
201 r = sd_bus_message_close_container(reply);
202 if (r < 0)
c7abe32b 203 return r;
878cd7e9 204
51cc3825 205 return sd_bus_message_send(reply);
878cd7e9
LP
206}
207
1f815bf1
SL
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
51cc3825 226 return sd_bus_message_send(reply);
1f815bf1
SL
227}
228
19070062 229int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
717603e3 230 _cleanup_strv_free_ char **l = NULL;
99534007 231 Machine *m = ASSERT_PTR(userdata);
717603e3
LP
232 int r;
233
717603e3 234 assert(message);
717603e3 235
31f9f589
IK
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))
1b09b81c 240 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
31f9f589
IK
241 if (r < 0)
242 return sd_bus_error_set_errnof(error, r, "Failed to get OS release: %m");
717603e3 243
9153b02b 244 return bus_reply_pair_array(message, l);
40205d70
LP
245}
246
19070062 247int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 248 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
5f8cc96a 249 _cleanup_free_ char *pty_name = NULL;
5bb1d7fb 250 _cleanup_close_ int master = -EBADF;
99534007 251 Machine *m = ASSERT_PTR(userdata);
40205d70
LP
252 int r;
253
40205d70 254 assert(message);
40205d70 255
8dd3f6a3
LN
256 const char *details[] = {
257 "machine", m->name,
258 NULL
259 };
260
fbe55073
LP
261 r = bus_verify_polkit_async(
262 message,
4289c3a7 263 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty",
8dd3f6a3 264 details,
fbe55073
LP
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 */
b4d8ef7c 271
ae1d13db 272 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
5f8cc96a
LP
273 if (master < 0)
274 return master;
275
5f8cc96a
LP
276 r = sd_bus_message_new_method_return(message, &reply);
277 if (r < 0)
278 return r;
40205d70 279
5f8cc96a
LP
280 r = sd_bus_message_append(reply, "hs", master, pty_name);
281 if (r < 0)
282 return r;
40205d70 283
51cc3825 284 return sd_bus_message_send(reply);
5f8cc96a 285}
40205d70 286
19070062 287int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 288 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
49af9e13 289 _cleanup_free_ char *pty_name = NULL;
5bb1d7fb 290 _cleanup_close_ int master = -EBADF;
99534007 291 Machine *m = ASSERT_PTR(userdata);
5f8cc96a 292 int r;
40205d70 293
19070062 294 assert(message);
19070062 295
8dd3f6a3
LN
296 const char *details[] = {
297 "machine", m->name,
298 "verb", "login",
299 NULL
300 };
301
d04c1fb8
LP
302 r = bus_verify_polkit_async(
303 message,
4289c3a7 304 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
8dd3f6a3 305 details,
d04c1fb8
LP
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
ae1d13db 313 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
5f8cc96a
LP
314 if (master < 0)
315 return master;
40205d70 316
41f1f283 317 r = machine_start_getty(m, pty_name, error);
49af9e13
LP
318 if (r < 0)
319 return r;
320
49af9e13
LP
321 r = sd_bus_message_new_method_return(message, &reply);
322 if (r < 0)
323 return r;
40205d70 324
49af9e13 325 r = sd_bus_message_append(reply, "hs", master, pty_name);
5f8cc96a
LP
326 if (r < 0)
327 return r;
40205d70 328
51cc3825 329 return sd_bus_message_send(reply);
49af9e13 330}
5f8cc96a 331
49af9e13 332int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
41f1f283 333 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
49af9e13 334 _cleanup_free_ char *pty_name = NULL;
41f1f283 335 _cleanup_close_ int master = -EBADF;
c46bc7e2 336 _cleanup_strv_free_ char **env = NULL, **args_wire = NULL, **args = NULL;
d353fcce 337 _cleanup_free_ char *command_line = NULL;
99534007 338 Machine *m = ASSERT_PTR(userdata);
41f1f283 339 const char *user, *path;
49af9e13
LP
340 int r;
341
342 assert(message);
49af9e13
LP
343
344 r = sd_bus_message_read(message, "ss", &user, &path);
345 if (r < 0)
346 return r;
09364a80 347 user = isempty(user) ? "root" : user;
c46bc7e2 348 r = sd_bus_message_read_strv(message, &args_wire);
49af9e13
LP
349 if (r < 0)
350 return r;
c46bc7e2 351 if (isempty(path)) {
b0eca6de
IK
352 path = machine_default_shell_path();
353 args = machine_default_shell_args(user);
49af9e13
LP
354 if (!args)
355 return -ENOMEM;
c46bc7e2
SL
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);
1cc6c93a 359 args = TAKE_PTR(args_wire);
c46bc7e2
SL
360 if (strv_isempty(args)) {
361 args = strv_free(args);
362
bea1a013 363 args = strv_new(path);
c46bc7e2
SL
364 if (!args)
365 return -ENOMEM;
366 }
49af9e13
LP
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))
1b09b81c 373 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
49af9e13 374
d353fcce
LN
375 command_line = strv_join(args, " ");
376 if (!command_line)
377 return -ENOMEM;
09364a80
MR
378 const char *details[] = {
379 "machine", m->name,
380 "user", user,
381 "program", path,
d353fcce 382 "command_line", command_line,
09364a80
MR
383 NULL
384 };
385
49af9e13
LP
386 r = bus_verify_polkit_async(
387 message,
4289c3a7 388 m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
09364a80 389 details,
49af9e13
LP
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
ae1d13db 397 master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
49af9e13
LP
398 if (master < 0)
399 return master;
400
41f1f283 401 r = machine_start_shell(m, master, pty_name, user, path, args, env, error);
49af9e13
LP
402 if (r < 0)
403 return r;
404
40205d70
LP
405 r = sd_bus_message_new_method_return(message, &reply);
406 if (r < 0)
407 return r;
408
ee451d76 409 r = sd_bus_message_append(reply, "hs", master, pty_name);
40205d70
LP
410 if (r < 0)
411 return r;
717603e3 412
51cc3825 413 return sd_bus_message_send(reply);
717603e3
LP
414}
415
19070062 416int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d3590ace 417 int read_only, make_file_or_directory;
6af52c3a 418 const char *dest, *src, *propagate_directory;
99534007 419 Machine *m = ASSERT_PTR(userdata);
5162829e 420 MountInNamespaceFlags flags = 0;
7f43928b 421 uid_t uid;
90adaa25
LP
422 int r;
423
19070062 424 assert(message);
19070062 425
90adaa25 426 if (m->class != MACHINE_CONTAINER)
1b09b81c 427 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
90adaa25 428
d3590ace 429 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory);
90adaa25
LP
430 if (r < 0)
431 return r;
432
99be45a4 433 if (!path_is_absolute(src) || !path_is_normalized(src))
1b09b81c 434 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized.");
90adaa25
LP
435
436 if (isempty(dest))
437 dest = src;
99be45a4 438 else if (!path_is_absolute(dest) || !path_is_normalized(dest))
1b09b81c 439 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized.");
90adaa25 440
8dd3f6a3
LN
441 const char *details[] = {
442 "machine", m->name,
443 "verb", "bind",
444 "src", src,
445 "dest", dest,
446 NULL
447 };
448
70244d1d
LP
449 r = bus_verify_polkit_async(
450 message,
70244d1d 451 "org.freedesktop.machine1.manage-machines",
8dd3f6a3 452 details,
70244d1d
LP
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
7f43928b
LP
460 r = machine_get_uid_shift(m, &uid);
461 if (r < 0)
462 return r;
463 if (uid != 0)
1b09b81c 464 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied.");
7f43928b 465
5162829e
LB
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
6af52c3a 471 propagate_directory = strjoina("/run/systemd/nspawn/propagate/", m->name);
d8854ff1 472 r = bind_mount_in_namespace(
5f48198a 473 &m->leader,
d8854ff1
LP
474 propagate_directory,
475 "/run/host/incoming/",
476 src, dest,
5162829e 477 flags);
d3590ace 478 if (r < 0)
6af52c3a 479 return sd_bus_error_set_errnof(error, r, "Failed to mount %s on %s in machine's namespace: %m", src, dest);
90adaa25 480
6af52c3a 481 return sd_bus_reply_method_return(message, NULL);
90adaa25
LP
482}
483
19070062 484int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
45519d13 485 const char *src, *dest, *host_path, *container_path;
652d9040 486 CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS;
99534007 487 Machine *m = ASSERT_PTR(userdata);
8632e7ae 488 Manager *manager = m->manager;
0370612e 489 bool copy_from;
0370612e
LP
490 int r;
491
19070062 492 assert(message);
19070062 493
795c5d31 494 if (m->manager->n_operations >= OPERATIONS_MAX)
1b09b81c 495 return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
0370612e
LP
496
497 if (m->class != MACHINE_CONTAINER)
1b09b81c 498 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
0370612e
LP
499
500 r = sd_bus_message_read(message, "ss", &src, &dest);
501 if (r < 0)
502 return r;
503
ae03e1a9
AW
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
d8440176 518 if (!path_is_absolute(src))
1b09b81c 519 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
0370612e
LP
520
521 if (isempty(dest))
522 dest = src;
d8440176 523 else if (!path_is_absolute(dest))
1b09b81c 524 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
0370612e 525
8dd3f6a3
LN
526 const char *details[] = {
527 "machine", m->name,
528 "verb", "copy",
529 "src", src,
530 "dest", dest,
531 NULL
532 };
533
70244d1d
LP
534 r = bus_verify_polkit_async(
535 message,
70244d1d 536 "org.freedesktop.machine1.manage-machines",
8dd3f6a3 537 details,
8632e7ae 538 &manager->polkit_registry,
70244d1d
LP
539 error);
540 if (r < 0)
541 return r;
542 if (r == 0)
543 return 1; /* Will call us back */
544
0370612e
LP
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
8632e7ae 555 Operation *op;
2694549d 556 r = machine_copy_from_to_operation(manager, m, host_path, container_path, copy_from, copy_flags, &op);
45519d13 557 if (r < 0)
8632e7ae 558 return sd_bus_error_set_errnof(error, r, "Failed to copy from/to machine '%s': %m", m->name);
0370612e 559
8632e7ae 560 operation_attach_bus_reply(op, message);
0370612e
LP
561 return 1;
562}
563
ae203207 564int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
254d1313 565 _cleanup_close_ int fd = -EBADF;
99534007 566 Machine *m = ASSERT_PTR(userdata);
ae203207
LP
567 int r;
568
569 assert(message);
ae203207 570
8dd3f6a3
LN
571 const char *details[] = {
572 "machine", m->name,
573 "verb", "open_root_directory",
574 NULL
575 };
576
ae203207
LP
577 r = bus_verify_polkit_async(
578 message,
ae203207 579 "org.freedesktop.machine1.manage-machines",
8dd3f6a3 580 details,
ae203207
LP
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
307458a6
IK
588 fd = machine_open_root_directory(m);
589 if (ERRNO_IS_NEG_NOT_SUPPORTED(fd))
1b09b81c 590 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
307458a6
IK
591 if (fd < 0)
592 return sd_bus_error_set_errnof(error, fd, "Failed to open root directory of machine '%s': %m", m->name);
ae203207
LP
593
594 return sd_bus_reply_method_return(message, "h", fd);
595}
596
3401419b 597int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
99534007 598 Machine *m = ASSERT_PTR(userdata);
3401419b
LP
599 uid_t shift = 0;
600 int r;
601
602 assert(message);
3401419b
LP
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)
1b09b81c 611 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines.");
3401419b
LP
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
4faa530c 622static int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
99534007 623 Manager *m = ASSERT_PTR(userdata);
4faa530c
ZJS
624 Machine *machine;
625 int r;
626
627 assert(bus);
628 assert(path);
629 assert(interface);
630 assert(found);
4faa530c
ZJS
631
632 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
f6cb4d4a 633 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
4faa530c
ZJS
634 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
635 sd_bus_message *message;
4faa530c
ZJS
636
637 message = sd_bus_get_current_message(bus);
638 if (!message)
639 return 0;
640
f6cb4d4a 641 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID|SD_BUS_CREDS_PIDFD, &creds);
4faa530c
ZJS
642 if (r < 0)
643 return r;
644
f6cb4d4a 645 r = bus_creds_get_pidref(creds, &pidref);
4faa530c
ZJS
646 if (r < 0)
647 return r;
648
f6cb4d4a 649 r = manager_get_machine_by_pidref(m, &pidref, &machine);
4faa530c
ZJS
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
ff3f2953 673char* machine_bus_path(Machine *m) {
4faa530c
ZJS
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;
4faa530c
ZJS
689 int r;
690
691 assert(bus);
692 assert(path);
693 assert(nodes);
694
90e74a66 695 HASHMAP_FOREACH(machine, m->machines) {
4faa530c
ZJS
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[] = {
c3350683 713 SD_BUS_VTABLE_START(0),
556089dc 714 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
766c94ad 715 SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
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),
89f7c846
LP
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),
98fc46f2
LP
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),
556089dc
LP
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),
9b5ed6fe 724 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1f815bf1
SL
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),
c3350683 728 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
bbe17ca1
ZJS
729
730 SD_BUS_METHOD("Terminate",
731 NULL,
732 NULL,
733 bus_machine_method_terminate,
734 SD_BUS_VTABLE_UNPRIVILEGED),
d5e4e60b 735 SD_BUS_METHOD_WITH_ARGS("Kill",
cd2fb049 736 SD_BUS_ARGS("s", whom, "i", signal),
d5e4e60b
A
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),
1f815bf1
SL
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),
d5e4e60b
A
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),
ae03e1a9
AW
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),
d5e4e60b
A
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),
bbe17ca1 805
717603e3 806 SD_BUS_VTABLE_END
c3350683 807};
9444b1f2 808
4faa530c
ZJS
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};
927b1649 815
9444b1f2 816int machine_send_signal(Machine *m, bool new_machine) {
9444b1f2
LP
817 _cleanup_free_ char *p = NULL;
818
819 assert(m);
820
9444b1f2
LP
821 p = machine_bus_path(m);
822 if (!p)
823 return -ENOMEM;
824
c3350683
LP
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);
9444b1f2
LP
831}
832
c3350683 833int machine_send_create_reply(Machine *m, sd_bus_error *error) {
4afd3348 834 _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
9444b1f2
LP
835 _cleanup_free_ char *p = NULL;
836
837 assert(m);
838
fb6becb4
LP
839 if (!m->create_message)
840 return 0;
841
1cc6c93a 842 c = TAKE_PTR(m->create_message);
fb6becb4 843
a658cafa 844 if (error)
df2d202e 845 return sd_bus_reply_method_error(c, error);
a658cafa 846
76e66585
LP
847 /* Update the machine state file before we notify the client
848 * about the result. */
849 machine_save(m);
850
c3350683
LP
851 p = machine_bus_path(m);
852 if (!p)
853 return -ENOMEM;
fb6becb4 854
df2d202e 855 return sd_bus_reply_method_return(c, "o", p);
fb6becb4 856}