]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-user-dbus.c
Merge pull request #1359 from jengelh/ue
[thirdparty/systemd.git] / src / login / logind-user-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <string.h>
24
25 #include "alloc-util.h"
26 #include "bus-util.h"
27 #include "formats-util.h"
28 #include "logind-user.h"
29 #include "logind.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 (signo <= 0 || signo >= _NSIG)
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, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
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 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
275 sd_bus_message *message;
276
277 message = sd_bus_get_current_message(bus);
278 if (!message)
279 return 0;
280
281 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
282 if (r < 0)
283 return r;
284
285 r = sd_bus_creds_get_owner_uid(creds, &uid);
286 } else {
287 const char *p;
288
289 p = startswith(path, "/org/freedesktop/login1/user/_");
290 if (!p)
291 return 0;
292
293 r = parse_uid(p, &uid);
294 }
295 if (r < 0)
296 return 0;
297
298 user = hashmap_get(m->users, UID_TO_PTR(uid));
299 if (!user)
300 return 0;
301
302 *found = user;
303 return 1;
304 }
305
306 char *user_bus_path(User *u) {
307 char *s;
308
309 assert(u);
310
311 if (asprintf(&s, "/org/freedesktop/login1/user/_"UID_FMT, u->uid) < 0)
312 return NULL;
313
314 return s;
315 }
316
317 int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
318 _cleanup_strv_free_ char **l = NULL;
319 sd_bus_message *message;
320 Manager *m = userdata;
321 User *user;
322 Iterator i;
323 int r;
324
325 assert(bus);
326 assert(path);
327 assert(nodes);
328
329 HASHMAP_FOREACH(user, m->users, i) {
330 char *p;
331
332 p = user_bus_path(user);
333 if (!p)
334 return -ENOMEM;
335
336 r = strv_consume(&l, p);
337 if (r < 0)
338 return r;
339 }
340
341 message = sd_bus_get_current_message(bus);
342 if (message) {
343 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
344 uid_t uid;
345
346 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
347 if (r >= 0) {
348 r = sd_bus_creds_get_owner_uid(creds, &uid);
349 if (r >= 0) {
350 user = hashmap_get(m->users, UID_TO_PTR(uid));
351 if (user) {
352 r = strv_extend(&l, "/org/freedesktop/login1/user/self");
353 if (r < 0)
354 return r;
355 }
356 }
357 }
358 }
359
360 *nodes = l;
361 l = NULL;
362
363 return 1;
364 }
365
366 int user_send_signal(User *u, bool new_user) {
367 _cleanup_free_ char *p = NULL;
368
369 assert(u);
370
371 p = user_bus_path(u);
372 if (!p)
373 return -ENOMEM;
374
375 return sd_bus_emit_signal(
376 u->manager->bus,
377 "/org/freedesktop/login1",
378 "org.freedesktop.login1.Manager",
379 new_user ? "UserNew" : "UserRemoved",
380 "uo", (uint32_t) u->uid, p);
381 }
382
383 int user_send_changed(User *u, const char *properties, ...) {
384 _cleanup_free_ char *p = NULL;
385 char **l;
386
387 assert(u);
388
389 if (!u->started)
390 return 0;
391
392 p = user_bus_path(u);
393 if (!p)
394 return -ENOMEM;
395
396 l = strv_from_stdarg_alloca(properties);
397
398 return sd_bus_emit_properties_changed_strv(u->manager->bus, p, "org.freedesktop.login1.User", l);
399 }