]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
b7103bc5 LP |
2 | |
3 | #include "sd-bus.h" | |
4 | ||
b7103bc5 | 5 | #include "bus-error.h" |
9b71e4ab | 6 | #include "bus-locator.h" |
20b16441 | 7 | #include "bus-unit-util.h" |
8fcde012 | 8 | #include "bus-util.h" |
e45c81b8 | 9 | #include "bus-wait-for-jobs.h" |
b7103bc5 | 10 | #include "nspawn-register.h" |
411d8c72 | 11 | #include "nspawn-settings.h" |
910384c8 | 12 | #include "special.h" |
8fcde012 LP |
13 | #include "stat-util.h" |
14 | #include "strv.h" | |
b7103bc5 | 15 | |
cd2dfc6f LP |
16 | static int append_machine_properties( |
17 | sd_bus_message *m, | |
18 | CustomMount *mounts, | |
19 | unsigned n_mounts, | |
411d8c72 NR |
20 | int kill_signal, |
21 | bool coredump_receive) { | |
cd2dfc6f LP |
22 | |
23 | unsigned j; | |
24 | int r; | |
25 | ||
26 | assert(m); | |
27 | ||
28 | r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "closed"); | |
29 | if (r < 0) | |
30 | return bus_log_create_error(r); | |
31 | ||
32 | /* If you make changes here, also make sure to update systemd-nspawn@.service, to keep the device policies in | |
33 | * sync regardless if we are run with or without the --keep-unit switch. */ | |
34 | r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 2, | |
35 | /* Allow the container to | |
36 | * access and create the API | |
37 | * device nodes, so that | |
38 | * PrivateDevices= in the | |
39 | * container can work | |
40 | * fine */ | |
41 | "/dev/net/tun", "rwm", | |
42 | /* Allow the container | |
43 | * access to ptys. However, | |
44 | * do not permit the | |
45 | * container to ever create | |
46 | * these device nodes. */ | |
47 | "char-pts", "rw"); | |
48 | if (r < 0) | |
49 | return bus_log_create_error(r); | |
50 | ||
51 | for (j = 0; j < n_mounts; j++) { | |
52 | CustomMount *cm = mounts + j; | |
53 | ||
54 | if (cm->type != CUSTOM_MOUNT_BIND) | |
55 | continue; | |
56 | ||
57 | r = is_device_node(cm->source); | |
58 | if (r == -ENOENT) { | |
59 | /* The bind source might only appear as the image is put together, hence don't complain */ | |
60 | log_debug_errno(r, "Bind mount source %s not found, ignoring: %m", cm->source); | |
61 | continue; | |
62 | } | |
63 | if (r < 0) | |
64 | return log_error_errno(r, "Failed to stat %s: %m", cm->source); | |
65 | ||
66 | if (r) { | |
67 | r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 1, | |
68 | cm->source, cm->read_only ? "r" : "rw"); | |
69 | if (r < 0) | |
70 | return log_error_errno(r, "Failed to append message arguments: %m"); | |
71 | } | |
72 | } | |
73 | ||
74 | if (kill_signal != 0) { | |
75 | r = sd_bus_message_append(m, "(sv)", "KillSignal", "i", kill_signal); | |
76 | if (r < 0) | |
77 | return bus_log_create_error(r); | |
78 | ||
79 | r = sd_bus_message_append(m, "(sv)", "KillMode", "s", "mixed"); | |
80 | if (r < 0) | |
81 | return bus_log_create_error(r); | |
82 | } | |
83 | ||
411d8c72 NR |
84 | if (coredump_receive) { |
85 | r = sd_bus_message_append(m, "(sv)", "CoredumpReceive", "b", true); | |
86 | if (r < 0) | |
87 | return bus_log_create_error(r); | |
88 | } | |
89 | ||
cd2dfc6f LP |
90 | return 0; |
91 | } | |
92 | ||
abdb9b08 LP |
93 | static int append_controller_property(sd_bus *bus, sd_bus_message *m) { |
94 | const char *unique; | |
95 | int r; | |
96 | ||
97 | assert(bus); | |
98 | assert(m); | |
99 | ||
100 | r = sd_bus_get_unique_name(bus, &unique); | |
101 | if (r < 0) | |
102 | return log_error_errno(r, "Failed to get unique name: %m"); | |
103 | ||
104 | r = sd_bus_message_append(m, "(sv)", "Controller", "s", unique); | |
105 | if (r < 0) | |
106 | return bus_log_create_error(r); | |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
869c1cf8 NR |
111 | static int can_set_coredump_receive(sd_bus *bus) { |
112 | _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL; | |
113 | _cleanup_free_ char *path = NULL; | |
114 | int b, r; | |
115 | ||
116 | assert(bus); | |
117 | ||
118 | path = unit_dbus_path_from_name(SPECIAL_INIT_SCOPE); | |
119 | if (!path) | |
120 | return log_oom(); | |
121 | ||
122 | r = sd_bus_get_property_trivial( | |
123 | bus, | |
124 | "org.freedesktop.systemd1", | |
125 | path, | |
126 | "org.freedesktop.systemd1.Scope", | |
127 | "CoredumpReceive", | |
128 | &e, | |
129 | 'b', &b); | |
130 | if (r < 0 && !sd_bus_error_has_names(&e, SD_BUS_ERROR_UNKNOWN_PROPERTY, SD_BUS_ERROR_PROPERTY_READ_ONLY)) | |
131 | log_warning_errno(r, "Failed to determine if CoredumpReceive= can be set, assuming it cannot be: %s", | |
132 | bus_error_message(&e, r)); | |
133 | ||
134 | return r >= 0; | |
135 | } | |
136 | ||
b7103bc5 | 137 | int register_machine( |
abdb9b08 | 138 | sd_bus *bus, |
b7103bc5 LP |
139 | const char *machine_name, |
140 | pid_t pid, | |
141 | const char *directory, | |
142 | sd_id128_t uuid, | |
143 | int local_ifindex, | |
144 | const char *slice, | |
145 | CustomMount *mounts, | |
146 | unsigned n_mounts, | |
147 | int kill_signal, | |
148 | char **properties, | |
de40a303 | 149 | sd_bus_message *properties_message, |
6aadfa4c | 150 | bool keep_unit, |
411d8c72 NR |
151 | const char *service, |
152 | StartMode start_mode) { | |
b7103bc5 | 153 | |
4afd3348 | 154 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
b7103bc5 LP |
155 | int r; |
156 | ||
abdb9b08 | 157 | assert(bus); |
b7103bc5 LP |
158 | |
159 | if (keep_unit) { | |
1ecaac5c | 160 | r = bus_call_method( |
b7103bc5 | 161 | bus, |
1ecaac5c | 162 | bus_machine_mgr, |
b7103bc5 LP |
163 | "RegisterMachineWithNetwork", |
164 | &error, | |
165 | NULL, | |
166 | "sayssusai", | |
167 | machine_name, | |
168 | SD_BUS_MESSAGE_APPEND_ID128(uuid), | |
6aadfa4c | 169 | service, |
b7103bc5 LP |
170 | "container", |
171 | (uint32_t) pid, | |
172 | strempty(directory), | |
173 | local_ifindex > 0 ? 1 : 0, local_ifindex); | |
174 | } else { | |
4afd3348 | 175 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
b7103bc5 | 176 | |
1ecaac5c | 177 | r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CreateMachineWithNetwork"); |
b7103bc5 LP |
178 | if (r < 0) |
179 | return bus_log_create_error(r); | |
180 | ||
181 | r = sd_bus_message_append( | |
182 | m, | |
183 | "sayssusai", | |
184 | machine_name, | |
185 | SD_BUS_MESSAGE_APPEND_ID128(uuid), | |
6aadfa4c | 186 | service, |
b7103bc5 LP |
187 | "container", |
188 | (uint32_t) pid, | |
189 | strempty(directory), | |
190 | local_ifindex > 0 ? 1 : 0, local_ifindex); | |
191 | if (r < 0) | |
192 | return bus_log_create_error(r); | |
193 | ||
194 | r = sd_bus_message_open_container(m, 'a', "(sv)"); | |
195 | if (r < 0) | |
196 | return bus_log_create_error(r); | |
197 | ||
198 | if (!isempty(slice)) { | |
199 | r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); | |
200 | if (r < 0) | |
201 | return bus_log_create_error(r); | |
202 | } | |
203 | ||
abdb9b08 LP |
204 | r = append_controller_property(bus, m); |
205 | if (r < 0) | |
206 | return r; | |
207 | ||
cd2dfc6f LP |
208 | r = append_machine_properties( |
209 | m, | |
210 | mounts, | |
211 | n_mounts, | |
411d8c72 | 212 | kill_signal, |
869c1cf8 | 213 | start_mode == START_BOOT && can_set_coredump_receive(bus) > 0); |
b7103bc5 | 214 | if (r < 0) |
cd2dfc6f | 215 | return r; |
b7103bc5 | 216 | |
de40a303 LP |
217 | if (properties_message) { |
218 | r = sd_bus_message_copy(m, properties_message, true); | |
219 | if (r < 0) | |
220 | return bus_log_create_error(r); | |
221 | } | |
222 | ||
89ada3ba | 223 | r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties); |
8673cf13 LP |
224 | if (r < 0) |
225 | return r; | |
b7103bc5 LP |
226 | |
227 | r = sd_bus_message_close_container(m); | |
228 | if (r < 0) | |
229 | return bus_log_create_error(r); | |
230 | ||
231 | r = sd_bus_call(bus, m, 0, &error, NULL); | |
232 | } | |
4ae25393 YW |
233 | if (r < 0) |
234 | return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r)); | |
b7103bc5 LP |
235 | |
236 | return 0; | |
237 | } | |
238 | ||
0bb0a9fa | 239 | int unregister_machine( |
11d81e50 LP |
240 | sd_bus *bus, |
241 | const char *machine_name) { | |
242 | ||
4afd3348 | 243 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
b7103bc5 LP |
244 | int r; |
245 | ||
abdb9b08 | 246 | assert(bus); |
b7103bc5 | 247 | |
1ecaac5c | 248 | r = bus_call_method(bus, bus_machine_mgr, "UnregisterMachine", &error, NULL, "s", machine_name); |
4ae25393 | 249 | if (r < 0) |
0bb0a9fa | 250 | log_debug("Failed to unregister machine: %s", bus_error_message(&error, r)); |
b7103bc5 LP |
251 | |
252 | return 0; | |
253 | } | |
cd2dfc6f LP |
254 | |
255 | int allocate_scope( | |
abdb9b08 | 256 | sd_bus *bus, |
cd2dfc6f LP |
257 | const char *machine_name, |
258 | pid_t pid, | |
259 | const char *slice, | |
260 | CustomMount *mounts, | |
261 | unsigned n_mounts, | |
262 | int kill_signal, | |
de40a303 | 263 | char **properties, |
7eda208f | 264 | sd_bus_message *properties_message, |
411d8c72 NR |
265 | bool allow_pidfd, |
266 | StartMode start_mode) { | |
cd2dfc6f | 267 | |
df61bc5e | 268 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; |
cd2dfc6f | 269 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
0a5706d1 | 270 | _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; |
cd2dfc6f | 271 | _cleanup_free_ char *scope = NULL; |
0a5706d1 | 272 | const char *description, *object; |
cd2dfc6f LP |
273 | int r; |
274 | ||
abdb9b08 | 275 | assert(bus); |
cd2dfc6f | 276 | |
0a5706d1 ZJS |
277 | r = bus_wait_for_jobs_new(bus, &w); |
278 | if (r < 0) | |
279 | return log_error_errno(r, "Could not watch job: %m"); | |
280 | ||
df7c4eb6 | 281 | r = unit_name_mangle_with_suffix(machine_name, "as machine name", 0, ".scope", &scope); |
cd2dfc6f LP |
282 | if (r < 0) |
283 | return log_error_errno(r, "Failed to mangle scope name: %m"); | |
284 | ||
1ecaac5c | 285 | r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit"); |
cd2dfc6f LP |
286 | if (r < 0) |
287 | return bus_log_create_error(r); | |
288 | ||
289 | r = sd_bus_message_append(m, "ss", scope, "fail"); | |
290 | if (r < 0) | |
291 | return bus_log_create_error(r); | |
292 | ||
293 | /* Properties */ | |
294 | r = sd_bus_message_open_container(m, 'a', "(sv)"); | |
295 | if (r < 0) | |
296 | return bus_log_create_error(r); | |
297 | ||
298 | description = strjoina("Container ", machine_name); | |
299 | ||
7eda208f LP |
300 | if (allow_pidfd) { |
301 | _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; | |
302 | r = pidref_set_pid(&pidref, pid); | |
303 | if (r < 0) | |
304 | return log_error_errno(r, "Failed to allocate PID reference: %m"); | |
305 | ||
306 | r = bus_append_scope_pidref(m, &pidref); | |
307 | } else | |
308 | r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid); | |
309 | if (r < 0) | |
310 | return bus_log_create_error(r); | |
311 | ||
312 | r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)", | |
cd2dfc6f LP |
313 | "Description", "s", description, |
314 | "Delegate", "b", 1, | |
1d78fea2 LP |
315 | "CollectMode", "s", "inactive-or-failed", |
316 | "AddRef", "b", 1, | |
910384c8 | 317 | "Slice", "s", isempty(slice) ? SPECIAL_MACHINE_SLICE : slice); |
cd2dfc6f LP |
318 | if (r < 0) |
319 | return bus_log_create_error(r); | |
320 | ||
abdb9b08 LP |
321 | r = append_controller_property(bus, m); |
322 | if (r < 0) | |
323 | return r; | |
324 | ||
de40a303 LP |
325 | if (properties_message) { |
326 | r = sd_bus_message_copy(m, properties_message, true); | |
327 | if (r < 0) | |
328 | return bus_log_create_error(r); | |
329 | } | |
330 | ||
cd2dfc6f LP |
331 | r = append_machine_properties( |
332 | m, | |
333 | mounts, | |
334 | n_mounts, | |
411d8c72 | 335 | kill_signal, |
869c1cf8 | 336 | start_mode == START_BOOT && can_set_coredump_receive(bus) > 0); |
cd2dfc6f LP |
337 | if (r < 0) |
338 | return r; | |
339 | ||
89ada3ba | 340 | r = bus_append_unit_property_assignment_many(m, UNIT_SCOPE, properties); |
cd2dfc6f LP |
341 | if (r < 0) |
342 | return r; | |
343 | ||
344 | r = sd_bus_message_close_container(m); | |
345 | if (r < 0) | |
346 | return bus_log_create_error(r); | |
347 | ||
348 | /* No auxiliary units */ | |
349 | r = sd_bus_message_append( | |
350 | m, | |
351 | "a(sa(sv))", | |
352 | 0); | |
353 | if (r < 0) | |
354 | return bus_log_create_error(r); | |
355 | ||
0a5706d1 | 356 | r = sd_bus_call(bus, m, 0, &error, &reply); |
7eda208f LP |
357 | if (r < 0) { |
358 | /* If this failed with a property we couldn't write, this is quite likely because the server | |
359 | * doesn't support PIDFDs yet, let's try without. */ | |
360 | if (allow_pidfd && | |
361 | sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY, SD_BUS_ERROR_PROPERTY_READ_ONLY)) | |
411d8c72 | 362 | return allocate_scope(bus, machine_name, pid, slice, mounts, n_mounts, kill_signal, properties, properties_message, /* allow_pidfd= */ false, start_mode); |
7eda208f | 363 | |
4ae25393 | 364 | return log_error_errno(r, "Failed to allocate scope: %s", bus_error_message(&error, r)); |
7eda208f | 365 | } |
cd2dfc6f | 366 | |
0a5706d1 ZJS |
367 | r = sd_bus_message_read(reply, "o", &object); |
368 | if (r < 0) | |
369 | return bus_log_parse_error(r); | |
370 | ||
e22ad53d | 371 | r = bus_wait_for_jobs_one(w, object, BUS_WAIT_JOBS_LOG_ERROR, NULL); |
0a5706d1 ZJS |
372 | if (r < 0) |
373 | return r; | |
374 | ||
cd2dfc6f LP |
375 | return 0; |
376 | } | |
1d78fea2 LP |
377 | |
378 | int terminate_scope( | |
379 | sd_bus *bus, | |
380 | const char *machine_name) { | |
381 | ||
382 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; | |
383 | _cleanup_free_ char *scope = NULL; | |
384 | int r; | |
385 | ||
df7c4eb6 | 386 | r = unit_name_mangle_with_suffix(machine_name, "to terminate", 0, ".scope", &scope); |
1d78fea2 LP |
387 | if (r < 0) |
388 | return log_error_errno(r, "Failed to mangle scope name: %m"); | |
389 | ||
1ecaac5c | 390 | r = bus_call_method(bus, bus_systemd_mgr, "AbandonScope", &error, NULL, "s", scope); |
1d78fea2 LP |
391 | if (r < 0) { |
392 | log_debug_errno(r, "Failed to abandon scope '%s', ignoring: %s", scope, bus_error_message(&error, r)); | |
393 | sd_bus_error_free(&error); | |
394 | } | |
395 | ||
1ecaac5c | 396 | r = bus_call_method( |
1d78fea2 | 397 | bus, |
1ecaac5c | 398 | bus_systemd_mgr, |
1d78fea2 LP |
399 | "KillUnit", |
400 | &error, | |
401 | NULL, | |
402 | "ssi", | |
403 | scope, | |
404 | "all", | |
405 | (int32_t) SIGKILL); | |
406 | if (r < 0) { | |
407 | log_debug_errno(r, "Failed to SIGKILL scope '%s', ignoring: %s", scope, bus_error_message(&error, r)); | |
408 | sd_bus_error_free(&error); | |
409 | } | |
410 | ||
1ecaac5c | 411 | r = bus_call_method(bus, bus_systemd_mgr, "UnrefUnit", &error, NULL, "s", scope); |
1d78fea2 LP |
412 | if (r < 0) |
413 | log_debug_errno(r, "Failed to drop reference to scope '%s', ignoring: %s", scope, bus_error_message(&error, r)); | |
414 | ||
415 | return 0; | |
416 | } |