1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "alloc-util.h"
4 #include "bus-common-errors.h"
5 #include "bus-get-properties.h"
6 #include "dbus-cgroup.h"
7 #include "dbus-kill.h"
8 #include "dbus-scope.h"
9 #include "dbus-unit.h"
10 #include "dbus-util.h"
11 #include "dbus.h"
12 #include "scope.h"
13 #include "selinux-access.h"
14 #include "unit.h"
15 
bus_scope_method_abandon(sd_bus_message * message,void * userdata,sd_bus_error * error)16 int bus_scope_method_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
17         Scope *s = userdata;
18         int r;
19 
20         assert(message);
21         assert(s);
22 
23         r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
24         if (r < 0)
25                 return r;
26 
27         r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
28         if (r < 0)
29                 return r;
30         if (r == 0)
31                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
32 
33         r = scope_abandon(s);
34         if (r == -ESTALE)
35                 return sd_bus_error_setf(error, BUS_ERROR_SCOPE_NOT_RUNNING, "Scope %s is not running, cannot abandon.", UNIT(s)->id);
36         if (r < 0)
37                 return r;
38 
39         return sd_bus_reply_method_return(message, NULL);
40 }
41 
42 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult);
43 
44 const sd_bus_vtable bus_scope_vtable[] = {
45         SD_BUS_VTABLE_START(0),
46         SD_BUS_PROPERTY("Controller", "s", NULL, offsetof(Scope, controller), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
47         SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
48         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
49         SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Scope, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
50         SD_BUS_PROPERTY("RuntimeRandomizedExtraUSec", "t", bus_property_get_usec, offsetof(Scope, runtime_rand_extra_usec), SD_BUS_VTABLE_PROPERTY_CONST),
51         SD_BUS_SIGNAL("RequestStop", NULL, 0),
52         SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_method_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
53         SD_BUS_VTABLE_END
54 };
55 
bus_scope_set_transient_property(Scope * s,const char * name,sd_bus_message * message,UnitWriteFlags flags,sd_bus_error * error)56 static int bus_scope_set_transient_property(
57                 Scope *s,
58                 const char *name,
59                 sd_bus_message *message,
60                 UnitWriteFlags flags,
61                 sd_bus_error *error) {
62 
63         Unit *u = UNIT(s);
64         int r;
65 
66         assert(s);
67         assert(name);
68         assert(message);
69 
70         flags |= UNIT_PRIVATE;
71 
72         if (streq(name, "TimeoutStopUSec"))
73                 return bus_set_transient_usec(u, name, &s->timeout_stop_usec, message, flags, error);
74 
75         if (streq(name, "RuntimeMaxUSec"))
76                 return bus_set_transient_usec(u, name, &s->runtime_max_usec, message, flags, error);
77 
78         if (streq(name, "RuntimeRandomizedExtraUSec"))
79                 return bus_set_transient_usec(u, name, &s->runtime_rand_extra_usec, message, flags, error);
80 
81         if (streq(name, "PIDs")) {
82                 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
83                 unsigned n = 0;
84 
85                 r = sd_bus_message_enter_container(message, 'a', "u");
86                 if (r < 0)
87                         return r;
88 
89                 for (;;) {
90                         uint32_t upid;
91                         pid_t pid;
92 
93                         r = sd_bus_message_read(message, "u", &upid);
94                         if (r < 0)
95                                 return r;
96                         if (r == 0)
97                                 break;
98 
99                         if (upid == 0) {
100                                 if (!creds) {
101                                         r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
102                                         if (r < 0)
103                                                 return r;
104                                 }
105 
106                                 r = sd_bus_creds_get_pid(creds, &pid);
107                                 if (r < 0)
108                                         return r;
109                         } else
110                                 pid = (uid_t) upid;
111 
112                         r = unit_pid_attachable(u, pid, error);
113                         if (r < 0)
114                                 return r;
115 
116                         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
117                                 r = unit_watch_pid(u, pid, false);
118                                 if (r < 0 && r != -EEXIST)
119                                         return r;
120                         }
121 
122                         n++;
123                 }
124 
125                 r = sd_bus_message_exit_container(message);
126                 if (r < 0)
127                         return r;
128 
129                 if (n <= 0)
130                         return -EINVAL;
131 
132                 return 1;
133 
134         } else if (streq(name, "Controller")) {
135                 const char *controller;
136 
137                 /* We can't support direct connections with this, as direct connections know no service or unique name
138                  * concept, but the Controller field stores exactly that. */
139                 if (sd_bus_message_get_bus(message) != u->manager->api_bus)
140                         return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Sorry, Controller= logic only supported via the bus.");
141 
142                 r = sd_bus_message_read(message, "s", &controller);
143                 if (r < 0)
144                         return r;
145 
146                 if (!isempty(controller) && !sd_bus_service_name_is_valid(controller))
147                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller);
148 
149                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
150                         r = free_and_strdup(&s->controller, empty_to_null(controller));
151                         if (r < 0)
152                                 return r;
153                 }
154 
155                 return 1;
156         }
157 
158         return 0;
159 }
160 
bus_scope_set_property(Unit * u,const char * name,sd_bus_message * message,UnitWriteFlags flags,sd_bus_error * error)161 int bus_scope_set_property(
162                 Unit *u,
163                 const char *name,
164                 sd_bus_message *message,
165                 UnitWriteFlags flags,
166                 sd_bus_error *error) {
167 
168         Scope *s = SCOPE(u);
169         int r;
170 
171         assert(s);
172         assert(name);
173         assert(message);
174 
175         r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
176         if (r != 0)
177                 return r;
178 
179         if (u->load_state == UNIT_STUB) {
180                 /* While we are created we still accept PIDs */
181 
182                 r = bus_scope_set_transient_property(s, name, message, flags, error);
183                 if (r != 0)
184                         return r;
185 
186                 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
187                 if (r != 0)
188                         return r;
189         }
190 
191         return 0;
192 }
193 
bus_scope_commit_properties(Unit * u)194 int bus_scope_commit_properties(Unit *u) {
195         assert(u);
196 
197         unit_realize_cgroup(u);
198 
199         return 0;
200 }
201 
bus_scope_send_request_stop(Scope * s)202 int bus_scope_send_request_stop(Scope *s) {
203         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
204         _cleanup_free_ char *p = NULL;
205         int r;
206 
207         assert(s);
208 
209         if (!s->controller)
210                 return 0;
211 
212         p = unit_dbus_path(UNIT(s));
213         if (!p)
214                 return -ENOMEM;
215 
216         r = sd_bus_message_new_signal(
217                         UNIT(s)->manager->api_bus,
218                         &m,
219                         p,
220                         "org.freedesktop.systemd1.Scope",
221                         "RequestStop");
222         if (r < 0)
223                 return r;
224 
225         return sd_bus_send_to(UNIT(s)->manager->api_bus, m, s->controller, NULL);
226 }
227 
on_controller_gone(sd_bus_track * track,void * userdata)228 static int on_controller_gone(sd_bus_track *track, void *userdata) {
229         Scope *s = userdata;
230 
231         assert(track);
232 
233         if (s->controller) {
234                 log_unit_debug(UNIT(s), "Controller %s disappeared from bus.", s->controller);
235                 unit_add_to_dbus_queue(UNIT(s));
236                 s->controller = mfree(s->controller);
237         }
238 
239         s->controller_track = sd_bus_track_unref(s->controller_track);
240 
241         return 0;
242 }
243 
bus_scope_track_controller(Scope * s)244 int bus_scope_track_controller(Scope *s) {
245         int r;
246 
247         assert(s);
248 
249         if (!s->controller || s->controller_track)
250                 return 0;
251 
252         r = sd_bus_track_new(UNIT(s)->manager->api_bus, &s->controller_track, on_controller_gone, s);
253         if (r < 0)
254                 return r;
255 
256         r = sd_bus_track_add_name(s->controller_track, s->controller);
257         if (r < 0) {
258                 s->controller_track = sd_bus_track_unref(s->controller_track);
259                 return r;
260         }
261 
262         return 0;
263 }
264