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