1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
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.
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.
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/>.
28 #include "bus-common-errors.h"
29 #include "bus-label.h"
32 #include "logind-session.h"
33 #include "logind-session-device.h"
35 static int property_get_user(
38 const char *interface,
40 sd_bus_message *reply,
42 sd_bus_error *error) {
44 _cleanup_free_ char *p = NULL;
45 Session *s = userdata;
51 p = user_bus_path(s->user);
55 return sd_bus_message_append(reply, "(uo)", (uint32_t) s->user->uid, p);
58 static int property_get_name(
61 const char *interface,
63 sd_bus_message *reply,
65 sd_bus_error *error) {
67 Session *s = userdata;
73 return sd_bus_message_append(reply, "s", s->user->name);
76 static int property_get_seat(
79 const char *interface,
81 sd_bus_message *reply,
83 sd_bus_error *error) {
85 _cleanup_free_ char *p = NULL;
86 Session *s = userdata;
92 p = s->seat ? seat_bus_path(s->seat) : strdup("/");
96 return sd_bus_message_append(reply, "(so)", s->seat ? s->seat->id : "", p);
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);
102 static int property_get_active(
105 const char *interface,
106 const char *property,
107 sd_bus_message *reply,
109 sd_bus_error *error) {
111 Session *s = userdata;
117 return sd_bus_message_append(reply, "b", session_is_active(s));
120 static int property_get_state(
123 const char *interface,
124 const char *property,
125 sd_bus_message *reply,
127 sd_bus_error *error) {
129 Session *s = userdata;
135 return sd_bus_message_append(reply, "s", session_state_to_string(session_get_state(s)));
138 static int property_get_idle_hint(
141 const char *interface,
142 const char *property,
143 sd_bus_message *reply,
145 sd_bus_error *error) {
147 Session *s = userdata;
153 return sd_bus_message_append(reply, "b", session_get_idle_hint(s, NULL) > 0);
156 static int property_get_idle_since_hint(
159 const char *interface,
160 const char *property,
161 sd_bus_message *reply,
163 sd_bus_error *error) {
165 Session *s = userdata;
166 dual_timestamp t = DUAL_TIMESTAMP_NULL;
174 r = session_get_idle_hint(s, &t);
178 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
180 return sd_bus_message_append(reply, "t", u);
183 int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
184 Session *s = userdata;
190 r = bus_verify_polkit_async(
193 "org.freedesktop.login1.manage",
197 &s->manager->polkit_registry,
202 return 1; /* Will call us back */
204 r = session_stop(s, true);
208 return sd_bus_reply_method_return(message, NULL);
211 int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
212 Session *s = userdata;
218 r = session_activate(s);
222 return sd_bus_reply_method_return(message, NULL);
225 int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error) {
226 Session *s = userdata;
232 r = bus_verify_polkit_async(
235 "org.freedesktop.login1.lock-sessions",
239 &s->manager->polkit_registry,
244 return 1; /* Will call us back */
246 r = session_send_lock(s, strstr(sd_bus_message_get_member(message), "Lock"));
250 return sd_bus_reply_method_return(message, NULL);
253 static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
254 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
255 Session *s = userdata;
262 r = sd_bus_message_read(message, "b", &b);
266 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
270 r = sd_bus_creds_get_euid(creds, &uid);
274 if (uid != 0 && uid != s->user->uid)
275 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
277 session_set_idle_hint(s, b);
279 return sd_bus_reply_method_return(message, NULL);
282 int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
283 Session *s = userdata;
292 r = sd_bus_message_read(message, "si", &swho, &signo);
299 who = kill_who_from_string(swho);
301 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
304 if (signo <= 0 || signo >= _NSIG)
305 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
307 r = bus_verify_polkit_async(
310 "org.freedesktop.login1.manage",
314 &s->manager->polkit_registry,
319 return 1; /* Will call us back */
321 r = session_kill(s, who, signo);
325 return sd_bus_reply_method_return(message, NULL);
328 static int method_take_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
329 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
330 Session *s = userdata;
337 r = sd_bus_message_read(message, "b", &force);
341 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
345 r = sd_bus_creds_get_euid(creds, &uid);
349 if (uid != 0 && (force || uid != s->user->uid))
350 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
352 r = session_set_controller(s, sd_bus_message_get_sender(message), force);
356 return sd_bus_reply_method_return(message, NULL);
359 static int method_release_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
360 Session *s = userdata;
365 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
366 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
368 session_drop_controller(s);
370 return sd_bus_reply_method_return(message, NULL);
373 static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
374 Session *s = userdata;
375 uint32_t major, minor;
383 r = sd_bus_message_read(message, "uu", &major, &minor);
387 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
388 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
390 dev = makedev(major, minor);
391 sd = hashmap_get(s->devices, &dev);
393 /* We don't allow retrieving a device multiple times.
394 * The related ReleaseDevice call is not ref-counted.
395 * The caller should use dup() if it requires more
396 * than one fd (it would be functionally
398 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
400 r = session_device_new(s, dev, &sd);
404 r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
406 session_device_free(sd);
411 static int method_release_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
412 Session *s = userdata;
413 uint32_t major, minor;
421 r = sd_bus_message_read(message, "uu", &major, &minor);
425 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
426 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
428 dev = makedev(major, minor);
429 sd = hashmap_get(s->devices, &dev);
431 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
433 session_device_free(sd);
434 return sd_bus_reply_method_return(message, NULL);
437 static int method_pause_device_complete(sd_bus_message *message, void *userdata, sd_bus_error *error) {
438 Session *s = userdata;
439 uint32_t major, minor;
447 r = sd_bus_message_read(message, "uu", &major, &minor);
451 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
452 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
454 dev = makedev(major, minor);
455 sd = hashmap_get(s->devices, &dev);
457 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
459 session_device_complete_pause(sd);
461 return sd_bus_reply_method_return(message, NULL);
464 const sd_bus_vtable session_vtable[] = {
465 SD_BUS_VTABLE_START(0),
467 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
468 SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
469 SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
470 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
471 SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
472 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
473 SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
474 SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
475 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
476 SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
477 SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
478 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
479 SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
480 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
481 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
482 SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
483 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_CONST),
484 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
485 SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
486 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
487 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
488 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
489 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
491 SD_BUS_METHOD("Terminate", NULL, NULL, bus_session_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
492 SD_BUS_METHOD("Activate", NULL, NULL, bus_session_method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
493 SD_BUS_METHOD("Lock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
494 SD_BUS_METHOD("Unlock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
495 SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED),
496 SD_BUS_METHOD("Kill", "si", NULL, bus_session_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
497 SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED),
498 SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED),
499 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED),
500 SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, SD_BUS_VTABLE_UNPRIVILEGED),
501 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, SD_BUS_VTABLE_UNPRIVILEGED),
503 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
504 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
505 SD_BUS_SIGNAL("Lock", NULL, 0),
506 SD_BUS_SIGNAL("Unlock", NULL, 0),
511 int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
512 Manager *m = userdata;
522 if (streq(path, "/org/freedesktop/login1/session/self")) {
523 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
524 sd_bus_message *message;
527 message = sd_bus_get_current_message(bus);
531 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
535 r = sd_bus_creds_get_session(creds, &name);
539 session = hashmap_get(m->sessions, name);
541 _cleanup_free_ char *e = NULL;
544 p = startswith(path, "/org/freedesktop/login1/session/");
548 e = bus_label_unescape(p);
552 session = hashmap_get(m->sessions, e);
562 char *session_bus_path(Session *s) {
563 _cleanup_free_ char *t = NULL;
567 t = bus_label_escape(s->id);
571 return strappend("/org/freedesktop/login1/session/", t);
574 int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
575 _cleanup_strv_free_ char **l = NULL;
576 sd_bus_message *message;
577 Manager *m = userdata;
586 HASHMAP_FOREACH(session, m->sessions, i) {
589 p = session_bus_path(session);
593 r = strv_consume(&l, p);
598 message = sd_bus_get_current_message(bus);
600 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
603 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
605 r = sd_bus_creds_get_session(creds, &name);
607 session = hashmap_get(m->sessions, name);
609 r = strv_extend(&l, "/org/freedesktop/login1/session/self");
623 int session_send_signal(Session *s, bool new_session) {
624 _cleanup_free_ char *p = NULL;
628 p = session_bus_path(s);
632 return sd_bus_emit_signal(
634 "/org/freedesktop/login1",
635 "org.freedesktop.login1.Manager",
636 new_session ? "SessionNew" : "SessionRemoved",
640 int session_send_changed(Session *s, const char *properties, ...) {
641 _cleanup_free_ char *p = NULL;
649 p = session_bus_path(s);
653 l = strv_from_stdarg_alloca(properties);
655 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l);
658 int session_send_lock(Session *s, bool lock) {
659 _cleanup_free_ char *p = NULL;
663 p = session_bus_path(s);
667 return sd_bus_emit_signal(
670 "org.freedesktop.login1.Session",
671 lock ? "Lock" : "Unlock",
675 int session_send_lock_all(Manager *m, bool lock) {
682 HASHMAP_FOREACH(session, m->sessions, i) {
685 k = session_send_lock(session, lock);
693 int session_send_create_reply(Session *s, sd_bus_error *error) {
694 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
695 _cleanup_close_ int fifo_fd = -1;
696 _cleanup_free_ char *p = NULL;
700 /* This is called after the session scope and the user service
701 * were successfully created, and finishes where
702 * bus_manager_create_session() left off. */
704 if (!s->create_message)
707 /// elogind does not support scope and service jobs
709 if (!sd_bus_error_is_set(error) && (s->scope_job || s->user->service_job))
713 c = s->create_message;
714 s->create_message = NULL;
717 return sd_bus_reply_method_error(c, error);
719 fifo_fd = session_create_fifo(s);
723 /* Update the session state file before we notify the client
724 * about the result. */
727 p = session_bus_path(s);
731 log_debug("Sending reply about created session: "
732 "id=%s object_path=%s uid=%u runtime_path=%s "
733 "session_fd=%d seat=%s vtnr=%u",
736 (uint32_t) s->user->uid,
737 s->user->runtime_path,
739 s->seat ? s->seat->id : "",
742 return sd_bus_reply_method_return(
746 s->user->runtime_path,
748 (uint32_t) s->user->uid,
749 s->seat ? s->seat->id : "",