1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "alloc-util.h"
25 #include "bus-common-errors.h"
26 #include "bus-label.h"
29 #include "logind-session-device.h"
30 #include "logind-session.h"
32 #include "signal-util.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 static int property_get_locked_hint(
187 const char *interface
,
188 const char *property
,
189 sd_bus_message
*reply
,
191 sd_bus_error
*error
) {
193 Session
*s
= userdata
;
199 return sd_bus_message_append(reply
, "b", session_get_locked_hint(s
) > 0);
202 int bus_session_method_terminate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
203 Session
*s
= userdata
;
209 r
= bus_verify_polkit_async(
212 "org.freedesktop.login1.manage",
216 &s
->manager
->polkit_registry
,
221 return 1; /* Will call us back */
223 r
= session_stop(s
, true);
227 return sd_bus_reply_method_return(message
, NULL
);
230 int bus_session_method_activate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
231 Session
*s
= userdata
;
237 r
= session_activate(s
);
241 return sd_bus_reply_method_return(message
, NULL
);
244 int bus_session_method_lock(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
245 Session
*s
= userdata
;
251 r
= bus_verify_polkit_async(
254 "org.freedesktop.login1.lock-sessions",
258 &s
->manager
->polkit_registry
,
263 return 1; /* Will call us back */
265 r
= session_send_lock(s
, strstr(sd_bus_message_get_member(message
), "Lock"));
269 return sd_bus_reply_method_return(message
, NULL
);
272 static int method_set_idle_hint(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
273 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
274 Session
*s
= userdata
;
281 r
= sd_bus_message_read(message
, "b", &b
);
285 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
289 r
= sd_bus_creds_get_euid(creds
, &uid
);
293 if (uid
!= 0 && uid
!= s
->user
->uid
)
294 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may set idle hint");
296 session_set_idle_hint(s
, b
);
298 return sd_bus_reply_method_return(message
, NULL
);
301 static int method_set_locked_hint(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
302 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
303 Session
*s
= userdata
;
310 r
= sd_bus_message_read(message
, "b", &b
);
314 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
318 r
= sd_bus_creds_get_euid(creds
, &uid
);
322 if (uid
!= 0 && uid
!= s
->user
->uid
)
323 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may set locked hint");
325 session_set_locked_hint(s
, b
);
327 return sd_bus_reply_method_return(message
, NULL
);
330 int bus_session_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
331 Session
*s
= userdata
;
340 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
347 who
= kill_who_from_string(swho
);
349 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid kill parameter '%s'", swho
);
352 if (!SIGNAL_VALID(signo
))
353 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid signal %i", signo
);
355 r
= bus_verify_polkit_async(
358 "org.freedesktop.login1.manage",
362 &s
->manager
->polkit_registry
,
367 return 1; /* Will call us back */
369 r
= session_kill(s
, who
, signo
);
373 return sd_bus_reply_method_return(message
, NULL
);
376 static int method_take_control(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
377 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
378 Session
*s
= userdata
;
385 r
= sd_bus_message_read(message
, "b", &force
);
389 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
393 r
= sd_bus_creds_get_euid(creds
, &uid
);
397 if (uid
!= 0 && (force
|| uid
!= s
->user
->uid
))
398 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may take control");
400 r
= session_set_controller(s
, sd_bus_message_get_sender(message
), force
, true);
404 return sd_bus_reply_method_return(message
, NULL
);
407 static int method_release_control(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
408 Session
*s
= userdata
;
413 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
414 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
416 session_drop_controller(s
);
418 return sd_bus_reply_method_return(message
, NULL
);
421 static int method_take_device(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
422 Session
*s
= userdata
;
423 uint32_t major
, minor
;
431 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
435 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
436 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
438 dev
= makedev(major
, minor
);
439 sd
= hashmap_get(s
->devices
, &dev
);
441 /* We don't allow retrieving a device multiple times.
442 * The related ReleaseDevice call is not ref-counted.
443 * The caller should use dup() if it requires more
444 * than one fd (it would be functionally
446 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_IS_TAKEN
, "Device already taken");
448 r
= session_device_new(s
, dev
, true, &sd
);
452 r
= session_device_save(sd
);
456 r
= sd_bus_reply_method_return(message
, "hb", sd
->fd
, !sd
->active
);
464 session_device_free(sd
);
468 static int method_release_device(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
469 Session
*s
= userdata
;
470 uint32_t major
, minor
;
478 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
482 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
483 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
485 dev
= makedev(major
, minor
);
486 sd
= hashmap_get(s
->devices
, &dev
);
488 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_NOT_TAKEN
, "Device not taken");
490 session_device_free(sd
);
493 return sd_bus_reply_method_return(message
, NULL
);
496 static int method_pause_device_complete(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
497 Session
*s
= userdata
;
498 uint32_t major
, minor
;
506 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
510 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
511 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
513 dev
= makedev(major
, minor
);
514 sd
= hashmap_get(s
->devices
, &dev
);
516 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_NOT_TAKEN
, "Device not taken");
518 session_device_complete_pause(sd
);
520 return sd_bus_reply_method_return(message
, NULL
);
523 const sd_bus_vtable session_vtable
[] = {
524 SD_BUS_VTABLE_START(0),
526 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Session
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
527 SD_BUS_PROPERTY("User", "(uo)", property_get_user
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
528 SD_BUS_PROPERTY("Name", "s", property_get_name
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
529 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session
, timestamp
), SD_BUS_VTABLE_PROPERTY_CONST
),
530 SD_BUS_PROPERTY("VTNr", "u", NULL
, offsetof(Session
, vtnr
), SD_BUS_VTABLE_PROPERTY_CONST
),
531 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
532 SD_BUS_PROPERTY("TTY", "s", NULL
, offsetof(Session
, tty
), SD_BUS_VTABLE_PROPERTY_CONST
),
533 SD_BUS_PROPERTY("Display", "s", NULL
, offsetof(Session
, display
), SD_BUS_VTABLE_PROPERTY_CONST
),
534 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool
, offsetof(Session
, remote
), SD_BUS_VTABLE_PROPERTY_CONST
),
535 SD_BUS_PROPERTY("RemoteHost", "s", NULL
, offsetof(Session
, remote_host
), SD_BUS_VTABLE_PROPERTY_CONST
),
536 SD_BUS_PROPERTY("RemoteUser", "s", NULL
, offsetof(Session
, remote_user
), SD_BUS_VTABLE_PROPERTY_CONST
),
537 SD_BUS_PROPERTY("Service", "s", NULL
, offsetof(Session
, service
), SD_BUS_VTABLE_PROPERTY_CONST
),
538 SD_BUS_PROPERTY("Desktop", "s", NULL
, offsetof(Session
, desktop
), SD_BUS_VTABLE_PROPERTY_CONST
),
539 SD_BUS_PROPERTY("Scope", "s", NULL
, offsetof(Session
, scope
), SD_BUS_VTABLE_PROPERTY_CONST
),
540 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid
, offsetof(Session
, leader
), SD_BUS_VTABLE_PROPERTY_CONST
),
541 SD_BUS_PROPERTY("Audit", "u", NULL
, offsetof(Session
, audit_id
), SD_BUS_VTABLE_PROPERTY_CONST
),
542 SD_BUS_PROPERTY("Type", "s", property_get_type
, offsetof(Session
, type
), SD_BUS_VTABLE_PROPERTY_CONST
),
543 SD_BUS_PROPERTY("Class", "s", property_get_class
, offsetof(Session
, class), SD_BUS_VTABLE_PROPERTY_CONST
),
544 SD_BUS_PROPERTY("Active", "b", property_get_active
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
545 SD_BUS_PROPERTY("State", "s", property_get_state
, 0, 0),
546 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
547 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
548 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
549 SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
551 SD_BUS_METHOD("Terminate", NULL
, NULL
, bus_session_method_terminate
, SD_BUS_VTABLE_UNPRIVILEGED
),
552 SD_BUS_METHOD("Activate", NULL
, NULL
, bus_session_method_activate
, SD_BUS_VTABLE_UNPRIVILEGED
),
553 SD_BUS_METHOD("Lock", NULL
, NULL
, bus_session_method_lock
, SD_BUS_VTABLE_UNPRIVILEGED
),
554 SD_BUS_METHOD("Unlock", NULL
, NULL
, bus_session_method_lock
, SD_BUS_VTABLE_UNPRIVILEGED
),
555 SD_BUS_METHOD("SetIdleHint", "b", NULL
, method_set_idle_hint
, SD_BUS_VTABLE_UNPRIVILEGED
),
556 SD_BUS_METHOD("SetLockedHint", "b", NULL
, method_set_locked_hint
, SD_BUS_VTABLE_UNPRIVILEGED
),
557 SD_BUS_METHOD("Kill", "si", NULL
, bus_session_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
558 SD_BUS_METHOD("TakeControl", "b", NULL
, method_take_control
, SD_BUS_VTABLE_UNPRIVILEGED
),
559 SD_BUS_METHOD("ReleaseControl", NULL
, NULL
, method_release_control
, SD_BUS_VTABLE_UNPRIVILEGED
),
560 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device
, SD_BUS_VTABLE_UNPRIVILEGED
),
561 SD_BUS_METHOD("ReleaseDevice", "uu", NULL
, method_release_device
, SD_BUS_VTABLE_UNPRIVILEGED
),
562 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL
, method_pause_device_complete
, SD_BUS_VTABLE_UNPRIVILEGED
),
564 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
565 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
566 SD_BUS_SIGNAL("Lock", NULL
, 0),
567 SD_BUS_SIGNAL("Unlock", NULL
, 0),
572 int session_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
573 Manager
*m
= userdata
;
583 if (streq(path
, "/org/freedesktop/login1/session/self")) {
584 sd_bus_message
*message
;
586 message
= sd_bus_get_current_message(bus
);
590 r
= manager_get_session_from_creds(m
, message
, NULL
, error
, &session
);
594 _cleanup_free_
char *e
= NULL
;
597 p
= startswith(path
, "/org/freedesktop/login1/session/");
601 e
= bus_label_unescape(p
);
605 session
= hashmap_get(m
->sessions
, e
);
614 char *session_bus_path(Session
*s
) {
615 _cleanup_free_
char *t
= NULL
;
619 t
= bus_label_escape(s
->id
);
623 return strappend("/org/freedesktop/login1/session/", t
);
626 int session_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
627 _cleanup_strv_free_
char **l
= NULL
;
628 sd_bus_message
*message
;
629 Manager
*m
= userdata
;
638 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
641 p
= session_bus_path(session
);
645 r
= strv_consume(&l
, p
);
650 message
= sd_bus_get_current_message(bus
);
652 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
655 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_SESSION
|SD_BUS_CREDS_AUGMENT
, &creds
);
657 r
= sd_bus_creds_get_session(creds
, &name
);
659 session
= hashmap_get(m
->sessions
, name
);
661 r
= strv_extend(&l
, "/org/freedesktop/login1/session/self");
675 int session_send_signal(Session
*s
, bool new_session
) {
676 _cleanup_free_
char *p
= NULL
;
680 p
= session_bus_path(s
);
684 return sd_bus_emit_signal(
686 "/org/freedesktop/login1",
687 "org.freedesktop.login1.Manager",
688 new_session
? "SessionNew" : "SessionRemoved",
692 int session_send_changed(Session
*s
, const char *properties
, ...) {
693 _cleanup_free_
char *p
= NULL
;
701 p
= session_bus_path(s
);
705 l
= strv_from_stdarg_alloca(properties
);
707 return sd_bus_emit_properties_changed_strv(s
->manager
->bus
, p
, "org.freedesktop.login1.Session", l
);
710 int session_send_lock(Session
*s
, bool lock
) {
711 _cleanup_free_
char *p
= NULL
;
715 p
= session_bus_path(s
);
719 return sd_bus_emit_signal(
722 "org.freedesktop.login1.Session",
723 lock
? "Lock" : "Unlock",
727 int session_send_lock_all(Manager
*m
, bool lock
) {
734 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
737 k
= session_send_lock(session
, lock
);
745 int session_send_create_reply(Session
*s
, sd_bus_error
*error
) {
746 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*c
= NULL
;
747 _cleanup_close_
int fifo_fd
= -1;
748 _cleanup_free_
char *p
= NULL
;
752 /* This is called after the session scope and the user service
753 * were successfully created, and finishes where
754 * bus_manager_create_session() left off. */
756 if (!s
->create_message
)
759 if (!sd_bus_error_is_set(error
) && (s
->scope_job
|| s
->user
->service_job
))
762 c
= s
->create_message
;
763 s
->create_message
= NULL
;
766 return sd_bus_reply_method_error(c
, error
);
768 fifo_fd
= session_create_fifo(s
);
772 /* Update the session state file before we notify the client
773 * about the result. */
776 p
= session_bus_path(s
);
780 log_debug("Sending reply about created session: "
781 "id=%s object_path=%s uid=%u runtime_path=%s "
782 "session_fd=%d seat=%s vtnr=%u",
785 (uint32_t) s
->user
->uid
,
786 s
->user
->runtime_path
,
788 s
->seat
? s
->seat
->id
: "",
791 return sd_bus_reply_method_return(
795 s
->user
->runtime_path
,
797 (uint32_t) s
->user
->uid
,
798 s
->seat
? s
->seat
->id
: "",