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