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