Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <errno.h>
4 : #include <string.h>
5 :
6 : #include "alloc-util.h"
7 : #include "bus-util.h"
8 : #include "format-util.h"
9 : #include "logind-dbus.h"
10 : #include "logind-session-dbus.h"
11 : #include "logind-user-dbus.h"
12 : #include "logind-user.h"
13 : #include "logind.h"
14 : #include "missing_capability.h"
15 : #include "signal-util.h"
16 : #include "strv.h"
17 : #include "user-util.h"
18 :
19 0 : static BUS_DEFINE_PROPERTY_GET2(property_get_state, "s", User, user_get_state, user_state_to_string);
20 :
21 0 : static int property_get_display(
22 : sd_bus *bus,
23 : const char *path,
24 : const char *interface,
25 : const char *property,
26 : sd_bus_message *reply,
27 : void *userdata,
28 : sd_bus_error *error) {
29 :
30 0 : _cleanup_free_ char *p = NULL;
31 0 : User *u = userdata;
32 :
33 0 : assert(bus);
34 0 : assert(reply);
35 0 : assert(u);
36 :
37 0 : p = u->display ? session_bus_path(u->display) : strdup("/");
38 0 : if (!p)
39 0 : return -ENOMEM;
40 :
41 0 : return sd_bus_message_append(reply, "(so)", u->display ? u->display->id : "", p);
42 : }
43 :
44 0 : static int property_get_sessions(
45 : sd_bus *bus,
46 : const char *path,
47 : const char *interface,
48 : const char *property,
49 : sd_bus_message *reply,
50 : void *userdata,
51 : sd_bus_error *error) {
52 :
53 0 : User *u = userdata;
54 : Session *session;
55 : int r;
56 :
57 0 : assert(bus);
58 0 : assert(reply);
59 0 : assert(u);
60 :
61 0 : r = sd_bus_message_open_container(reply, 'a', "(so)");
62 0 : if (r < 0)
63 0 : return r;
64 :
65 0 : LIST_FOREACH(sessions_by_user, session, u->sessions) {
66 0 : _cleanup_free_ char *p = NULL;
67 :
68 0 : p = session_bus_path(session);
69 0 : if (!p)
70 0 : return -ENOMEM;
71 :
72 0 : r = sd_bus_message_append(reply, "(so)", session->id, p);
73 0 : if (r < 0)
74 0 : return r;
75 :
76 : }
77 :
78 0 : return sd_bus_message_close_container(reply);
79 : }
80 :
81 0 : static int property_get_idle_hint(
82 : sd_bus *bus,
83 : const char *path,
84 : const char *interface,
85 : const char *property,
86 : sd_bus_message *reply,
87 : void *userdata,
88 : sd_bus_error *error) {
89 :
90 0 : User *u = userdata;
91 :
92 0 : assert(bus);
93 0 : assert(reply);
94 0 : assert(u);
95 :
96 0 : return sd_bus_message_append(reply, "b", user_get_idle_hint(u, NULL) > 0);
97 : }
98 :
99 0 : static int property_get_idle_since_hint(
100 : sd_bus *bus,
101 : const char *path,
102 : const char *interface,
103 : const char *property,
104 : sd_bus_message *reply,
105 : void *userdata,
106 : sd_bus_error *error) {
107 :
108 0 : User *u = userdata;
109 0 : dual_timestamp t = DUAL_TIMESTAMP_NULL;
110 : uint64_t k;
111 :
112 0 : assert(bus);
113 0 : assert(reply);
114 0 : assert(u);
115 :
116 0 : (void) user_get_idle_hint(u, &t);
117 0 : k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
118 :
119 0 : return sd_bus_message_append(reply, "t", k);
120 : }
121 :
122 0 : static int property_get_linger(
123 : sd_bus *bus,
124 : const char *path,
125 : const char *interface,
126 : const char *property,
127 : sd_bus_message *reply,
128 : void *userdata,
129 : sd_bus_error *error) {
130 :
131 0 : User *u = userdata;
132 : int r;
133 :
134 0 : assert(bus);
135 0 : assert(reply);
136 0 : assert(u);
137 :
138 0 : r = user_check_linger_file(u);
139 :
140 0 : return sd_bus_message_append(reply, "b", r > 0);
141 : }
142 :
143 0 : int bus_user_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
144 0 : User *u = userdata;
145 : int r;
146 :
147 0 : assert(message);
148 0 : assert(u);
149 :
150 0 : r = bus_verify_polkit_async(
151 : message,
152 : CAP_KILL,
153 : "org.freedesktop.login1.manage",
154 : NULL,
155 : false,
156 : u->uid,
157 0 : &u->manager->polkit_registry,
158 : error);
159 0 : if (r < 0)
160 0 : return r;
161 0 : if (r == 0)
162 0 : return 1; /* Will call us back */
163 :
164 0 : r = user_stop(u, true);
165 0 : if (r < 0)
166 0 : return r;
167 :
168 0 : return sd_bus_reply_method_return(message, NULL);
169 : }
170 :
171 0 : int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
172 0 : User *u = userdata;
173 : int32_t signo;
174 : int r;
175 :
176 0 : assert(message);
177 0 : assert(u);
178 :
179 0 : r = bus_verify_polkit_async(
180 : message,
181 : CAP_KILL,
182 : "org.freedesktop.login1.manage",
183 : NULL,
184 : false,
185 : u->uid,
186 0 : &u->manager->polkit_registry,
187 : error);
188 0 : if (r < 0)
189 0 : return r;
190 0 : if (r == 0)
191 0 : return 1; /* Will call us back */
192 :
193 0 : r = sd_bus_message_read(message, "i", &signo);
194 0 : if (r < 0)
195 0 : return r;
196 :
197 0 : if (!SIGNAL_VALID(signo))
198 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
199 :
200 0 : r = user_kill(u, signo);
201 0 : if (r < 0)
202 0 : return r;
203 :
204 0 : return sd_bus_reply_method_return(message, NULL);
205 : }
206 :
207 : const sd_bus_vtable user_vtable[] = {
208 : SD_BUS_VTABLE_START(0),
209 :
210 : SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(User, uid), SD_BUS_VTABLE_PROPERTY_CONST),
211 : SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(User, gid), SD_BUS_VTABLE_PROPERTY_CONST),
212 : SD_BUS_PROPERTY("Name", "s", NULL, offsetof(User, name), SD_BUS_VTABLE_PROPERTY_CONST),
213 : BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(User, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
214 : SD_BUS_PROPERTY("RuntimePath", "s", NULL, offsetof(User, runtime_path), SD_BUS_VTABLE_PROPERTY_CONST),
215 : SD_BUS_PROPERTY("Service", "s", NULL, offsetof(User, service), SD_BUS_VTABLE_PROPERTY_CONST),
216 : SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST),
217 : SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
218 : SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
219 : SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
220 : SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
221 : SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
222 : SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
223 : SD_BUS_PROPERTY("Linger", "b", property_get_linger, 0, 0),
224 :
225 : SD_BUS_METHOD("Terminate", NULL, NULL, bus_user_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
226 : SD_BUS_METHOD("Kill", "i", NULL, bus_user_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
227 :
228 : SD_BUS_VTABLE_END
229 : };
230 :
231 0 : int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
232 0 : Manager *m = userdata;
233 : uid_t uid;
234 : User *user;
235 : int r;
236 :
237 0 : assert(bus);
238 0 : assert(path);
239 0 : assert(interface);
240 0 : assert(found);
241 0 : assert(m);
242 :
243 0 : if (streq(path, "/org/freedesktop/login1/user/self")) {
244 : sd_bus_message *message;
245 :
246 0 : message = sd_bus_get_current_message(bus);
247 0 : if (!message)
248 0 : return 0;
249 :
250 0 : r = manager_get_user_from_creds(m, message, UID_INVALID, error, &user);
251 0 : if (r == -ENXIO) {
252 0 : sd_bus_error_free(error);
253 0 : return 0;
254 : }
255 0 : if (r < 0)
256 0 : return r;
257 : } else {
258 : const char *p;
259 :
260 0 : p = startswith(path, "/org/freedesktop/login1/user/_");
261 0 : if (!p)
262 0 : return 0;
263 :
264 0 : r = parse_uid(p, &uid);
265 0 : if (r < 0)
266 0 : return 0;
267 :
268 0 : user = hashmap_get(m->users, UID_TO_PTR(uid));
269 0 : if (!user)
270 0 : return 0;
271 : }
272 :
273 0 : *found = user;
274 0 : return 1;
275 : }
276 :
277 0 : char *user_bus_path(User *u) {
278 : char *s;
279 :
280 0 : assert(u);
281 :
282 0 : if (asprintf(&s, "/org/freedesktop/login1/user/_"UID_FMT, u->uid) < 0)
283 0 : return NULL;
284 :
285 0 : return s;
286 : }
287 :
288 0 : int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
289 0 : _cleanup_strv_free_ char **l = NULL;
290 : sd_bus_message *message;
291 0 : Manager *m = userdata;
292 : User *user;
293 : Iterator i;
294 : int r;
295 :
296 0 : assert(bus);
297 0 : assert(path);
298 0 : assert(nodes);
299 :
300 0 : HASHMAP_FOREACH(user, m->users, i) {
301 : char *p;
302 :
303 0 : p = user_bus_path(user);
304 0 : if (!p)
305 0 : return -ENOMEM;
306 :
307 0 : r = strv_consume(&l, p);
308 0 : if (r < 0)
309 0 : return r;
310 : }
311 :
312 0 : message = sd_bus_get_current_message(bus);
313 0 : if (message) {
314 0 : _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
315 :
316 0 : r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
317 0 : if (r >= 0) {
318 : uid_t uid;
319 :
320 0 : r = sd_bus_creds_get_owner_uid(creds, &uid);
321 0 : if (r >= 0) {
322 0 : user = hashmap_get(m->users, UID_TO_PTR(uid));
323 0 : if (user) {
324 0 : r = strv_extend(&l, "/org/freedesktop/login1/user/self");
325 0 : if (r < 0)
326 0 : return r;
327 : }
328 : }
329 : }
330 : }
331 :
332 0 : *nodes = TAKE_PTR(l);
333 :
334 0 : return 1;
335 : }
336 :
337 0 : int user_send_signal(User *u, bool new_user) {
338 0 : _cleanup_free_ char *p = NULL;
339 :
340 0 : assert(u);
341 :
342 0 : p = user_bus_path(u);
343 0 : if (!p)
344 0 : return -ENOMEM;
345 :
346 0 : return sd_bus_emit_signal(
347 0 : u->manager->bus,
348 : "/org/freedesktop/login1",
349 : "org.freedesktop.login1.Manager",
350 : new_user ? "UserNew" : "UserRemoved",
351 0 : "uo", (uint32_t) u->uid, p);
352 : }
353 :
354 0 : int user_send_changed(User *u, const char *properties, ...) {
355 0 : _cleanup_free_ char *p = NULL;
356 : char **l;
357 :
358 0 : assert(u);
359 :
360 0 : if (!u->started)
361 0 : return 0;
362 :
363 0 : p = user_bus_path(u);
364 0 : if (!p)
365 0 : return -ENOMEM;
366 :
367 0 : l = strv_from_stdarg_alloca(properties);
368 :
369 0 : return sd_bus_emit_properties_changed_strv(u->manager->bus, p, "org.freedesktop.login1.User", l);
370 : }
|