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