]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-session-dbus.c
logind: remove spurious include of <sys/capability.h>
[thirdparty/systemd.git] / src / login / logind-session-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 "strv.h"
27 #include "bus-util.h"
28 #include "bus-common-errors.h"
29 #include "bus-label.h"
30
31 #include "logind.h"
32 #include "logind-session.h"
33 #include "logind-session-device.h"
34
35 static int property_get_user(
36 sd_bus *bus,
37 const char *path,
38 const char *interface,
39 const char *property,
40 sd_bus_message *reply,
41 void *userdata,
42 sd_bus_error *error) {
43
44 _cleanup_free_ char *p = NULL;
45 Session *s = userdata;
46
47 assert(bus);
48 assert(reply);
49 assert(s);
50
51 p = user_bus_path(s->user);
52 if (!p)
53 return -ENOMEM;
54
55 return sd_bus_message_append(reply, "(uo)", (uint32_t) s->user->uid, p);
56 }
57
58 static int property_get_name(
59 sd_bus *bus,
60 const char *path,
61 const char *interface,
62 const char *property,
63 sd_bus_message *reply,
64 void *userdata,
65 sd_bus_error *error) {
66
67 Session *s = userdata;
68
69 assert(bus);
70 assert(reply);
71 assert(s);
72
73 return sd_bus_message_append(reply, "s", s->user->name);
74 }
75
76 static int property_get_seat(
77 sd_bus *bus,
78 const char *path,
79 const char *interface,
80 const char *property,
81 sd_bus_message *reply,
82 void *userdata,
83 sd_bus_error *error) {
84
85 _cleanup_free_ char *p = NULL;
86 Session *s = userdata;
87
88 assert(bus);
89 assert(reply);
90 assert(s);
91
92 p = s->seat ? seat_bus_path(s->seat) : strdup("/");
93 if (!p)
94 return -ENOMEM;
95
96 return sd_bus_message_append(reply, "(so)", s->seat ? s->seat->id : "", p);
97 }
98
99 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, session_type, SessionType);
100 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, session_class, SessionClass);
101
102 static int property_get_active(
103 sd_bus *bus,
104 const char *path,
105 const char *interface,
106 const char *property,
107 sd_bus_message *reply,
108 void *userdata,
109 sd_bus_error *error) {
110
111 Session *s = userdata;
112
113 assert(bus);
114 assert(reply);
115 assert(s);
116
117 return sd_bus_message_append(reply, "b", session_is_active(s));
118 }
119
120 static int property_get_state(
121 sd_bus *bus,
122 const char *path,
123 const char *interface,
124 const char *property,
125 sd_bus_message *reply,
126 void *userdata,
127 sd_bus_error *error) {
128
129 Session *s = userdata;
130
131 assert(bus);
132 assert(reply);
133 assert(s);
134
135 return sd_bus_message_append(reply, "s", session_state_to_string(session_get_state(s)));
136 }
137
138 static int property_get_idle_hint(
139 sd_bus *bus,
140 const char *path,
141 const char *interface,
142 const char *property,
143 sd_bus_message *reply,
144 void *userdata,
145 sd_bus_error *error) {
146
147 Session *s = userdata;
148
149 assert(bus);
150 assert(reply);
151 assert(s);
152
153 return sd_bus_message_append(reply, "b", session_get_idle_hint(s, NULL) > 0);
154 }
155
156 static int property_get_idle_since_hint(
157 sd_bus *bus,
158 const char *path,
159 const char *interface,
160 const char *property,
161 sd_bus_message *reply,
162 void *userdata,
163 sd_bus_error *error) {
164
165 Session *s = userdata;
166 dual_timestamp t;
167 uint64_t u;
168 int r;
169
170 assert(bus);
171 assert(reply);
172 assert(s);
173
174 r = session_get_idle_hint(s, &t);
175 if (r < 0)
176 return r;
177
178 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
179
180 return sd_bus_message_append(reply, "t", u);
181 }
182
183 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
184 Session *s = userdata;
185 int r;
186
187 assert(bus);
188 assert(message);
189 assert(s);
190
191 r = session_stop(s, true);
192 if (r < 0)
193 return r;
194
195 return sd_bus_reply_method_return(message, NULL);
196 }
197
198 static int method_activate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
199 Session *s = userdata;
200 int r;
201
202 assert(bus);
203 assert(message);
204 assert(s);
205
206 r = session_activate(s);
207 if (r < 0)
208 return r;
209
210 return sd_bus_reply_method_return(message, NULL);
211 }
212
213 static int method_lock(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
214 Session *s = userdata;
215 int r;
216
217 assert(bus);
218 assert(message);
219 assert(s);
220
221 r = session_send_lock(s, streq(sd_bus_message_get_member(message), "Lock"));
222 if (r < 0)
223 return r;
224
225 return sd_bus_reply_method_return(message, NULL);
226 }
227
228 static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
229 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
230 Session *s = userdata;
231 uid_t uid;
232 int r, b;
233
234 assert(bus);
235 assert(message);
236 assert(s);
237
238 r = sd_bus_message_read(message, "b", &b);
239 if (r < 0)
240 return r;
241
242 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
243 if (r < 0)
244 return r;
245
246 r = sd_bus_creds_get_uid(creds, &uid);
247 if (r < 0)
248 return r;
249
250 if (uid != 0 && uid != s->user->uid)
251 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
252
253 session_set_idle_hint(s, b);
254
255 return sd_bus_reply_method_return(message, NULL);
256 }
257
258 static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
259 Session *s = userdata;
260 const char *swho;
261 int32_t signo;
262 KillWho who;
263 int r;
264
265 assert(bus);
266 assert(message);
267 assert(s);
268
269 r = sd_bus_message_read(message, "si", &swho, &signo);
270 if (r < 0)
271 return r;
272
273 if (isempty(swho))
274 who = KILL_ALL;
275 else {
276 who = kill_who_from_string(swho);
277 if (who < 0)
278 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
279 }
280
281 if (signo <= 0 || signo >= _NSIG)
282 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
283
284 r = session_kill(s, who, signo);
285 if (r < 0)
286 return r;
287
288 return sd_bus_reply_method_return(message, NULL);
289 }
290
291 static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
292 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
293 Session *s = userdata;
294 int r, force;
295 uid_t uid;
296
297 assert(bus);
298 assert(message);
299 assert(s);
300
301 r = sd_bus_message_read(message, "b", &force);
302 if (r < 0)
303 return r;
304
305 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
306 if (r < 0)
307 return r;
308
309 r = sd_bus_creds_get_uid(creds, &uid);
310 if (r < 0)
311 return r;
312
313 if (uid != 0 && (force || uid != s->user->uid))
314 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
315
316 r = session_set_controller(s, sd_bus_message_get_sender(message), force);
317 if (r < 0)
318 return r;
319
320 return sd_bus_reply_method_return(message, NULL);
321 }
322
323 static int method_release_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
324 Session *s = userdata;
325
326 assert(bus);
327 assert(message);
328 assert(s);
329
330 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
331 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
332
333 session_drop_controller(s);
334
335 return sd_bus_reply_method_return(message, NULL);
336 }
337
338 static int method_take_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
339 Session *s = userdata;
340 uint32_t major, minor;
341 SessionDevice *sd;
342 dev_t dev;
343 int r;
344
345 assert(bus);
346 assert(message);
347 assert(s);
348
349 r = sd_bus_message_read(message, "uu", &major, &minor);
350 if (r < 0)
351 return r;
352
353 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
354 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
355
356 dev = makedev(major, minor);
357 sd = hashmap_get(s->devices, &dev);
358 if (sd)
359 /* We don't allow retrieving a device multiple times.
360 * The related ReleaseDevice call is not ref-counted.
361 * The caller should use dup() if it requires more
362 * than one fd (it would be functionally
363 * equivalent). */
364 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
365
366 r = session_device_new(s, dev, &sd);
367 if (r < 0)
368 return r;
369
370 r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
371 if (r < 0)
372 session_device_free(sd);
373
374 return r;
375 }
376
377 static int method_release_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
378 Session *s = userdata;
379 uint32_t major, minor;
380 SessionDevice *sd;
381 dev_t dev;
382 int r;
383
384 assert(bus);
385 assert(message);
386 assert(s);
387
388 r = sd_bus_message_read(message, "uu", &major, &minor);
389 if (r < 0)
390 return r;
391
392 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
393 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
394
395 dev = makedev(major, minor);
396 sd = hashmap_get(s->devices, &dev);
397 if (!sd)
398 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
399
400 session_device_free(sd);
401 return sd_bus_reply_method_return(message, NULL);
402 }
403
404 static int method_pause_device_complete(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
405 Session *s = userdata;
406 uint32_t major, minor;
407 SessionDevice *sd;
408 dev_t dev;
409 int r;
410
411 assert(bus);
412 assert(message);
413 assert(s);
414
415 r = sd_bus_message_read(message, "uu", &major, &minor);
416 if (r < 0)
417 return r;
418
419 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
420 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
421
422 dev = makedev(major, minor);
423 sd = hashmap_get(s->devices, &dev);
424 if (!sd)
425 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
426
427 session_device_complete_pause(sd);
428
429 return sd_bus_reply_method_return(message, NULL);
430 }
431
432 const sd_bus_vtable session_vtable[] = {
433 SD_BUS_VTABLE_START(0),
434
435 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
436 SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
437 SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
438 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
439 SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
440 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
441 SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
442 SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
443 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
444 SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
445 SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
446 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
447 SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
448 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
449 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
450 SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
451 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_CONST),
452 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
453 SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
454 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
455 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
456 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
457 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
458
459 SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
460 SD_BUS_METHOD("Activate", NULL, NULL, method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
461 SD_BUS_METHOD("Lock", NULL, NULL, method_lock, 0),
462 SD_BUS_METHOD("Unlock", NULL, NULL, method_lock, 0),
463 SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED),
464 SD_BUS_METHOD("Kill", "si", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
465 SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED),
466 SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED),
467 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED),
468 SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, SD_BUS_VTABLE_UNPRIVILEGED),
469 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, SD_BUS_VTABLE_UNPRIVILEGED),
470
471 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
472 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
473 SD_BUS_SIGNAL("Lock", NULL, 0),
474 SD_BUS_SIGNAL("Unlock", NULL, 0),
475
476 SD_BUS_VTABLE_END
477 };
478
479 int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
480 Manager *m = userdata;
481 Session *session;
482 int r;
483
484 assert(bus);
485 assert(path);
486 assert(interface);
487 assert(found);
488 assert(m);
489
490 if (streq(path, "/org/freedesktop/login1/session/self")) {
491 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
492 sd_bus_message *message;
493 pid_t pid;
494
495 message = sd_bus_get_current_message(bus);
496 if (!message)
497 return 0;
498
499 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
500 if (r < 0)
501 return r;
502
503 r = sd_bus_creds_get_pid(creds, &pid);
504 if (r < 0)
505 return r;
506
507 r = manager_get_session_by_pid(m, pid, &session);
508 if (r <= 0)
509 return 0;
510 } else {
511 _cleanup_free_ char *e = NULL;
512 const char *p;
513
514 p = startswith(path, "/org/freedesktop/login1/session/");
515 if (!p)
516 return 0;
517
518 e = bus_label_unescape(p);
519 if (!e)
520 return -ENOMEM;
521
522 session = hashmap_get(m->sessions, e);
523 if (!session)
524 return 0;
525 }
526
527 *found = session;
528 return 1;
529 }
530
531 char *session_bus_path(Session *s) {
532 _cleanup_free_ char *t = NULL;
533
534 assert(s);
535
536 t = bus_label_escape(s->id);
537 if (!t)
538 return NULL;
539
540 return strappend("/org/freedesktop/login1/session/", t);
541 }
542
543 int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
544 _cleanup_strv_free_ char **l = NULL;
545 Manager *m = userdata;
546 Session *session;
547 Iterator i;
548 int r;
549
550 assert(bus);
551 assert(path);
552 assert(nodes);
553
554 HASHMAP_FOREACH(session, m->sessions, i) {
555 char *p;
556
557 p = session_bus_path(session);
558 if (!p)
559 return -ENOMEM;
560
561 r = strv_consume(&l, p);
562 if (r < 0)
563 return r;
564 }
565
566 *nodes = l;
567 l = NULL;
568
569 return 1;
570 }
571
572 int session_send_signal(Session *s, bool new_session) {
573 _cleanup_free_ char *p = NULL;
574
575 assert(s);
576
577 p = session_bus_path(s);
578 if (!p)
579 return -ENOMEM;
580
581 return sd_bus_emit_signal(
582 s->manager->bus,
583 "/org/freedesktop/login1",
584 "org.freedesktop.login1.Manager",
585 new_session ? "SessionNew" : "SessionRemoved",
586 "so", s->id, p);
587 }
588
589 int session_send_changed(Session *s, const char *properties, ...) {
590 _cleanup_free_ char *p = NULL;
591 char **l;
592
593 assert(s);
594
595 if (!s->started)
596 return 0;
597
598 p = session_bus_path(s);
599 if (!p)
600 return -ENOMEM;
601
602 l = strv_from_stdarg_alloca(properties);
603
604 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l);
605 }
606
607 int session_send_lock(Session *s, bool lock) {
608 _cleanup_free_ char *p = NULL;
609
610 assert(s);
611
612 p = session_bus_path(s);
613 if (!p)
614 return -ENOMEM;
615
616 return sd_bus_emit_signal(
617 s->manager->bus,
618 p,
619 "org.freedesktop.login1.Session",
620 lock ? "Lock" : "Unlock",
621 NULL);
622 }
623
624 int session_send_lock_all(Manager *m, bool lock) {
625 Session *session;
626 Iterator i;
627 int r = 0;
628
629 assert(m);
630
631 HASHMAP_FOREACH(session, m->sessions, i) {
632 int k;
633
634 k = session_send_lock(session, lock);
635 if (k < 0)
636 r = k;
637 }
638
639 return r;
640 }
641
642 int session_send_create_reply(Session *s, sd_bus_error *error) {
643 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
644 _cleanup_close_ int fifo_fd = -1;
645 _cleanup_free_ char *p = NULL;
646
647 assert(s);
648
649 /* This is called after the session scope and the user service
650 * were successfully created, and finishes where
651 * bus_manager_create_session() left off. */
652
653 if (!s->create_message)
654 return 0;
655
656 if (!sd_bus_error_is_set(error) && (s->scope_job || s->user->service_job))
657 return 0;
658
659 c = s->create_message;
660 s->create_message = NULL;
661
662 if (error)
663 return sd_bus_reply_method_error(c, error);
664
665 fifo_fd = session_create_fifo(s);
666 if (fifo_fd < 0)
667 return fifo_fd;
668
669 /* Update the session state file before we notify the client
670 * about the result. */
671 session_save(s);
672
673 p = session_bus_path(s);
674 if (!p)
675 return -ENOMEM;
676
677 log_debug("Sending reply about created session: "
678 "id=%s object_path=%s uid=%u runtime_path=%s "
679 "session_fd=%d seat=%s vtnr=%u",
680 s->id,
681 p,
682 (uint32_t) s->user->uid,
683 s->user->runtime_path,
684 fifo_fd,
685 s->seat ? s->seat->id : "",
686 (uint32_t) s->vtnr);
687
688 return sd_bus_reply_method_return(
689 c, "soshusub",
690 s->id,
691 p,
692 s->user->runtime_path,
693 fifo_fd,
694 (uint32_t) s->user->uid,
695 s->seat ? s->seat->id : "",
696 (uint32_t) s->vtnr,
697 false);
698 }