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