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/>.
25 #include "alloc-util.h"
26 #include "bus-common-errors.h"
27 #include "bus-label.h"
30 #include "logind-session-device.h"
31 #include "logind-session.h"
36 static int property_get_user(
39 const char *interface,
41 sd_bus_message *reply,
43 sd_bus_error *error) {
45 _cleanup_free_ char *p = NULL;
46 Session *s = userdata;
52 p = user_bus_path(s->user);
56 return sd_bus_message_append(reply, "(uo)", (uint32_t) s->user->uid, p);
59 static int property_get_name(
62 const char *interface,
64 sd_bus_message *reply,
66 sd_bus_error *error) {
68 Session *s = userdata;
74 return sd_bus_message_append(reply, "s", s->user->name);
77 static int property_get_seat(
80 const char *interface,
82 sd_bus_message *reply,
84 sd_bus_error *error) {
86 _cleanup_free_ char *p = NULL;
87 Session *s = userdata;
93 p = s->seat ? seat_bus_path(s->seat) : strdup("/");
97 return sd_bus_message_append(reply, "(so)", s->seat ? s->seat->id : "", p);
100 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, session_type, SessionType);
101 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, session_class, SessionClass);
103 static int property_get_active(
106 const char *interface,
107 const char *property,
108 sd_bus_message *reply,
110 sd_bus_error *error) {
112 Session *s = userdata;
118 return sd_bus_message_append(reply, "b", session_is_active(s));
121 static int property_get_state(
124 const char *interface,
125 const char *property,
126 sd_bus_message *reply,
128 sd_bus_error *error) {
130 Session *s = userdata;
136 return sd_bus_message_append(reply, "s", session_state_to_string(session_get_state(s)));
139 static int property_get_idle_hint(
142 const char *interface,
143 const char *property,
144 sd_bus_message *reply,
146 sd_bus_error *error) {
148 Session *s = userdata;
154 return sd_bus_message_append(reply, "b", session_get_idle_hint(s, NULL) > 0);
157 static int property_get_idle_since_hint(
160 const char *interface,
161 const char *property,
162 sd_bus_message *reply,
164 sd_bus_error *error) {
166 Session *s = userdata;
167 dual_timestamp t = DUAL_TIMESTAMP_NULL;
175 r = session_get_idle_hint(s, &t);
179 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
181 return sd_bus_message_append(reply, "t", u);
184 int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
185 Session *s = userdata;
191 r = bus_verify_polkit_async(
194 "org.freedesktop.login1.manage",
198 &s->manager->polkit_registry,
203 return 1; /* Will call us back */
205 r = session_stop(s, true);
209 return sd_bus_reply_method_return(message, NULL);
212 int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
213 Session *s = userdata;
219 r = session_activate(s);
223 return sd_bus_reply_method_return(message, NULL);
226 int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error) {
227 Session *s = userdata;
233 r = bus_verify_polkit_async(
236 "org.freedesktop.login1.lock-sessions",
240 &s->manager->polkit_registry,
245 return 1; /* Will call us back */
247 r = session_send_lock(s, strstr(sd_bus_message_get_member(message), "Lock"));
251 return sd_bus_reply_method_return(message, NULL);
254 static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
255 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
256 Session *s = userdata;
263 r = sd_bus_message_read(message, "b", &b);
267 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
271 r = sd_bus_creds_get_euid(creds, &uid);
275 if (uid != 0 && uid != s->user->uid)
276 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
278 session_set_idle_hint(s, b);
280 return sd_bus_reply_method_return(message, NULL);
283 int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
284 Session *s = userdata;
293 r = sd_bus_message_read(message, "si", &swho, &signo);
300 who = kill_who_from_string(swho);
302 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
305 if (signo <= 0 || signo >= _NSIG)
306 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
308 r = bus_verify_polkit_async(
311 "org.freedesktop.login1.manage",
315 &s->manager->polkit_registry,
320 return 1; /* Will call us back */
322 r = session_kill(s, who, signo);
326 return sd_bus_reply_method_return(message, NULL);
329 static int method_take_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
330 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
331 Session *s = userdata;
338 r = sd_bus_message_read(message, "b", &force);
342 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
346 r = sd_bus_creds_get_euid(creds, &uid);
350 if (uid != 0 && (force || uid != s->user->uid))
351 return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
353 r = session_set_controller(s, sd_bus_message_get_sender(message), force);
357 return sd_bus_reply_method_return(message, NULL);
360 static int method_release_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
361 Session *s = userdata;
366 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
367 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
369 session_drop_controller(s);
371 return sd_bus_reply_method_return(message, NULL);
374 static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
375 Session *s = userdata;
376 uint32_t major, minor;
384 r = sd_bus_message_read(message, "uu", &major, &minor);
388 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
389 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
391 dev = makedev(major, minor);
392 sd = hashmap_get(s->devices, &dev);
394 /* We don't allow retrieving a device multiple times.
395 * The related ReleaseDevice call is not ref-counted.
396 * The caller should use dup() if it requires more
397 * than one fd (it would be functionally
399 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
401 r = session_device_new(s, dev, &sd);
405 r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
407 session_device_free(sd);
412 static int method_release_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
413 Session *s = userdata;
414 uint32_t major, minor;
422 r = sd_bus_message_read(message, "uu", &major, &minor);
426 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
427 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
429 dev = makedev(major, minor);
430 sd = hashmap_get(s->devices, &dev);
432 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
434 session_device_free(sd);
435 return sd_bus_reply_method_return(message, NULL);
438 static int method_pause_device_complete(sd_bus_message *message, void *userdata, sd_bus_error *error) {
439 Session *s = userdata;
440 uint32_t major, minor;
448 r = sd_bus_message_read(message, "uu", &major, &minor);
452 if (!session_is_controller(s, sd_bus_message_get_sender(message)))
453 return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
455 dev = makedev(major, minor);
456 sd = hashmap_get(s->devices, &dev);
458 return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
460 session_device_complete_pause(sd);
462 return sd_bus_reply_method_return(message, NULL);
465 const sd_bus_vtable session_vtable[] = {
466 SD_BUS_VTABLE_START(0),
468 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
469 SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
470 SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
471 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
472 SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
473 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
474 SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
475 SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
476 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
477 SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
478 SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
479 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
480 SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
481 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
482 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
483 SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
484 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_CONST),
485 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
486 SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
487 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
488 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
489 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
490 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
492 SD_BUS_METHOD("Terminate", NULL, NULL, bus_session_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
493 SD_BUS_METHOD("Activate", NULL, NULL, bus_session_method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
494 SD_BUS_METHOD("Lock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
495 SD_BUS_METHOD("Unlock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
496 SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED),
497 SD_BUS_METHOD("Kill", "si", NULL, bus_session_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
498 SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED),
499 SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED),
500 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED),
501 SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, SD_BUS_VTABLE_UNPRIVILEGED),
502 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, SD_BUS_VTABLE_UNPRIVILEGED),
504 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
505 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
506 SD_BUS_SIGNAL("Lock", NULL, 0),
507 SD_BUS_SIGNAL("Unlock", NULL, 0),
512 int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
513 Manager *m = userdata;
523 if (streq(path, "/org/freedesktop/login1/session/self")) {
524 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
525 sd_bus_message *message;
528 message = sd_bus_get_current_message(bus);
532 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
536 r = sd_bus_creds_get_session(creds, &name);
540 session = hashmap_get(m->sessions, name);
542 _cleanup_free_ char *e = NULL;
545 p = startswith(path, "/org/freedesktop/login1/session/");
549 e = bus_label_unescape(p);
553 session = hashmap_get(m->sessions, e);
563 char *session_bus_path(Session *s) {
564 _cleanup_free_ char *t = NULL;
568 t = bus_label_escape(s->id);
572 return strappend("/org/freedesktop/login1/session/", t);
575 int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
576 _cleanup_strv_free_ char **l = NULL;
577 sd_bus_message *message;
578 Manager *m = userdata;
587 HASHMAP_FOREACH(session, m->sessions, i) {
590 p = session_bus_path(session);
594 r = strv_consume(&l, p);
599 message = sd_bus_get_current_message(bus);
601 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
604 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
606 r = sd_bus_creds_get_session(creds, &name);
608 session = hashmap_get(m->sessions, name);
610 r = strv_extend(&l, "/org/freedesktop/login1/session/self");
624 int session_send_signal(Session *s, bool new_session) {
625 _cleanup_free_ char *p = NULL;
629 p = session_bus_path(s);
633 return sd_bus_emit_signal(
635 "/org/freedesktop/login1",
636 "org.freedesktop.login1.Manager",
637 new_session ? "SessionNew" : "SessionRemoved",
641 int session_send_changed(Session *s, const char *properties, ...) {
642 _cleanup_free_ char *p = NULL;
650 p = session_bus_path(s);
654 l = strv_from_stdarg_alloca(properties);
656 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l);
659 int session_send_lock(Session *s, bool lock) {
660 _cleanup_free_ char *p = NULL;
664 p = session_bus_path(s);
668 return sd_bus_emit_signal(
671 "org.freedesktop.login1.Session",
672 lock ? "Lock" : "Unlock",
676 int session_send_lock_all(Manager *m, bool lock) {
683 HASHMAP_FOREACH(session, m->sessions, i) {
686 k = session_send_lock(session, lock);
694 int session_send_create_reply(Session *s, sd_bus_error *error) {
695 _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
696 _cleanup_close_ int fifo_fd = -1;
697 _cleanup_free_ char *p = NULL;
701 /* This is called after the session scope and the user service
702 * were successfully created, and finishes where
703 * bus_manager_create_session() left off. */
705 if (!s->create_message)
708 #if 0 /// 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 and user state files before we notify
724 * the client about the result. */
728 p = session_bus_path(s);
732 log_debug("Sending reply about created session: "
733 "id=%s object_path=%s uid=%u runtime_path=%s "
734 "session_fd=%d seat=%s vtnr=%u",
737 (uint32_t) s->user->uid,
738 s->user->runtime_path,
740 s->seat ? s->seat->id : "",
743 return sd_bus_reply_method_return(
747 s->user->runtime_path,
749 (uint32_t) s->user->uid,
750 s->seat ? s->seat->id : "",