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