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