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