chiark / gitweb /
Remove support for auto-spawning VTs
[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 #include "formats-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_bus_creds_unref_ 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_bus_creds_unref_ 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 }