File: | build-scan/../src/machine/machine-dbus.c |
Warning: | line 589, column 33 Potential leak of memory pointed to by 'args' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <errno(*__errno_location ()).h> | |||
4 | #include <string.h> | |||
5 | #include <sys/mount.h> | |||
6 | #include <sys/wait.h> | |||
7 | ||||
8 | /* When we include libgen.h because we need dirname() we immediately | |||
9 | * undefine basename() since libgen.h defines it as a macro to the POSIX | |||
10 | * version which is really broken. We prefer GNU basename(). */ | |||
11 | #include <libgen.h> | |||
12 | #undef basename | |||
13 | ||||
14 | #include "alloc-util.h" | |||
15 | #include "bus-common-errors.h" | |||
16 | #include "bus-internal.h" | |||
17 | #include "bus-label.h" | |||
18 | #include "bus-util.h" | |||
19 | #include "copy.h" | |||
20 | #include "env-util.h" | |||
21 | #include "fd-util.h" | |||
22 | #include "fileio.h" | |||
23 | #include "format-util.h" | |||
24 | #include "fs-util.h" | |||
25 | #include "in-addr-util.h" | |||
26 | #include "local-addresses.h" | |||
27 | #include "machine-dbus.h" | |||
28 | #include "machine.h" | |||
29 | #include "mkdir.h" | |||
30 | #include "os-util.h" | |||
31 | #include "path-util.h" | |||
32 | #include "process-util.h" | |||
33 | #include "signal-util.h" | |||
34 | #include "strv.h" | |||
35 | #include "terminal-util.h" | |||
36 | #include "user-util.h" | |||
37 | ||||
38 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass)int property_get_class(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) { MachineClass *data = userdata ; do { if ((__builtin_expect(!!(!(bus)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("bus"), "../src/machine/machine-dbus.c", 38, __PRETTY_FUNCTION__); } while (0); do { if ((__builtin_expect (!!(!(reply)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("reply"), "../src/machine/machine-dbus.c", 38, __PRETTY_FUNCTION__ ); } while (0); do { if ((__builtin_expect(!!(!(data)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("data"), "../src/machine/machine-dbus.c" , 38, __PRETTY_FUNCTION__); } while (0); return sd_bus_message_append (reply, "s", machine_class_to_string((*(data)))); }; | |||
39 | static BUS_DEFINE_PROPERTY_GET2(property_get_state, "s", Machine, machine_get_state, machine_state_to_string)int property_get_state(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) { Machine *data = userdata; do { if ((__builtin_expect(!!(!(bus)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("bus"), "../src/machine/machine-dbus.c", 39, __PRETTY_FUNCTION__); } while (0); do { if ((__builtin_expect (!!(!(reply)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("reply"), "../src/machine/machine-dbus.c", 39, __PRETTY_FUNCTION__ ); } while (0); do { if ((__builtin_expect(!!(!(data)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("data"), "../src/machine/machine-dbus.c" , 39, __PRETTY_FUNCTION__); } while (0); return sd_bus_message_append (reply, "s", machine_state_to_string(machine_get_state(data)) ); }; | |||
40 | ||||
41 | static int property_get_netif( | |||
42 | sd_bus *bus, | |||
43 | const char *path, | |||
44 | const char *interface, | |||
45 | const char *property, | |||
46 | sd_bus_message *reply, | |||
47 | void *userdata, | |||
48 | sd_bus_error *error) { | |||
49 | ||||
50 | Machine *m = userdata; | |||
51 | ||||
52 | assert(bus)do { if ((__builtin_expect(!!(!(bus)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("bus"), "../src/machine/machine-dbus.c", 52, __PRETTY_FUNCTION__); } while (0); | |||
53 | assert(reply)do { if ((__builtin_expect(!!(!(reply)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("reply"), "../src/machine/machine-dbus.c" , 53, __PRETTY_FUNCTION__); } while (0); | |||
54 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 54 , __PRETTY_FUNCTION__); } while (0); | |||
55 | ||||
56 | assert_cc(sizeof(int) == sizeof(int32_t))GCC diagnostic push
; GCC diagnostic ignored "-Wdeclaration-after-statement" ; struct _assert_struct_10 { char x[(sizeof(int) == sizeof(int32_t )) ? 0 : -1]; }; GCC diagnostic pop ; | |||
57 | ||||
58 | return sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int)); | |||
59 | } | |||
60 | ||||
61 | int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
62 | Machine *m = userdata; | |||
63 | int r; | |||
64 | ||||
65 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/machine/machine-dbus.c" , 65, __PRETTY_FUNCTION__); } while (0); | |||
66 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 66 , __PRETTY_FUNCTION__); } while (0); | |||
67 | ||||
68 | r = bus_verify_polkit_async( | |||
69 | message, | |||
70 | CAP_KILL5, | |||
71 | "org.freedesktop.machine1.manage-machines", | |||
72 | NULL((void*)0), | |||
73 | false0, | |||
74 | UID_INVALID((uid_t) -1), | |||
75 | &m->manager->polkit_registry, | |||
76 | error); | |||
77 | if (r < 0) | |||
78 | return r; | |||
79 | if (r == 0) | |||
80 | return 1; /* Will call us back */ | |||
81 | ||||
82 | r = machine_stop(m); | |||
83 | if (r < 0) | |||
84 | return r; | |||
85 | ||||
86 | return sd_bus_reply_method_return(message, NULL((void*)0)); | |||
87 | } | |||
88 | ||||
89 | int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
90 | Machine *m = userdata; | |||
91 | const char *swho; | |||
92 | int32_t signo; | |||
93 | KillWho who; | |||
94 | int r; | |||
95 | ||||
96 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/machine/machine-dbus.c" , 96, __PRETTY_FUNCTION__); } while (0); | |||
97 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 97 , __PRETTY_FUNCTION__); } while (0); | |||
98 | ||||
99 | r = sd_bus_message_read(message, "si", &swho, &signo); | |||
100 | if (r < 0) | |||
101 | return r; | |||
102 | ||||
103 | if (isempty(swho)) | |||
104 | who = KILL_ALL; | |||
105 | else { | |||
106 | who = kill_who_from_string(swho); | |||
107 | if (who < 0) | |||
108 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Invalid kill parameter '%s'", swho); | |||
109 | } | |||
110 | ||||
111 | if (!SIGNAL_VALID(signo)) | |||
112 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Invalid signal %i", signo); | |||
113 | ||||
114 | r = bus_verify_polkit_async( | |||
115 | message, | |||
116 | CAP_KILL5, | |||
117 | "org.freedesktop.machine1.manage-machines", | |||
118 | NULL((void*)0), | |||
119 | false0, | |||
120 | UID_INVALID((uid_t) -1), | |||
121 | &m->manager->polkit_registry, | |||
122 | error); | |||
123 | if (r < 0) | |||
124 | return r; | |||
125 | if (r == 0) | |||
126 | return 1; /* Will call us back */ | |||
127 | ||||
128 | r = machine_kill(m, who, signo); | |||
129 | if (r < 0) | |||
130 | return r; | |||
131 | ||||
132 | return sd_bus_reply_method_return(message, NULL((void*)0)); | |||
133 | } | |||
134 | ||||
135 | int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
136 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL((void*)0); | |||
137 | Machine *m = userdata; | |||
138 | int r; | |||
139 | ||||
140 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/machine/machine-dbus.c" , 140, __PRETTY_FUNCTION__); } while (0); | |||
141 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 141 , __PRETTY_FUNCTION__); } while (0); | |||
142 | ||||
143 | r = sd_bus_message_new_method_return(message, &reply); | |||
144 | if (r < 0) | |||
145 | return r; | |||
146 | ||||
147 | r = sd_bus_message_open_container(reply, 'a', "(iay)"); | |||
148 | if (r < 0) | |||
149 | return r; | |||
150 | ||||
151 | switch (m->class) { | |||
152 | ||||
153 | case MACHINE_HOST: { | |||
154 | _cleanup_free___attribute__((cleanup(freep))) struct local_address *addresses = NULL((void*)0); | |||
155 | struct local_address *a; | |||
156 | int n, i; | |||
157 | ||||
158 | n = local_addresses(NULL((void*)0), 0, AF_UNSPEC0, &addresses); | |||
159 | if (n < 0) | |||
160 | return n; | |||
161 | ||||
162 | for (a = addresses, i = 0; i < n; a++, i++) { | |||
163 | ||||
164 | r = sd_bus_message_open_container(reply, 'r', "iay"); | |||
165 | if (r < 0) | |||
166 | return r; | |||
167 | ||||
168 | r = sd_bus_message_append(reply, "i", addresses[i].family); | |||
169 | if (r < 0) | |||
170 | return r; | |||
171 | ||||
172 | r = sd_bus_message_append_array(reply, 'y', &addresses[i].address, FAMILY_ADDRESS_SIZE(addresses[i].family)); | |||
173 | if (r < 0) | |||
174 | return r; | |||
175 | ||||
176 | r = sd_bus_message_close_container(reply); | |||
177 | if (r < 0) | |||
178 | return r; | |||
179 | } | |||
180 | ||||
181 | break; | |||
182 | } | |||
183 | ||||
184 | case MACHINE_CONTAINER: { | |||
185 | _cleanup_close_pair___attribute__((cleanup(close_pairp))) int pair[2] = { -1, -1 }; | |||
186 | _cleanup_free___attribute__((cleanup(freep))) char *us = NULL((void*)0), *them = NULL((void*)0); | |||
187 | _cleanup_close___attribute__((cleanup(closep))) int netns_fd = -1; | |||
188 | const char *p; | |||
189 | pid_t child; | |||
190 | ||||
191 | r = readlink_malloc("/proc/self/ns/net", &us); | |||
192 | if (r < 0) | |||
193 | return r; | |||
194 | ||||
195 | p = procfs_file_alloca(m->leader, "ns/net")({ pid_t _pid_ = (m->leader); const char *_r_; if (_pid_ == 0) { _r_ = ("/proc/self/" "ns/net"); } else { _r_ = __builtin_alloca ((sizeof("""/proc/""") - 1) + (2+(sizeof(pid_t) <= 1 ? 3 : sizeof(pid_t) <= 2 ? 5 : sizeof(pid_t) <= 4 ? 10 : sizeof (pid_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(pid_t) > 8)]) )) + 1 + sizeof("ns/net")); sprintf((char*) _r_, "/proc/""%" "i" "/" "ns/net", _pid_); } _r_; }); | |||
196 | r = readlink_malloc(p, &them); | |||
197 | if (r < 0) | |||
198 | return r; | |||
199 | ||||
200 | if (streq(us, them)(strcmp((us),(them)) == 0)) | |||
201 | return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING"org.freedesktop.machine1.NoPrivateNetworking", "Machine %s does not use private networking", m->name); | |||
202 | ||||
203 | r = namespace_open(m->leader, NULL((void*)0), NULL((void*)0), &netns_fd, NULL((void*)0), NULL((void*)0)); | |||
204 | if (r < 0) | |||
205 | return r; | |||
206 | ||||
207 | if (socketpair(AF_UNIX1, SOCK_SEQPACKETSOCK_SEQPACKET, 0, pair) < 0) | |||
208 | return -errno(*__errno_location ()); | |||
209 | ||||
210 | r = safe_fork("(sd-addr)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child); | |||
211 | if (r < 0) | |||
212 | return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); | |||
213 | if (r == 0) { | |||
214 | _cleanup_free___attribute__((cleanup(freep))) struct local_address *addresses = NULL((void*)0); | |||
215 | struct local_address *a; | |||
216 | int i, n; | |||
217 | ||||
218 | pair[0] = safe_close(pair[0]); | |||
219 | ||||
220 | r = namespace_enter(-1, -1, netns_fd, -1, -1); | |||
221 | if (r < 0) | |||
222 | _exit(EXIT_FAILURE1); | |||
223 | ||||
224 | n = local_addresses(NULL((void*)0), 0, AF_UNSPEC0, &addresses); | |||
225 | if (n < 0) | |||
226 | _exit(EXIT_FAILURE1); | |||
227 | ||||
228 | for (a = addresses, i = 0; i < n; a++, i++) { | |||
229 | struct iovec iov[2] = { | |||
230 | { .iov_base = &a->family, .iov_len = sizeof(a->family) }, | |||
231 | { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) }, | |||
232 | }; | |||
233 | ||||
234 | r = writev(pair[1], iov, 2); | |||
235 | if (r < 0) | |||
236 | _exit(EXIT_FAILURE1); | |||
237 | } | |||
238 | ||||
239 | pair[1] = safe_close(pair[1]); | |||
240 | ||||
241 | _exit(EXIT_SUCCESS0); | |||
242 | } | |||
243 | ||||
244 | pair[1] = safe_close(pair[1]); | |||
245 | ||||
246 | for (;;) { | |||
247 | int family; | |||
248 | ssize_t n; | |||
249 | union in_addr_union in_addr; | |||
250 | struct iovec iov[2]; | |||
251 | struct msghdr mh = { | |||
252 | .msg_iov = iov, | |||
253 | .msg_iovlen = 2, | |||
254 | }; | |||
255 | ||||
256 | iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) }; | |||
257 | iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) }; | |||
258 | ||||
259 | n = recvmsg(pair[0], &mh, 0); | |||
260 | if (n < 0) | |||
261 | return -errno(*__errno_location ()); | |||
262 | if ((size_t) n < sizeof(family)) | |||
263 | break; | |||
264 | ||||
265 | r = sd_bus_message_open_container(reply, 'r', "iay"); | |||
266 | if (r < 0) | |||
267 | return r; | |||
268 | ||||
269 | r = sd_bus_message_append(reply, "i", family); | |||
270 | if (r < 0) | |||
271 | return r; | |||
272 | ||||
273 | switch (family) { | |||
274 | ||||
275 | case AF_INET2: | |||
276 | if (n != sizeof(struct in_addr) + sizeof(family)) | |||
277 | return -EIO5; | |||
278 | ||||
279 | r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in)); | |||
280 | break; | |||
281 | ||||
282 | case AF_INET610: | |||
283 | if (n != sizeof(struct in6_addr) + sizeof(family)) | |||
284 | return -EIO5; | |||
285 | ||||
286 | r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6)); | |||
287 | break; | |||
288 | } | |||
289 | if (r < 0) | |||
290 | return r; | |||
291 | ||||
292 | r = sd_bus_message_close_container(reply); | |||
293 | if (r < 0) | |||
294 | return r; | |||
295 | } | |||
296 | ||||
297 | r = wait_for_terminate_and_check("(sd-addr)", child, 0); | |||
298 | if (r < 0) | |||
299 | return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m"); | |||
300 | if (r != EXIT_SUCCESS0) | |||
301 | return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED"org.freedesktop.DBus.Error.Failed", "Child died abnormally."); | |||
302 | break; | |||
303 | } | |||
304 | ||||
305 | default: | |||
306 | return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED"org.freedesktop.DBus.Error.NotSupported", "Requesting IP address data is only supported on container machines."); | |||
307 | } | |||
308 | ||||
309 | r = sd_bus_message_close_container(reply); | |||
310 | if (r < 0) | |||
311 | return r; | |||
312 | ||||
313 | return sd_bus_send(NULL((void*)0), reply, NULL((void*)0)); | |||
314 | } | |||
315 | ||||
316 | #define EXIT_NOT_FOUND2 2 | |||
317 | ||||
318 | int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
319 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **l = NULL((void*)0); | |||
320 | Machine *m = userdata; | |||
321 | int r; | |||
322 | ||||
323 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/machine/machine-dbus.c" , 323, __PRETTY_FUNCTION__); } while (0); | |||
324 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 324 , __PRETTY_FUNCTION__); } while (0); | |||
325 | ||||
326 | switch (m->class) { | |||
327 | ||||
328 | case MACHINE_HOST: | |||
329 | r = load_os_release_pairs(NULL((void*)0), &l); | |||
330 | if (r < 0) | |||
331 | return r; | |||
332 | ||||
333 | break; | |||
334 | ||||
335 | case MACHINE_CONTAINER: { | |||
336 | _cleanup_close___attribute__((cleanup(closep))) int mntns_fd = -1, root_fd = -1; | |||
337 | _cleanup_close_pair___attribute__((cleanup(close_pairp))) int pair[2] = { -1, -1 }; | |||
338 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | |||
339 | pid_t child; | |||
340 | ||||
341 | r = namespace_open(m->leader, NULL((void*)0), &mntns_fd, NULL((void*)0), NULL((void*)0), &root_fd); | |||
342 | if (r < 0) | |||
343 | return r; | |||
344 | ||||
345 | if (socketpair(AF_UNIX1, SOCK_SEQPACKETSOCK_SEQPACKET, 0, pair) < 0) | |||
346 | return -errno(*__errno_location ()); | |||
347 | ||||
348 | r = safe_fork("(sd-osrel)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child); | |||
349 | if (r < 0) | |||
350 | return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); | |||
351 | if (r == 0) { | |||
352 | int fd = -1; | |||
353 | ||||
354 | pair[0] = safe_close(pair[0]); | |||
355 | ||||
356 | r = namespace_enter(-1, mntns_fd, -1, -1, root_fd); | |||
357 | if (r < 0) | |||
358 | _exit(EXIT_FAILURE1); | |||
359 | ||||
360 | r = open_os_release(NULL((void*)0), NULL((void*)0), &fd); | |||
361 | if (r == -ENOENT2) | |||
362 | _exit(EXIT_NOT_FOUND2); | |||
363 | if (r < 0) | |||
364 | _exit(EXIT_FAILURE1); | |||
365 | ||||
366 | r = copy_bytes(fd, pair[1], (uint64_t) -1, 0); | |||
367 | if (r < 0) | |||
368 | _exit(EXIT_FAILURE1); | |||
369 | ||||
370 | _exit(EXIT_SUCCESS0); | |||
371 | } | |||
372 | ||||
373 | pair[1] = safe_close(pair[1]); | |||
374 | ||||
375 | f = fdopen(pair[0], "re"); | |||
376 | if (!f) | |||
377 | return -errno(*__errno_location ()); | |||
378 | ||||
379 | pair[0] = -1; | |||
380 | ||||
381 | r = load_env_file_pairs(f, "/etc/os-release", NULL((void*)0), &l); | |||
382 | if (r < 0) | |||
383 | return r; | |||
384 | ||||
385 | r = wait_for_terminate_and_check("(sd-osrel)", child, 0); | |||
386 | if (r < 0) | |||
387 | return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m"); | |||
388 | if (r == EXIT_NOT_FOUND2) | |||
389 | return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED"org.freedesktop.DBus.Error.Failed", "Machine does not contain OS release information"); | |||
390 | if (r != EXIT_SUCCESS0) | |||
391 | return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED"org.freedesktop.DBus.Error.Failed", "Child died abnormally."); | |||
392 | ||||
393 | break; | |||
394 | } | |||
395 | ||||
396 | default: | |||
397 | return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED"org.freedesktop.DBus.Error.NotSupported", "Requesting OS release data is only supported on container machines."); | |||
398 | } | |||
399 | ||||
400 | return bus_reply_pair_array(message, l); | |||
401 | } | |||
402 | ||||
403 | int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
404 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL((void*)0); | |||
405 | _cleanup_free___attribute__((cleanup(freep))) char *pty_name = NULL((void*)0); | |||
406 | _cleanup_close___attribute__((cleanup(closep))) int master = -1; | |||
407 | Machine *m = userdata; | |||
408 | int r; | |||
409 | ||||
410 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/machine/machine-dbus.c" , 410, __PRETTY_FUNCTION__); } while (0); | |||
411 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 411 , __PRETTY_FUNCTION__); } while (0); | |||
412 | ||||
413 | r = bus_verify_polkit_async( | |||
414 | message, | |||
415 | CAP_SYS_ADMIN21, | |||
416 | m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty", | |||
417 | NULL((void*)0), | |||
418 | false0, | |||
419 | UID_INVALID((uid_t) -1), | |||
420 | &m->manager->polkit_registry, | |||
421 | error); | |||
422 | if (r < 0) | |||
423 | return r; | |||
424 | if (r == 0) | |||
425 | return 1; /* Will call us back */ | |||
426 | ||||
427 | master = machine_openpt(m, O_RDWR02|O_NOCTTY0400|O_CLOEXEC02000000); | |||
428 | if (master < 0) | |||
429 | return master; | |||
430 | ||||
431 | r = ptsname_namespace(master, &pty_name); | |||
432 | if (r < 0) | |||
433 | return r; | |||
434 | ||||
435 | r = sd_bus_message_new_method_return(message, &reply); | |||
436 | if (r < 0) | |||
437 | return r; | |||
438 | ||||
439 | r = sd_bus_message_append(reply, "hs", master, pty_name); | |||
440 | if (r < 0) | |||
441 | return r; | |||
442 | ||||
443 | return sd_bus_send(NULL((void*)0), reply, NULL((void*)0)); | |||
444 | } | |||
445 | ||||
446 | static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) { | |||
447 | int r; | |||
448 | ||||
449 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 449 , __PRETTY_FUNCTION__); } while (0); | |||
450 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/machine/machine-dbus.c", 450, __PRETTY_FUNCTION__); } while (0); | |||
451 | ||||
452 | switch (m->class) { | |||
453 | ||||
454 | case MACHINE_HOST: | |||
455 | *ret = NULL((void*)0); | |||
456 | break; | |||
457 | ||||
458 | case MACHINE_CONTAINER: { | |||
459 | _cleanup_(sd_bus_unrefp)__attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus = NULL((void*)0); | |||
460 | char *address; | |||
461 | ||||
462 | r = sd_bus_new(&bus); | |||
463 | if (r < 0) | |||
464 | return r; | |||
465 | ||||
466 | if (asprintf(&address, "x-machine-kernel:pid=%1$" PID_PRI"i" ";x-machine-unix:pid=%1$" PID_PRI"i", m->leader) < 0) | |||
467 | return -ENOMEM12; | |||
468 | ||||
469 | bus->address = address; | |||
470 | bus->bus_client = true1; | |||
471 | bus->trusted = false0; | |||
472 | bus->is_system = true1; | |||
473 | ||||
474 | r = sd_bus_start(bus); | |||
475 | if (r == -ENOENT2) | |||
476 | return sd_bus_error_set_errnof(error, r, "There is no system bus in container %s.", m->name); | |||
477 | if (r < 0) | |||
478 | return r; | |||
479 | ||||
480 | *ret = TAKE_PTR(bus)({ typeof(bus) _ptr_ = (bus); (bus) = ((void*)0); _ptr_; }); | |||
481 | break; | |||
482 | } | |||
483 | ||||
484 | default: | |||
485 | return -EOPNOTSUPP95; | |||
486 | } | |||
487 | ||||
488 | return 0; | |||
489 | } | |||
490 | ||||
491 | int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
492 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL((void*)0); | |||
493 | _cleanup_free___attribute__((cleanup(freep))) char *pty_name = NULL((void*)0); | |||
494 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *allocated_bus = NULL((void*)0); | |||
495 | _cleanup_close___attribute__((cleanup(closep))) int master = -1; | |||
496 | sd_bus *container_bus = NULL((void*)0); | |||
497 | Machine *m = userdata; | |||
498 | const char *p, *getty; | |||
499 | int r; | |||
500 | ||||
501 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/machine/machine-dbus.c" , 501, __PRETTY_FUNCTION__); } while (0); | |||
502 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 502 , __PRETTY_FUNCTION__); } while (0); | |||
503 | ||||
504 | r = bus_verify_polkit_async( | |||
505 | message, | |||
506 | CAP_SYS_ADMIN21, | |||
507 | m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login", | |||
508 | NULL((void*)0), | |||
509 | false0, | |||
510 | UID_INVALID((uid_t) -1), | |||
511 | &m->manager->polkit_registry, | |||
512 | error); | |||
513 | if (r < 0) | |||
514 | return r; | |||
515 | if (r == 0) | |||
516 | return 1; /* Will call us back */ | |||
517 | ||||
518 | master = machine_openpt(m, O_RDWR02|O_NOCTTY0400|O_CLOEXEC02000000); | |||
519 | if (master < 0) | |||
520 | return master; | |||
521 | ||||
522 | r = ptsname_namespace(master, &pty_name); | |||
523 | if (r < 0) | |||
524 | return r; | |||
525 | ||||
526 | p = path_startswith(pty_name, "/dev/pts/"); | |||
527 | if (!p) | |||
528 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "PTS name %s is invalid", pty_name); | |||
529 | ||||
530 | r = container_bus_new(m, error, &allocated_bus); | |||
531 | if (r < 0) | |||
532 | return r; | |||
533 | ||||
534 | container_bus = allocated_bus ?: m->manager->bus; | |||
535 | ||||
536 | getty = strjoina("container-getty@", p, ".service")({ const char *_appendees_[] = { "container-getty@", p, ".service" }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
537 | ||||
538 | r = sd_bus_call_method( | |||
539 | container_bus, | |||
540 | "org.freedesktop.systemd1", | |||
541 | "/org/freedesktop/systemd1", | |||
542 | "org.freedesktop.systemd1.Manager", | |||
543 | "StartUnit", | |||
544 | error, NULL((void*)0), | |||
545 | "ss", getty, "replace"); | |||
546 | if (r < 0) | |||
547 | return r; | |||
548 | ||||
549 | r = sd_bus_message_new_method_return(message, &reply); | |||
550 | if (r < 0) | |||
551 | return r; | |||
552 | ||||
553 | r = sd_bus_message_append(reply, "hs", master, pty_name); | |||
554 | if (r < 0) | |||
555 | return r; | |||
556 | ||||
557 | return sd_bus_send(NULL((void*)0), reply, NULL((void*)0)); | |||
558 | } | |||
559 | ||||
560 | int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
561 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL((void*)0), *tm = NULL((void*)0); | |||
562 | _cleanup_free___attribute__((cleanup(freep))) char *pty_name = NULL((void*)0); | |||
563 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *allocated_bus = NULL((void*)0); | |||
564 | sd_bus *container_bus = NULL((void*)0); | |||
565 | _cleanup_close___attribute__((cleanup(closep))) int master = -1, slave = -1; | |||
566 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **env = NULL((void*)0), **args_wire = NULL((void*)0), **args = NULL((void*)0); | |||
567 | Machine *m = userdata; | |||
568 | const char *p, *unit, *user, *path, *description, *utmp_id; | |||
569 | int r; | |||
570 | ||||
571 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/machine/machine-dbus.c" , 571, __PRETTY_FUNCTION__); } while (0); | |||
| ||||
572 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 572 , __PRETTY_FUNCTION__); } while (0); | |||
573 | ||||
574 | r = sd_bus_message_read(message, "ss", &user, &path); | |||
575 | if (r < 0) | |||
576 | return r; | |||
577 | user = empty_to_null(user); | |||
578 | r = sd_bus_message_read_strv(message, &args_wire); | |||
579 | if (r < 0) | |||
580 | return r; | |||
581 | if (isempty(path)) { | |||
582 | path = "/bin/sh"; | |||
583 | ||||
584 | args = new0(char*, 3 + 1)((char**) calloc((3 + 1), sizeof(char*))); | |||
585 | if (!args) | |||
586 | return -ENOMEM12; | |||
587 | args[0] = strdup("sh"); | |||
588 | if (!args[0]) | |||
589 | return -ENOMEM12; | |||
| ||||
590 | args[1] = strdup("-c"); | |||
591 | if (!args[1]) | |||
592 | return -ENOMEM12; | |||
593 | r = asprintf(&args[2], | |||
594 | "shell=$(getent passwd %s 2>/dev/null | { IFS=: read _ _ _ _ _ _ x; echo \"$x\"; })\n"\ | |||
595 | "exec \"${shell:-/bin/sh}\" -l", /* -l is means --login */ | |||
596 | isempty(user) ? "root" : user); | |||
597 | if (r < 0) { | |||
598 | args[2] = NULL((void*)0); | |||
599 | return -ENOMEM12; | |||
600 | } | |||
601 | } else { | |||
602 | if (!path_is_absolute(path)) | |||
603 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Specified path '%s' is not absolute", path); | |||
604 | args = TAKE_PTR(args_wire)({ typeof(args_wire) _ptr_ = (args_wire); (args_wire) = ((void *)0); _ptr_; }); | |||
605 | if (strv_isempty(args)) { | |||
606 | args = strv_free(args); | |||
607 | ||||
608 | args = strv_new(path, NULL((void*)0)); | |||
609 | if (!args) | |||
610 | return -ENOMEM12; | |||
611 | } | |||
612 | } | |||
613 | ||||
614 | r = sd_bus_message_read_strv(message, &env); | |||
615 | if (r < 0) | |||
616 | return r; | |||
617 | if (!strv_env_is_valid(env)) | |||
618 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Invalid environment assignments"); | |||
619 | ||||
620 | r = bus_verify_polkit_async( | |||
621 | message, | |||
622 | CAP_SYS_ADMIN21, | |||
623 | m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell", | |||
624 | NULL((void*)0), | |||
625 | false0, | |||
626 | UID_INVALID((uid_t) -1), | |||
627 | &m->manager->polkit_registry, | |||
628 | error); | |||
629 | if (r < 0) | |||
630 | return r; | |||
631 | if (r == 0) | |||
632 | return 1; /* Will call us back */ | |||
633 | ||||
634 | master = machine_openpt(m, O_RDWR02|O_NOCTTY0400|O_CLOEXEC02000000); | |||
635 | if (master < 0) | |||
636 | return master; | |||
637 | ||||
638 | r = ptsname_namespace(master, &pty_name); | |||
639 | if (r < 0) | |||
640 | return r; | |||
641 | ||||
642 | p = path_startswith(pty_name, "/dev/pts/"); | |||
643 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/machine/machine-dbus.c", 643 , __PRETTY_FUNCTION__); } while (0); | |||
644 | ||||
645 | slave = machine_open_terminal(m, pty_name, O_RDWR02|O_NOCTTY0400|O_CLOEXEC02000000); | |||
646 | if (slave < 0) | |||
647 | return slave; | |||
648 | ||||
649 | utmp_id = path_startswith(pty_name, "/dev/"); | |||
650 | assert(utmp_id)do { if ((__builtin_expect(!!(!(utmp_id)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("utmp_id"), "../src/machine/machine-dbus.c" , 650, __PRETTY_FUNCTION__); } while (0); | |||
651 | ||||
652 | r = container_bus_new(m, error, &allocated_bus); | |||
653 | if (r < 0) | |||
654 | return r; | |||
655 | ||||
656 | container_bus = allocated_bus ?: m->manager->bus; | |||
657 | ||||
658 | r = sd_bus_message_new_method_call( | |||
659 | container_bus, | |||
660 | &tm, | |||
661 | "org.freedesktop.systemd1", | |||
662 | "/org/freedesktop/systemd1", | |||
663 | "org.freedesktop.systemd1.Manager", | |||
664 | "StartTransientUnit"); | |||
665 | if (r < 0) | |||
666 | return r; | |||
667 | ||||
668 | /* Name and mode */ | |||
669 | unit = strjoina("container-shell@", p, ".service")({ const char *_appendees_[] = { "container-shell@", p, ".service" }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
670 | r = sd_bus_message_append(tm, "ss", unit, "fail"); | |||
671 | if (r < 0) | |||
672 | return r; | |||
673 | ||||
674 | /* Properties */ | |||
675 | r = sd_bus_message_open_container(tm, 'a', "(sv)"); | |||
676 | if (r < 0) | |||
677 | return r; | |||
678 | ||||
679 | description = strjoina("Shell for User ", isempty(user) ? "root" : user)({ const char *_appendees_[] = { "Shell for User ", isempty(user ) ? "root" : user }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _len_ += strlen (_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
680 | r = sd_bus_message_append(tm, | |||
681 | "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)", | |||
682 | "Description", "s", description, | |||
683 | "StandardInputFileDescriptor", "h", slave, | |||
684 | "StandardOutputFileDescriptor", "h", slave, | |||
685 | "StandardErrorFileDescriptor", "h", slave, | |||
686 | "SendSIGHUP", "b", true1, | |||
687 | "IgnoreSIGPIPE", "b", false0, | |||
688 | "KillMode", "s", "mixed", | |||
689 | "TTYReset", "b", true1, | |||
690 | "UtmpIdentifier", "s", utmp_id, | |||
691 | "UtmpMode", "s", "user", | |||
692 | "PAMName", "s", "login", | |||
693 | "WorkingDirectory", "s", "-~"); | |||
694 | if (r < 0) | |||
695 | return r; | |||
696 | ||||
697 | r = sd_bus_message_append(tm, "(sv)", "User", "s", isempty(user) ? "root" : user); | |||
698 | if (r < 0) | |||
699 | return r; | |||
700 | ||||
701 | if (!strv_isempty(env)) { | |||
702 | r = sd_bus_message_open_container(tm, 'r', "sv"); | |||
703 | if (r < 0) | |||
704 | return r; | |||
705 | ||||
706 | r = sd_bus_message_append(tm, "s", "Environment"); | |||
707 | if (r < 0) | |||
708 | return r; | |||
709 | ||||
710 | r = sd_bus_message_open_container(tm, 'v', "as"); | |||
711 | if (r < 0) | |||
712 | return r; | |||
713 | ||||
714 | r = sd_bus_message_append_strv(tm, env); | |||
715 | if (r < 0) | |||
716 | return r; | |||
717 | ||||
718 | r = sd_bus_message_close_container(tm); | |||
719 | if (r < 0) | |||
720 | return r; | |||
721 | ||||
722 | r = sd_bus_message_close_container(tm); | |||
723 | if (r < 0) | |||
724 | return r; | |||
725 | } | |||
726 | ||||
727 | /* Exec container */ | |||
728 | r = sd_bus_message_open_container(tm, 'r', "sv"); | |||
729 | if (r < 0) | |||
730 | return r; | |||
731 | ||||
732 | r = sd_bus_message_append(tm, "s", "ExecStart"); | |||
733 | if (r < 0) | |||
734 | return r; | |||
735 | ||||
736 | r = sd_bus_message_open_container(tm, 'v', "a(sasb)"); | |||
737 | if (r < 0) | |||
738 | return r; | |||
739 | ||||
740 | r = sd_bus_message_open_container(tm, 'a', "(sasb)"); | |||
741 | if (r < 0) | |||
742 | return r; | |||
743 | ||||
744 | r = sd_bus_message_open_container(tm, 'r', "sasb"); | |||
745 | if (r < 0) | |||
746 | return r; | |||
747 | ||||
748 | r = sd_bus_message_append(tm, "s", path); | |||
749 | if (r < 0) | |||
750 | return r; | |||
751 | ||||
752 | r = sd_bus_message_append_strv(tm, args); | |||
753 | if (r < 0) | |||
754 | return r; | |||
755 | ||||
756 | r = sd_bus_message_append(tm, "b", true1); | |||
757 | if (r < 0) | |||
758 | return r; | |||
759 | ||||
760 | r = sd_bus_message_close_container(tm); | |||
761 | if (r < 0) | |||
762 | return r; | |||
763 | ||||
764 | r = sd_bus_message_close_container(tm); | |||
765 | if (r < 0) | |||
766 | return r; | |||
767 | ||||
768 | r = sd_bus_message_close_container(tm); | |||
769 | if (r < 0) | |||
770 | return r; | |||
771 | ||||
772 | r = sd_bus_message_close_container(tm); | |||
773 | if (r < 0) | |||
774 | return r; | |||
775 | ||||
776 | r = sd_bus_message_close_container(tm); | |||
777 | if (r < 0) | |||
778 | return r; | |||
779 | ||||
780 | /* Auxiliary units */ | |||
781 | r = sd_bus_message_append(tm, "a(sa(sv))", 0); | |||
782 | if (r < 0) | |||
783 | return r; | |||
784 | ||||
785 | r = sd_bus_call(container_bus, tm, 0, error, NULL((void*)0)); | |||
786 | if (r < 0) | |||
787 | return r; | |||
788 | ||||
789 | slave = safe_close(slave); | |||
790 | ||||
791 | r = sd_bus_message_new_method_return(message, &reply); | |||
792 | if (r < 0) | |||
793 | return r; | |||
794 | ||||
795 | r = sd_bus_message_append(reply, "hs", master, pty_name); | |||
796 | if (r < 0) | |||
797 | return r; | |||
798 | ||||
799 | return sd_bus_send(NULL((void*)0), reply, NULL((void*)0)); | |||
800 | } | |||
801 | ||||
802 | int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
803 | _cleanup_close_pair___attribute__((cleanup(close_pairp))) int errno_pipe_fd[2] = { -1, -1 }; | |||
804 | char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p; | |||
805 | bool_Bool mount_slave_created = false0, mount_slave_mounted = false0, | |||
806 | mount_tmp_created = false0, mount_tmp_mounted = false0, | |||
807 | mount_outside_created = false0, mount_outside_mounted = false0; | |||
808 | _cleanup_free___attribute__((cleanup(freep))) char *chased_src = NULL((void*)0); | |||
809 | int read_only, make_file_or_directory; | |||
810 | const char *dest, *src; | |||
811 | Machine *m = userdata; | |||
812 | struct stat st; | |||
813 | pid_t child; | |||
814 | uid_t uid; | |||
815 | int r; | |||
816 | ||||
817 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/machine/machine-dbus.c" , 817, __PRETTY_FUNCTION__); } while (0); | |||
818 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 818 , __PRETTY_FUNCTION__); } while (0); | |||
819 | ||||
820 | if (m->class != MACHINE_CONTAINER) | |||
821 | return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED"org.freedesktop.DBus.Error.NotSupported", "Bind mounting is only supported on container machines."); | |||
822 | ||||
823 | r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory); | |||
824 | if (r < 0) | |||
825 | return r; | |||
826 | ||||
827 | if (!path_is_absolute(src) || !path_is_normalized(src)) | |||
828 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Source path must be absolute and not contain ../."); | |||
829 | ||||
830 | if (isempty(dest)) | |||
831 | dest = src; | |||
832 | else if (!path_is_absolute(dest) || !path_is_normalized(dest)) | |||
833 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Destination path must be absolute and not contain ../."); | |||
834 | ||||
835 | r = bus_verify_polkit_async( | |||
836 | message, | |||
837 | CAP_SYS_ADMIN21, | |||
838 | "org.freedesktop.machine1.manage-machines", | |||
839 | NULL((void*)0), | |||
840 | false0, | |||
841 | UID_INVALID((uid_t) -1), | |||
842 | &m->manager->polkit_registry, | |||
843 | error); | |||
844 | if (r < 0) | |||
845 | return r; | |||
846 | if (r == 0) | |||
847 | return 1; /* Will call us back */ | |||
848 | ||||
849 | r = machine_get_uid_shift(m, &uid); | |||
850 | if (r < 0) | |||
851 | return r; | |||
852 | if (uid != 0) | |||
853 | return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED"org.freedesktop.DBus.Error.NotSupported", "Can't bind mount on container with user namespacing applied."); | |||
854 | ||||
855 | /* One day, when bind mounting /proc/self/fd/n works across | |||
856 | * namespace boundaries we should rework this logic to make | |||
857 | * use of it... */ | |||
858 | ||||
859 | p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/")({ const char *_appendees_[] = { "/run/systemd/nspawn/propagate/" , m->name, "/" }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _len_ += strlen (_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
860 | if (laccess(p, F_OK)faccessat(-100, (p), (0), 0x100) < 0) | |||
861 | return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED"org.freedesktop.DBus.Error.NotSupported", "Container does not allow propagation of mount points."); | |||
862 | ||||
863 | r = chase_symlinks(src, NULL((void*)0), CHASE_TRAIL_SLASH, &chased_src); | |||
864 | if (r < 0) | |||
865 | return sd_bus_error_set_errnof(error, r, "Failed to resolve source path: %m"); | |||
866 | ||||
867 | if (lstat(chased_src, &st) < 0) | |||
868 | return sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Failed to stat() source path: %m"); | |||
869 | if (S_ISLNK(st.st_mode)((((st.st_mode)) & 0170000) == (0120000))) /* This shouldn't really happen, given that we just chased the symlinks above, but let's better be safe… */ | |||
870 | return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED"org.freedesktop.DBus.Error.NotSupported", "Source directory can't be a symbolic link"); | |||
871 | ||||
872 | /* Our goal is to install a new bind mount into the container, | |||
873 | possibly read-only. This is irritatingly complex | |||
874 | unfortunately, currently. | |||
875 | ||||
876 | First, we start by creating a private playground in /tmp, | |||
877 | that we can mount MS_SLAVE. (Which is necessary, since | |||
878 | MS_MOVE cannot be applied to mounts with MS_SHARED parent | |||
879 | mounts.) */ | |||
880 | ||||
881 | if (!mkdtemp(mount_slave)) | |||
882 | return sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Failed to create playground %s: %m", mount_slave); | |||
883 | ||||
884 | mount_slave_created = true1; | |||
885 | ||||
886 | if (mount(mount_slave, mount_slave, NULL((void*)0), MS_BINDMS_BIND, NULL((void*)0)) < 0) { | |||
887 | r = sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Failed to make bind mount %s: %m", mount_slave); | |||
888 | goto finish; | |||
889 | } | |||
890 | ||||
891 | mount_slave_mounted = true1; | |||
892 | ||||
893 | if (mount(NULL((void*)0), mount_slave, NULL((void*)0), MS_SLAVEMS_SLAVE, NULL((void*)0)) < 0) { | |||
894 | r = sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Failed to remount slave %s: %m", mount_slave); | |||
895 | goto finish; | |||
896 | } | |||
897 | ||||
898 | /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */ | |||
899 | mount_tmp = strjoina(mount_slave, "/mount")({ const char *_appendees_[] = { mount_slave, "/mount" }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
900 | if (S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) | |||
901 | r = mkdir_errno_wrapper(mount_tmp, 0700); | |||
902 | else | |||
903 | r = touch(mount_tmp); | |||
904 | if (r < 0) { | |||
905 | sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Failed to create temporary mount point %s: %m", mount_tmp); | |||
906 | goto finish; | |||
907 | } | |||
908 | ||||
909 | mount_tmp_created = true1; | |||
910 | ||||
911 | if (mount(chased_src, mount_tmp, NULL((void*)0), MS_BINDMS_BIND, NULL((void*)0)) < 0) { | |||
912 | r = sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Failed to mount %s: %m", chased_src); | |||
913 | goto finish; | |||
914 | } | |||
915 | ||||
916 | mount_tmp_mounted = true1; | |||
917 | ||||
918 | /* Third, we remount the new bind mount read-only if requested. */ | |||
919 | if (read_only) | |||
920 | if (mount(NULL((void*)0), mount_tmp, NULL((void*)0), MS_BINDMS_BIND|MS_REMOUNTMS_REMOUNT|MS_RDONLYMS_RDONLY, NULL((void*)0)) < 0) { | |||
921 | r = sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Failed to remount read-only %s: %m", mount_tmp); | |||
922 | goto finish; | |||
923 | } | |||
924 | ||||
925 | /* Fourth, we move the new bind mount into the propagation directory. This way it will appear there read-only | |||
926 | * right-away. */ | |||
927 | ||||
928 | mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX")({ const char *_appendees_[] = { "/run/systemd/nspawn/propagate/" , m->name, "/XXXXXX" }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _len_ += strlen (_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
929 | if (S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) | |||
930 | r = mkdtemp(mount_outside) ? 0 : -errno(*__errno_location ()); | |||
931 | else { | |||
932 | r = mkostemp_safe(mount_outside); | |||
933 | safe_close(r); | |||
934 | } | |||
935 | if (r < 0) { | |||
936 | sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Cannot create propagation file or directory %s: %m", mount_outside); | |||
937 | goto finish; | |||
938 | } | |||
939 | ||||
940 | mount_outside_created = true1; | |||
941 | ||||
942 | if (mount(mount_tmp, mount_outside, NULL((void*)0), MS_MOVEMS_MOVE, NULL((void*)0)) < 0) { | |||
943 | r = sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Failed to move %s to %s: %m", mount_tmp, mount_outside); | |||
944 | goto finish; | |||
945 | } | |||
946 | ||||
947 | mount_outside_mounted = true1; | |||
948 | mount_tmp_mounted = false0; | |||
949 | ||||
950 | if (S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) | |||
951 | (void) rmdir(mount_tmp); | |||
952 | else | |||
953 | (void) unlink(mount_tmp); | |||
954 | mount_tmp_created = false0; | |||
955 | ||||
956 | (void) umount(mount_slave); | |||
957 | mount_slave_mounted = false0; | |||
958 | ||||
959 | (void) rmdir(mount_slave); | |||
960 | mount_slave_created = false0; | |||
961 | ||||
962 | if (pipe2(errno_pipe_fd, O_CLOEXEC02000000|O_NONBLOCK04000) < 0) { | |||
963 | r = sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Failed to create pipe: %m"); | |||
964 | goto finish; | |||
965 | } | |||
966 | ||||
967 | r = safe_fork("(sd-bindmnt)", FORK_RESET_SIGNALS, &child); | |||
968 | if (r < 0) { | |||
969 | sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); | |||
970 | goto finish; | |||
971 | } | |||
972 | if (r == 0) { | |||
973 | const char *mount_inside; | |||
974 | int mntfd; | |||
975 | const char *q; | |||
976 | ||||
977 | errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); | |||
978 | ||||
979 | q = procfs_file_alloca(m->leader, "ns/mnt")({ pid_t _pid_ = (m->leader); const char *_r_; if (_pid_ == 0) { _r_ = ("/proc/self/" "ns/mnt"); } else { _r_ = __builtin_alloca ((sizeof("""/proc/""") - 1) + (2+(sizeof(pid_t) <= 1 ? 3 : sizeof(pid_t) <= 2 ? 5 : sizeof(pid_t) <= 4 ? 10 : sizeof (pid_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(pid_t) > 8)]) )) + 1 + sizeof("ns/mnt")); sprintf((char*) _r_, "/proc/""%" "i" "/" "ns/mnt", _pid_); } _r_; }); | |||
980 | mntfd = open(q, O_RDONLY00|O_NOCTTY0400|O_CLOEXEC02000000); | |||
981 | if (mntfd < 0) { | |||
982 | r = log_error_errno(errno, "Failed to open mount namespace of leader: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/machine/machine-dbus.c", 982, __func__ , "Failed to open mount namespace of leader: %m") : -abs(_e); }); | |||
983 | goto child_fail; | |||
984 | } | |||
985 | ||||
986 | if (setns(mntfd, CLONE_NEWNS0x00020000) < 0) { | |||
987 | r = log_error_errno(errno, "Failed to join namespace of leader: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/machine/machine-dbus.c", 987, __func__ , "Failed to join namespace of leader: %m") : -abs(_e); }); | |||
988 | goto child_fail; | |||
989 | } | |||
990 | ||||
991 | if (make_file_or_directory) { | |||
992 | if (S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) | |||
993 | (void) mkdir_p(dest, 0755); | |||
994 | else { | |||
995 | (void) mkdir_parents(dest, 0755); | |||
996 | safe_close(open(dest, O_CREAT0100|O_EXCL0200|O_WRONLY01|O_CLOEXEC02000000|O_NOCTTY0400, 0600)); | |||
997 | } | |||
998 | } | |||
999 | ||||
1000 | /* Fifth, move the mount to the right place inside */ | |||
1001 | mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside))({ const char *_appendees_[] = { "/run/systemd/nspawn/incoming/" , basename(mount_outside) }; char *_d_, *_p_; size_t _len_ = 0 ; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _len_ += strlen (_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
1002 | if (mount(mount_inside, dest, NULL((void*)0), MS_MOVEMS_MOVE, NULL((void*)0)) < 0) { | |||
1003 | r = log_error_errno(errno, "Failed to mount: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/machine/machine-dbus.c", 1003, __func__ , "Failed to mount: %m") : -abs(_e); }); | |||
1004 | goto child_fail; | |||
1005 | } | |||
1006 | ||||
1007 | _exit(EXIT_SUCCESS0); | |||
1008 | ||||
1009 | child_fail: | |||
1010 | (void) write(errno_pipe_fd[1], &r, sizeof(r)); | |||
1011 | errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); | |||
1012 | ||||
1013 | _exit(EXIT_FAILURE1); | |||
1014 | } | |||
1015 | ||||
1016 | errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); | |||
1017 | ||||
1018 | r = wait_for_terminate_and_check("(sd-bindmnt)", child, 0); | |||
1019 | if (r < 0) { | |||
1020 | r = sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m"); | |||
1021 | goto finish; | |||
1022 | } | |||
1023 | if (r != EXIT_SUCCESS0) { | |||
1024 | if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r)) | |||
1025 | r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m"); | |||
1026 | else | |||
1027 | r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED"org.freedesktop.DBus.Error.Failed", "Child failed."); | |||
1028 | goto finish; | |||
1029 | } | |||
1030 | ||||
1031 | r = sd_bus_reply_method_return(message, NULL((void*)0)); | |||
1032 | ||||
1033 | finish: | |||
1034 | if (mount_outside_mounted) | |||
1035 | (void) umount(mount_outside); | |||
1036 | if (mount_outside_created) { | |||
1037 | if (S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) | |||
1038 | (void) rmdir(mount_outside); | |||
1039 | else | |||
1040 | (void) unlink(mount_outside); | |||
1041 | } | |||
1042 | ||||
1043 | if (mount_tmp_mounted) | |||
1044 | (void) umount(mount_tmp); | |||
1045 | if (mount_tmp_created) { | |||
1046 | if (S_ISDIR(st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) | |||
1047 | (void) rmdir(mount_tmp); | |||
1048 | else | |||
1049 | (void) unlink(mount_tmp); | |||
1050 | } | |||
1051 | ||||
1052 | if (mount_slave_mounted) | |||
1053 | (void) umount(mount_slave); | |||
1054 | if (mount_slave_created) | |||
1055 | (void) rmdir(mount_slave); | |||
1056 | ||||
1057 | return r; | |||
1058 | } | |||
1059 | ||||
1060 | int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
1061 | const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname; | |||
1062 | _cleanup_close_pair___attribute__((cleanup(close_pairp))) int errno_pipe_fd[2] = { -1, -1 }; | |||
1063 | CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE; | |||
1064 | _cleanup_close___attribute__((cleanup(closep))) int hostfd = -1; | |||
1065 | Machine *m = userdata; | |||
1066 | bool_Bool copy_from; | |||
1067 | pid_t child; | |||
1068 | uid_t uid_shift; | |||
1069 | char *t; | |||
1070 | int r; | |||
1071 | ||||
1072 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/machine/machine-dbus.c" , 1072, __PRETTY_FUNCTION__); } while (0); | |||
1073 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 1073 , __PRETTY_FUNCTION__); } while (0); | |||
1074 | ||||
1075 | if (m->manager->n_operations >= OPERATIONS_MAX64) | |||
1076 | return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED"org.freedesktop.DBus.Error.LimitsExceeded", "Too many ongoing copies."); | |||
1077 | ||||
1078 | if (m->class != MACHINE_CONTAINER) | |||
1079 | return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED"org.freedesktop.DBus.Error.NotSupported", "Copying files is only supported on container machines."); | |||
1080 | ||||
1081 | r = sd_bus_message_read(message, "ss", &src, &dest); | |||
1082 | if (r < 0) | |||
1083 | return r; | |||
1084 | ||||
1085 | if (!path_is_absolute(src)) | |||
1086 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Source path must be absolute."); | |||
1087 | ||||
1088 | if (isempty(dest)) | |||
1089 | dest = src; | |||
1090 | else if (!path_is_absolute(dest)) | |||
1091 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Destination path must be absolute."); | |||
1092 | ||||
1093 | r = bus_verify_polkit_async( | |||
1094 | message, | |||
1095 | CAP_SYS_ADMIN21, | |||
1096 | "org.freedesktop.machine1.manage-machines", | |||
1097 | NULL((void*)0), | |||
1098 | false0, | |||
1099 | UID_INVALID((uid_t) -1), | |||
1100 | &m->manager->polkit_registry, | |||
1101 | error); | |||
1102 | if (r < 0) | |||
1103 | return r; | |||
1104 | if (r == 0) | |||
1105 | return 1; /* Will call us back */ | |||
1106 | ||||
1107 | r = machine_get_uid_shift(m, &uid_shift); | |||
1108 | if (r < 0) | |||
1109 | return r; | |||
1110 | ||||
1111 | copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom"); | |||
1112 | ||||
1113 | if (copy_from) { | |||
1114 | container_path = src; | |||
1115 | host_path = dest; | |||
1116 | } else { | |||
1117 | host_path = src; | |||
1118 | container_path = dest; | |||
1119 | } | |||
1120 | ||||
1121 | host_basename = basename(host_path); | |||
1122 | t = strdupa(host_path)(__extension__ ({ const char *__old = (host_path); size_t __len = strlen (__old) + 1; char *__new = (char *) __builtin_alloca (__len); (char *) memcpy (__new, __old, __len); })); | |||
1123 | host_dirname = dirname(t); | |||
1124 | ||||
1125 | container_basename = basename(container_path); | |||
1126 | t = strdupa(container_path)(__extension__ ({ const char *__old = (container_path); size_t __len = strlen (__old) + 1; char *__new = (char *) __builtin_alloca (__len); (char *) memcpy (__new, __old, __len); })); | |||
1127 | container_dirname = dirname(t); | |||
1128 | ||||
1129 | hostfd = open(host_dirname, O_CLOEXEC02000000|O_RDONLY00|O_NOCTTY0400|O_DIRECTORY0200000); | |||
1130 | if (hostfd < 0) | |||
1131 | return sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Failed to open host directory %s: %m", host_dirname); | |||
1132 | ||||
1133 | if (pipe2(errno_pipe_fd, O_CLOEXEC02000000|O_NONBLOCK04000) < 0) | |||
1134 | return sd_bus_error_set_errnof(error, errno(*__errno_location ()), "Failed to create pipe: %m"); | |||
1135 | ||||
1136 | r = safe_fork("(sd-copy)", FORK_RESET_SIGNALS, &child); | |||
1137 | if (r < 0) | |||
1138 | return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); | |||
1139 | if (r == 0) { | |||
1140 | int containerfd; | |||
1141 | const char *q; | |||
1142 | int mntfd; | |||
1143 | ||||
1144 | errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); | |||
1145 | ||||
1146 | q = procfs_file_alloca(m->leader, "ns/mnt")({ pid_t _pid_ = (m->leader); const char *_r_; if (_pid_ == 0) { _r_ = ("/proc/self/" "ns/mnt"); } else { _r_ = __builtin_alloca ((sizeof("""/proc/""") - 1) + (2+(sizeof(pid_t) <= 1 ? 3 : sizeof(pid_t) <= 2 ? 5 : sizeof(pid_t) <= 4 ? 10 : sizeof (pid_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(pid_t) > 8)]) )) + 1 + sizeof("ns/mnt")); sprintf((char*) _r_, "/proc/""%" "i" "/" "ns/mnt", _pid_); } _r_; }); | |||
1147 | mntfd = open(q, O_RDONLY00|O_NOCTTY0400|O_CLOEXEC02000000); | |||
1148 | if (mntfd < 0) { | |||
1149 | r = log_error_errno(errno, "Failed to open mount namespace of leader: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/machine/machine-dbus.c", 1149, __func__ , "Failed to open mount namespace of leader: %m") : -abs(_e); }); | |||
1150 | goto child_fail; | |||
1151 | } | |||
1152 | ||||
1153 | if (setns(mntfd, CLONE_NEWNS0x00020000) < 0) { | |||
1154 | r = log_error_errno(errno, "Failed to join namespace of leader: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/machine/machine-dbus.c", 1154, __func__ , "Failed to join namespace of leader: %m") : -abs(_e); }); | |||
1155 | goto child_fail; | |||
1156 | } | |||
1157 | ||||
1158 | containerfd = open(container_dirname, O_CLOEXEC02000000|O_RDONLY00|O_NOCTTY0400|O_DIRECTORY0200000); | |||
1159 | if (containerfd < 0) { | |||
1160 | r = log_error_errno(errno, "Failed to open destination directory: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/machine/machine-dbus.c", 1160, __func__ , "Failed to open destination directory: %m") : -abs(_e); }); | |||
1161 | goto child_fail; | |||
1162 | } | |||
1163 | ||||
1164 | /* Run the actual copy operation. Note that when an UID shift is set we'll either clamp the UID/GID to | |||
1165 | * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy | |||
1166 | * the UID/GIDs as they are. */ | |||
1167 | if (copy_from) | |||
1168 | r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID((uid_t) -1) : 0, uid_shift == 0 ? GID_INVALID((gid_t) -1) : 0, copy_flags); | |||
1169 | else | |||
1170 | r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID((uid_t) -1) : uid_shift, uid_shift == 0 ? GID_INVALID((gid_t) -1) : uid_shift, copy_flags); | |||
1171 | ||||
1172 | hostfd = safe_close(hostfd); | |||
1173 | containerfd = safe_close(containerfd); | |||
1174 | ||||
1175 | if (r < 0) { | |||
1176 | r = log_error_errno(r, "Failed to copy tree: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/machine/machine-dbus.c", 1176, __func__, "Failed to copy tree: %m" ) : -abs(_e); }); | |||
1177 | goto child_fail; | |||
1178 | } | |||
1179 | ||||
1180 | _exit(EXIT_SUCCESS0); | |||
1181 | ||||
1182 | child_fail: | |||
1183 | (void) write(errno_pipe_fd[1], &r, sizeof(r)); | |||
1184 | _exit(EXIT_FAILURE1); | |||
1185 | } | |||
1186 | ||||
1187 | errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); | |||
1188 | ||||
1189 | /* Copying might take a while, hence install a watch on the child, and return */ | |||
1190 | ||||
1191 | r = operation_new(m->manager, m, child, message, errno_pipe_fd[0], NULL((void*)0)); | |||
1192 | if (r < 0) { | |||
1193 | (void) sigkill_wait(child); | |||
1194 | return r; | |||
1195 | } | |||
1196 | errno_pipe_fd[0] = -1; | |||
1197 | ||||
1198 | return 1; | |||
1199 | } | |||
1200 | ||||
1201 | int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
1202 | _cleanup_close___attribute__((cleanup(closep))) int fd = -1; | |||
1203 | Machine *m = userdata; | |||
1204 | int r; | |||
1205 | ||||
1206 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/machine/machine-dbus.c" , 1206, __PRETTY_FUNCTION__); } while (0); | |||
1207 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 1207 , __PRETTY_FUNCTION__); } while (0); | |||
1208 | ||||
1209 | r = bus_verify_polkit_async( | |||
1210 | message, | |||
1211 | CAP_SYS_ADMIN21, | |||
1212 | "org.freedesktop.machine1.manage-machines", | |||
1213 | NULL((void*)0), | |||
1214 | false0, | |||
1215 | UID_INVALID((uid_t) -1), | |||
1216 | &m->manager->polkit_registry, | |||
1217 | error); | |||
1218 | if (r < 0) | |||
1219 | return r; | |||
1220 | if (r == 0) | |||
1221 | return 1; /* Will call us back */ | |||
1222 | ||||
1223 | switch (m->class) { | |||
1224 | ||||
1225 | case MACHINE_HOST: | |||
1226 | fd = open("/", O_RDONLY00|O_CLOEXEC02000000|O_DIRECTORY0200000); | |||
1227 | if (fd < 0) | |||
1228 | return -errno(*__errno_location ()); | |||
1229 | ||||
1230 | break; | |||
1231 | ||||
1232 | case MACHINE_CONTAINER: { | |||
1233 | _cleanup_close___attribute__((cleanup(closep))) int mntns_fd = -1, root_fd = -1; | |||
1234 | _cleanup_close_pair___attribute__((cleanup(close_pairp))) int pair[2] = { -1, -1 }; | |||
1235 | pid_t child; | |||
1236 | ||||
1237 | r = namespace_open(m->leader, NULL((void*)0), &mntns_fd, NULL((void*)0), NULL((void*)0), &root_fd); | |||
1238 | if (r < 0) | |||
1239 | return r; | |||
1240 | ||||
1241 | if (socketpair(AF_UNIX1, SOCK_DGRAMSOCK_DGRAM, 0, pair) < 0) | |||
1242 | return -errno(*__errno_location ()); | |||
1243 | ||||
1244 | r = safe_fork("(sd-openroot)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child); | |||
1245 | if (r < 0) | |||
1246 | return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); | |||
1247 | if (r == 0) { | |||
1248 | _cleanup_close___attribute__((cleanup(closep))) int dfd = -1; | |||
1249 | ||||
1250 | pair[0] = safe_close(pair[0]); | |||
1251 | ||||
1252 | r = namespace_enter(-1, mntns_fd, -1, -1, root_fd); | |||
1253 | if (r < 0) | |||
1254 | _exit(EXIT_FAILURE1); | |||
1255 | ||||
1256 | dfd = open("/", O_RDONLY00|O_CLOEXEC02000000|O_DIRECTORY0200000); | |||
1257 | if (dfd < 0) | |||
1258 | _exit(EXIT_FAILURE1); | |||
1259 | ||||
1260 | r = send_one_fd(pair[1], dfd, 0)send_one_fd_iov_sa(pair[1], dfd, ((void*)0), 0, ((void*)0), 0 , 0); | |||
1261 | dfd = safe_close(dfd); | |||
1262 | if (r < 0) | |||
1263 | _exit(EXIT_FAILURE1); | |||
1264 | ||||
1265 | _exit(EXIT_SUCCESS0); | |||
1266 | } | |||
1267 | ||||
1268 | pair[1] = safe_close(pair[1]); | |||
1269 | ||||
1270 | r = wait_for_terminate_and_check("(sd-openroot)", child, 0); | |||
1271 | if (r < 0) | |||
1272 | return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m"); | |||
1273 | if (r != EXIT_SUCCESS0) | |||
1274 | return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED"org.freedesktop.DBus.Error.Failed", "Child died abnormally."); | |||
1275 | ||||
1276 | fd = receive_one_fd(pair[0], MSG_DONTWAITMSG_DONTWAIT); | |||
1277 | if (fd < 0) | |||
1278 | return fd; | |||
1279 | ||||
1280 | break; | |||
1281 | } | |||
1282 | ||||
1283 | default: | |||
1284 | return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED"org.freedesktop.DBus.Error.NotSupported", "Opening the root directory is only supported on container machines."); | |||
1285 | } | |||
1286 | ||||
1287 | return sd_bus_reply_method_return(message, "h", fd); | |||
1288 | } | |||
1289 | ||||
1290 | int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
1291 | Machine *m = userdata; | |||
1292 | uid_t shift = 0; | |||
1293 | int r; | |||
1294 | ||||
1295 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/machine/machine-dbus.c" , 1295, __PRETTY_FUNCTION__); } while (0); | |||
1296 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 1296 , __PRETTY_FUNCTION__); } while (0); | |||
1297 | ||||
1298 | /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but | |||
1299 | * we kinda have to for this. */ | |||
1300 | ||||
1301 | if (m->class == MACHINE_HOST) | |||
1302 | return sd_bus_reply_method_return(message, "u", UINT32_C(0)0U); | |||
1303 | ||||
1304 | if (m->class != MACHINE_CONTAINER) | |||
1305 | return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED"org.freedesktop.DBus.Error.NotSupported", "UID/GID shift may only be determined for container machines."); | |||
1306 | ||||
1307 | r = machine_get_uid_shift(m, &shift); | |||
1308 | if (r == -ENXIO6) | |||
1309 | return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED"org.freedesktop.DBus.Error.NotSupported", "Machine %s uses a complex UID/GID mapping, cannot determine shift", m->name); | |||
1310 | if (r < 0) | |||
1311 | return r; | |||
1312 | ||||
1313 | return sd_bus_reply_method_return(message, "u", (uint32_t) shift); | |||
1314 | } | |||
1315 | ||||
1316 | const sd_bus_vtable machine_vtable[] = { | |||
1317 | SD_BUS_VTABLE_START(0){ .type = _SD_BUS_VTABLE_START, .flags = 0, .x = { .start = { .element_size = sizeof(sd_bus_vtable) }, }, }, | |||
1318 | SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST){ .type = _SD_BUS_VTABLE_PROPERTY, .flags = SD_BUS_VTABLE_PROPERTY_CONST , .x = { .property = { .member = "Name", .signature = "s", .get = ((void*)0), .set = ((void*)0), .offset = __builtin_offsetof (Machine, name), }, }, }, | |||
1319 | SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST){ .type = _SD_BUS_VTABLE_PROPERTY, .flags = SD_BUS_VTABLE_PROPERTY_CONST , .x = { .property = { .member = "Id", .signature = "ay", .get = bus_property_get_id128, .set = ((void*)0), .offset = __builtin_offsetof (Machine, id), }, }, }, | |||
1320 | BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST){ .type = _SD_BUS_VTABLE_PROPERTY, .flags = (SD_BUS_VTABLE_PROPERTY_CONST ), .x = { .property = { .member = "Timestamp", .signature = "t" , .get = ((sd_bus_property_get_t) ((void*)0)), .set = ((void* )0), .offset = (__builtin_offsetof(Machine, timestamp)) + __builtin_offsetof (struct dual_timestamp, realtime), }, }, }, { .type = _SD_BUS_VTABLE_PROPERTY , .flags = (SD_BUS_VTABLE_PROPERTY_CONST), .x = { .property = { .member = "Timestamp" "Monotonic", .signature = "t", .get = ((sd_bus_property_get_t) ((void*)0)), .set = ((void*)0), .offset = (__builtin_offsetof(Machine, timestamp)) + __builtin_offsetof (struct dual_timestamp, monotonic), }, }, }, | |||
1321 | SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST){ .type = _SD_BUS_VTABLE_PROPERTY, .flags = SD_BUS_VTABLE_PROPERTY_CONST , .x = { .property = { .member = "Service", .signature = "s", .get = ((void*)0), .set = ((void*)0), .offset = __builtin_offsetof (Machine, service), }, }, }, | |||
1322 | SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST){ .type = _SD_BUS_VTABLE_PROPERTY, .flags = SD_BUS_VTABLE_PROPERTY_CONST , .x = { .property = { .member = "Unit", .signature = "s", .get = ((void*)0), .set = ((void*)0), .offset = __builtin_offsetof (Machine, unit), }, }, }, | |||
1323 | SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN){ .type = _SD_BUS_VTABLE_PROPERTY, .flags = SD_BUS_VTABLE_PROPERTY_CONST |SD_BUS_VTABLE_HIDDEN, .x = { .property = { .member = "Scope" , .signature = "s", .get = ((void*)0), .set = ((void*)0), .offset = __builtin_offsetof(Machine, unit), }, }, }, | |||
1324 | SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST){ .type = _SD_BUS_VTABLE_PROPERTY, .flags = SD_BUS_VTABLE_PROPERTY_CONST , .x = { .property = { .member = "Leader", .signature = "u", . get = ((void*)0), .set = ((void*)0), .offset = __builtin_offsetof (Machine, leader), }, }, }, | |||
1325 | SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST){ .type = _SD_BUS_VTABLE_PROPERTY, .flags = SD_BUS_VTABLE_PROPERTY_CONST , .x = { .property = { .member = "Class", .signature = "s", . get = property_get_class, .set = ((void*)0), .offset = __builtin_offsetof (Machine, class), }, }, }, | |||
1326 | SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST){ .type = _SD_BUS_VTABLE_PROPERTY, .flags = SD_BUS_VTABLE_PROPERTY_CONST , .x = { .property = { .member = "RootDirectory", .signature = "s", .get = ((void*)0), .set = ((void*)0), .offset = __builtin_offsetof (Machine, root_directory), }, }, }, | |||
1327 | SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST){ .type = _SD_BUS_VTABLE_PROPERTY, .flags = SD_BUS_VTABLE_PROPERTY_CONST , .x = { .property = { .member = "NetworkInterfaces", .signature = "ai", .get = property_get_netif, .set = ((void*)0), .offset = 0, }, }, }, | |||
1328 | SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0){ .type = _SD_BUS_VTABLE_PROPERTY, .flags = 0, .x = { .property = { .member = "State", .signature = "s", .get = property_get_state , .set = ((void*)0), .offset = 0, }, }, }, | |||
1329 | SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "Terminate", .signature = ((void *)0), .result = ((void*)0), .handler = bus_machine_method_terminate , .offset = 0, }, }, }, | |||
1330 | SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "Kill", .signature = "si", .result = ((void*)0), .handler = bus_machine_method_kill, .offset = 0 , }, }, }, | |||
1331 | SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "GetAddresses", .signature = ( (void*)0), .result = "a(iay)", .handler = bus_machine_method_get_addresses , .offset = 0, }, }, }, | |||
1332 | SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "GetOSRelease", .signature = ( (void*)0), .result = "a{ss}", .handler = bus_machine_method_get_os_release , .offset = 0, }, }, }, | |||
1333 | SD_BUS_METHOD("GetUIDShift", NULL, "u", bus_machine_method_get_uid_shift, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "GetUIDShift", .signature = (( void*)0), .result = "u", .handler = bus_machine_method_get_uid_shift , .offset = 0, }, }, }, | |||
1334 | SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "OpenPTY", .signature = ((void *)0), .result = "hs", .handler = bus_machine_method_open_pty, .offset = 0, }, }, }, | |||
1335 | SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "OpenLogin", .signature = ((void *)0), .result = "hs", .handler = bus_machine_method_open_login , .offset = 0, }, }, }, | |||
1336 | SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "OpenShell", .signature = "ssasas" , .result = "hs", .handler = bus_machine_method_open_shell, . offset = 0, }, }, }, | |||
1337 | SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "BindMount", .signature = "ssbb" , .result = ((void*)0), .handler = bus_machine_method_bind_mount , .offset = 0, }, }, }, | |||
1338 | SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "CopyFrom", .signature = "ss", .result = ((void*)0), .handler = bus_machine_method_copy, .offset = 0, }, }, }, | |||
1339 | SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "CopyTo", .signature = "ss", . result = ((void*)0), .handler = bus_machine_method_copy, .offset = 0, }, }, }, | |||
1340 | SD_BUS_METHOD("OpenRootDirectory", NULL, "h", bus_machine_method_open_root_directory, SD_BUS_VTABLE_UNPRIVILEGED){ .type = _SD_BUS_VTABLE_METHOD, .flags = SD_BUS_VTABLE_UNPRIVILEGED , .x = { .method = { .member = "OpenRootDirectory", .signature = ((void*)0), .result = "h", .handler = bus_machine_method_open_root_directory , .offset = 0, }, }, }, | |||
1341 | SD_BUS_VTABLE_END{ .type = _SD_BUS_VTABLE_END, .flags = 0, .x = { { 0 } }, } | |||
1342 | }; | |||
1343 | ||||
1344 | int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { | |||
1345 | Manager *m = userdata; | |||
1346 | Machine *machine; | |||
1347 | int r; | |||
1348 | ||||
1349 | assert(bus)do { if ((__builtin_expect(!!(!(bus)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("bus"), "../src/machine/machine-dbus.c", 1349, __PRETTY_FUNCTION__); } while (0); | |||
1350 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/machine/machine-dbus.c" , 1350, __PRETTY_FUNCTION__); } while (0); | |||
1351 | assert(interface)do { if ((__builtin_expect(!!(!(interface)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("interface"), "../src/machine/machine-dbus.c" , 1351, __PRETTY_FUNCTION__); } while (0); | |||
1352 | assert(found)do { if ((__builtin_expect(!!(!(found)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("found"), "../src/machine/machine-dbus.c" , 1352, __PRETTY_FUNCTION__); } while (0); | |||
1353 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 1353 , __PRETTY_FUNCTION__); } while (0); | |||
1354 | ||||
1355 | if (streq(path, "/org/freedesktop/machine1/machine/self")(strcmp((path),("/org/freedesktop/machine1/machine/self")) == 0)) { | |||
1356 | _cleanup_(sd_bus_creds_unrefp)__attribute__((cleanup(sd_bus_creds_unrefp))) sd_bus_creds *creds = NULL((void*)0); | |||
1357 | sd_bus_message *message; | |||
1358 | pid_t pid; | |||
1359 | ||||
1360 | message = sd_bus_get_current_message(bus); | |||
1361 | if (!message) | |||
1362 | return 0; | |||
1363 | ||||
1364 | r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); | |||
1365 | if (r < 0) | |||
1366 | return r; | |||
1367 | ||||
1368 | r = sd_bus_creds_get_pid(creds, &pid); | |||
1369 | if (r < 0) | |||
1370 | return r; | |||
1371 | ||||
1372 | r = manager_get_machine_by_pid(m, pid, &machine); | |||
1373 | if (r <= 0) | |||
1374 | return 0; | |||
1375 | } else { | |||
1376 | _cleanup_free___attribute__((cleanup(freep))) char *e = NULL((void*)0); | |||
1377 | const char *p; | |||
1378 | ||||
1379 | p = startswith(path, "/org/freedesktop/machine1/machine/"); | |||
1380 | if (!p) | |||
1381 | return 0; | |||
1382 | ||||
1383 | e = bus_label_unescape(p); | |||
1384 | if (!e) | |||
1385 | return -ENOMEM12; | |||
1386 | ||||
1387 | machine = hashmap_get(m->machines, e); | |||
1388 | if (!machine) | |||
1389 | return 0; | |||
1390 | } | |||
1391 | ||||
1392 | *found = machine; | |||
1393 | return 1; | |||
1394 | } | |||
1395 | ||||
1396 | char *machine_bus_path(Machine *m) { | |||
1397 | _cleanup_free___attribute__((cleanup(freep))) char *e = NULL((void*)0); | |||
1398 | ||||
1399 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 1399 , __PRETTY_FUNCTION__); } while (0); | |||
1400 | ||||
1401 | e = bus_label_escape(m->name); | |||
1402 | if (!e) | |||
1403 | return NULL((void*)0); | |||
1404 | ||||
1405 | return strappend("/org/freedesktop/machine1/machine/", e); | |||
1406 | } | |||
1407 | ||||
1408 | int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { | |||
1409 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **l = NULL((void*)0); | |||
1410 | Machine *machine = NULL((void*)0); | |||
1411 | Manager *m = userdata; | |||
1412 | Iterator i; | |||
1413 | int r; | |||
1414 | ||||
1415 | assert(bus)do { if ((__builtin_expect(!!(!(bus)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("bus"), "../src/machine/machine-dbus.c", 1415, __PRETTY_FUNCTION__); } while (0); | |||
1416 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/machine/machine-dbus.c" , 1416, __PRETTY_FUNCTION__); } while (0); | |||
1417 | assert(nodes)do { if ((__builtin_expect(!!(!(nodes)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("nodes"), "../src/machine/machine-dbus.c" , 1417, __PRETTY_FUNCTION__); } while (0); | |||
1418 | ||||
1419 | HASHMAP_FOREACH(machine, m->machines, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((m->machines), & (i), (void**)&(machine), ((void*)0)); ) { | |||
1420 | char *p; | |||
1421 | ||||
1422 | p = machine_bus_path(machine); | |||
1423 | if (!p) | |||
1424 | return -ENOMEM12; | |||
1425 | ||||
1426 | r = strv_consume(&l, p); | |||
1427 | if (r < 0) | |||
1428 | return r; | |||
1429 | } | |||
1430 | ||||
1431 | *nodes = TAKE_PTR(l)({ typeof(l) _ptr_ = (l); (l) = ((void*)0); _ptr_; }); | |||
1432 | ||||
1433 | return 1; | |||
1434 | } | |||
1435 | ||||
1436 | int machine_send_signal(Machine *m, bool_Bool new_machine) { | |||
1437 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); | |||
1438 | ||||
1439 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 1439 , __PRETTY_FUNCTION__); } while (0); | |||
1440 | ||||
1441 | p = machine_bus_path(m); | |||
1442 | if (!p) | |||
1443 | return -ENOMEM12; | |||
1444 | ||||
1445 | return sd_bus_emit_signal( | |||
1446 | m->manager->bus, | |||
1447 | "/org/freedesktop/machine1", | |||
1448 | "org.freedesktop.machine1.Manager", | |||
1449 | new_machine ? "MachineNew" : "MachineRemoved", | |||
1450 | "so", m->name, p); | |||
1451 | } | |||
1452 | ||||
1453 | int machine_send_create_reply(Machine *m, sd_bus_error *error) { | |||
1454 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *c = NULL((void*)0); | |||
1455 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); | |||
1456 | ||||
1457 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/machine/machine-dbus.c", 1457 , __PRETTY_FUNCTION__); } while (0); | |||
1458 | ||||
1459 | if (!m->create_message) | |||
1460 | return 0; | |||
1461 | ||||
1462 | c = TAKE_PTR(m->create_message)({ typeof(m->create_message) _ptr_ = (m->create_message ); (m->create_message) = ((void*)0); _ptr_; }); | |||
1463 | ||||
1464 | if (error) | |||
1465 | return sd_bus_reply_method_error(c, error); | |||
1466 | ||||
1467 | /* Update the machine state file before we notify the client | |||
1468 | * about the result. */ | |||
1469 | machine_save(m); | |||
1470 | ||||
1471 | p = machine_bus_path(m); | |||
1472 | if (!p) | |||
1473 | return -ENOMEM12; | |||
1474 | ||||
1475 | return sd_bus_reply_method_return(c, "o", p); | |||
1476 | } |