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