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