chiark / gitweb /
tmpfiles: add 'a' type to set ACLs
[elogind.git] / src / login / logind-seat-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 "util.h"
26 #include "bus-util.h"
27 #include "strv.h"
28 #include "bus-common-errors.h"
29 #include "bus-label.h"
30 #include "logind.h"
31 #include "logind-seat.h"
32
33 static int property_get_active_session(
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         Seat *s = userdata;
44
45         assert(bus);
46         assert(reply);
47         assert(s);
48
49         p = s->active ? session_bus_path(s->active) : strdup("/");
50         if (!p)
51                 return -ENOMEM;
52
53         return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p);
54 }
55
56 static int property_get_can_multi_session(
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         Seat *s = userdata;
66
67         assert(bus);
68         assert(reply);
69         assert(s);
70
71         return sd_bus_message_append(reply, "b", seat_can_multi_session(s));
72 }
73
74 static int property_get_can_tty(
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         Seat *s = userdata;
84
85         assert(bus);
86         assert(reply);
87         assert(s);
88
89         return sd_bus_message_append(reply, "b", seat_can_tty(s));
90 }
91
92 static int property_get_can_graphical(
93                 sd_bus *bus,
94                 const char *path,
95                 const char *interface,
96                 const char *property,
97                 sd_bus_message *reply,
98                 void *userdata,
99                 sd_bus_error *error) {
100
101         Seat *s = userdata;
102
103         assert(bus);
104         assert(reply);
105         assert(s);
106
107         return sd_bus_message_append(reply, "b", seat_can_graphical(s));
108 }
109
110 static int property_get_sessions(
111                 sd_bus *bus,
112                 const char *path,
113                 const char *interface,
114                 const char *property,
115                 sd_bus_message *reply,
116                 void *userdata,
117                 sd_bus_error *error) {
118
119         Seat *s = userdata;
120         Session *session;
121         int r;
122
123         assert(bus);
124         assert(reply);
125         assert(s);
126
127         r = sd_bus_message_open_container(reply, 'a', "(so)");
128         if (r < 0)
129                 return r;
130
131         LIST_FOREACH(sessions_by_seat, session, s->sessions) {
132                 _cleanup_free_ char *p = NULL;
133
134                 p = session_bus_path(session);
135                 if (!p)
136                         return -ENOMEM;
137
138                 r = sd_bus_message_append(reply, "(so)", session->id, p);
139                 if (r < 0)
140                         return r;
141
142         }
143
144         r = sd_bus_message_close_container(reply);
145         if (r < 0)
146                 return r;
147
148         return 1;
149 }
150
151 static int property_get_idle_hint(
152                 sd_bus *bus,
153                 const char *path,
154                 const char *interface,
155                 const char *property,
156                 sd_bus_message *reply,
157                 void *userdata,
158                 sd_bus_error *error) {
159
160         Seat *s = userdata;
161
162         assert(bus);
163         assert(reply);
164         assert(s);
165
166         return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0);
167 }
168
169 static int property_get_idle_since_hint(
170                 sd_bus *bus,
171                 const char *path,
172                 const char *interface,
173                 const char *property,
174                 sd_bus_message *reply,
175                 void *userdata,
176                 sd_bus_error *error) {
177
178         Seat *s = userdata;
179         dual_timestamp t;
180         uint64_t u;
181         int r;
182
183         assert(bus);
184         assert(reply);
185         assert(s);
186
187         r = seat_get_idle_hint(s, &t);
188         if (r < 0)
189                 return r;
190
191         u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
192
193         return sd_bus_message_append(reply, "t", u);
194 }
195
196 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
197         Seat *s = userdata;
198         int r;
199
200         assert(bus);
201         assert(message);
202         assert(s);
203
204         r = seat_stop_sessions(s, true);
205         if (r < 0)
206                 return r;
207
208         return sd_bus_reply_method_return(message, NULL);
209 }
210
211 static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
212         Seat *s = userdata;
213         const char *name;
214         Session *session;
215         int r;
216
217         assert(bus);
218         assert(message);
219         assert(s);
220
221         r = sd_bus_message_read(message, "s", &name);
222         if (r < 0)
223                 return r;
224
225         session = hashmap_get(s->manager->sessions, name);
226         if (!session)
227                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
228
229         if (session->seat != s)
230                 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
231
232         r = session_activate(session);
233         if (r < 0)
234                 return r;
235
236         return sd_bus_reply_method_return(message, NULL);
237 }
238
239 static int method_switch_to(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
240         Seat *s = userdata;
241         unsigned int to;
242         int r;
243
244         assert(bus);
245         assert(message);
246         assert(s);
247
248         r = sd_bus_message_read(message, "u", &to);
249         if (r < 0)
250                 return r;
251
252         if (to <= 0)
253                 return -EINVAL;
254
255         r = seat_switch_to(s, to);
256         if (r < 0)
257                 return r;
258
259         return sd_bus_reply_method_return(message, NULL);
260 }
261
262 static int method_switch_to_next(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
263         Seat *s = userdata;
264         int r;
265
266         assert(bus);
267         assert(message);
268         assert(s);
269
270         r = seat_switch_to_next(s);
271         if (r < 0)
272                 return r;
273
274         return sd_bus_reply_method_return(message, NULL);
275 }
276
277 static int method_switch_to_previous(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
278         Seat *s = userdata;
279         int r;
280
281         assert(bus);
282         assert(message);
283         assert(s);
284
285         r = seat_switch_to_previous(s);
286         if (r < 0)
287                 return r;
288
289         return sd_bus_reply_method_return(message, NULL);
290 }
291
292 const sd_bus_vtable seat_vtable[] = {
293         SD_BUS_VTABLE_START(0),
294
295         SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
296         SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
297         SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
298         SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
299         SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
300         SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
301         SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
302         SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
303         SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
304
305         SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
306         SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
307         SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED),
308         SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
309         SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
310
311         SD_BUS_VTABLE_END
312 };
313
314 int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
315         Manager *m = userdata;
316         Seat *seat;
317         int r;
318
319         assert(bus);
320         assert(path);
321         assert(interface);
322         assert(found);
323         assert(m);
324
325         if (streq(path, "/org/freedesktop/login1/seat/self")) {
326                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
327                 sd_bus_message *message;
328                 Session *session;
329                 const char *name;
330
331                 message = sd_bus_get_current_message(bus);
332                 if (!message)
333                         return 0;
334
335                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
336                 if (r < 0)
337                         return r;
338
339                 r = sd_bus_creds_get_session(creds, &name);
340                 if (r < 0)
341                         return r;
342
343                 session = hashmap_get(m->sessions, name);
344                 if (!session)
345                         return 0;
346
347                 seat = session->seat;
348         } else {
349                 _cleanup_free_ char *e = NULL;
350                 const char *p;
351
352                 p = startswith(path, "/org/freedesktop/login1/seat/");
353                 if (!p)
354                         return 0;
355
356                 e = bus_label_unescape(p);
357                 if (!e)
358                         return -ENOMEM;
359
360                 seat = hashmap_get(m->seats, e);
361         }
362
363         if (!seat)
364                 return 0;
365
366         *found = seat;
367         return 1;
368 }
369
370 char *seat_bus_path(Seat *s) {
371         _cleanup_free_ char *t = NULL;
372
373         assert(s);
374
375         t = bus_label_escape(s->id);
376         if (!t)
377                 return NULL;
378
379         return strappend("/org/freedesktop/login1/seat/", t);
380 }
381
382 int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
383         _cleanup_strv_free_ char **l = NULL;
384         sd_bus_message *message;
385         Manager *m = userdata;
386         Seat *seat;
387         Iterator i;
388         int r;
389
390         assert(bus);
391         assert(path);
392         assert(nodes);
393
394         HASHMAP_FOREACH(seat, m->seats, i) {
395                 char *p;
396
397                 p = seat_bus_path(seat);
398                 if (!p)
399                         return -ENOMEM;
400
401                 r = strv_consume(&l, p);
402                 if (r < 0)
403                         return r;
404         }
405
406         message = sd_bus_get_current_message(bus);
407         if (message) {
408                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
409                 const char *name;
410                 Session *session;
411
412                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
413                 if (r >= 0) {
414                         r = sd_bus_creds_get_session(creds, &name);
415                         if (r >= 0) {
416                                 session = hashmap_get(m->sessions, name);
417                                 if (session && session->seat) {
418                                         r = strv_extend(&l, "/org/freedesktop/login1/seat/self");
419                                         if (r < 0)
420                                                 return r;
421                                 }
422                         }
423                 }
424         }
425
426         *nodes = l;
427         l = NULL;
428
429         return 1;
430 }
431
432 int seat_send_signal(Seat *s, bool new_seat) {
433         _cleanup_free_ char *p = NULL;
434
435         assert(s);
436
437         p = seat_bus_path(s);
438         if (!p)
439                 return -ENOMEM;
440
441         return sd_bus_emit_signal(
442                         s->manager->bus,
443                         "/org/freedesktop/login1",
444                         "org.freedesktop.login1.Manager",
445                         new_seat ? "SeatNew" : "SeatRemoved",
446                         "so", s->id, p);
447 }
448
449 int seat_send_changed(Seat *s, const char *properties, ...) {
450         _cleanup_free_ char *p = NULL;
451         char **l;
452
453         assert(s);
454
455         if (!s->started)
456                 return 0;
457
458         p = seat_bus_path(s);
459         if (!p)
460                 return -ENOMEM;
461
462         l = strv_from_stdarg_alloca(properties);
463
464         return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
465 }