1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #include "alloc-util.h"
7 #include "bus-common-errors.h"
11 #include "logind-session-device.h"
12 #include "logind-session.h"
14 #include "missing_capability.h"
15 #include "signal-util.h"
16 #include "stat-util.h"
20 static int property_get_user(
23 const char *interface
,
25 sd_bus_message
*reply
,
27 sd_bus_error
*error
) {
29 _cleanup_free_
char *p
= NULL
;
30 Session
*s
= userdata
;
36 p
= user_bus_path(s
->user
);
40 return sd_bus_message_append(reply
, "(uo)", (uint32_t) s
->user
->uid
, p
);
43 static int property_get_name(
46 const char *interface
,
48 sd_bus_message
*reply
,
50 sd_bus_error
*error
) {
52 Session
*s
= userdata
;
58 return sd_bus_message_append(reply
, "s", s
->user
->name
);
61 static int property_get_seat(
64 const char *interface
,
66 sd_bus_message
*reply
,
68 sd_bus_error
*error
) {
70 _cleanup_free_
char *p
= NULL
;
71 Session
*s
= userdata
;
77 p
= s
->seat
? seat_bus_path(s
->seat
) : strdup("/");
81 return sd_bus_message_append(reply
, "(so)", s
->seat
? s
->seat
->id
: "", p
);
84 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type
, session_type
, SessionType
);
85 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class
, session_class
, SessionClass
);
86 static BUS_DEFINE_PROPERTY_GET(property_get_active
, "b", Session
, session_is_active
);
87 static BUS_DEFINE_PROPERTY_GET2(property_get_state
, "s", Session
, session_get_state
, session_state_to_string
);
89 static int property_get_idle_hint(
92 const char *interface
,
94 sd_bus_message
*reply
,
96 sd_bus_error
*error
) {
98 Session
*s
= userdata
;
104 return sd_bus_message_append(reply
, "b", session_get_idle_hint(s
, NULL
) > 0);
107 static int property_get_idle_since_hint(
110 const char *interface
,
111 const char *property
,
112 sd_bus_message
*reply
,
114 sd_bus_error
*error
) {
116 Session
*s
= userdata
;
117 dual_timestamp t
= DUAL_TIMESTAMP_NULL
;
125 r
= session_get_idle_hint(s
, &t
);
129 u
= streq(property
, "IdleSinceHint") ? t
.realtime
: t
.monotonic
;
131 return sd_bus_message_append(reply
, "t", u
);
134 static int property_get_locked_hint(
137 const char *interface
,
138 const char *property
,
139 sd_bus_message
*reply
,
141 sd_bus_error
*error
) {
143 Session
*s
= userdata
;
149 return sd_bus_message_append(reply
, "b", session_get_locked_hint(s
) > 0);
152 int bus_session_method_terminate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
153 Session
*s
= userdata
;
159 r
= bus_verify_polkit_async(
162 "org.freedesktop.login1.manage",
166 &s
->manager
->polkit_registry
,
171 return 1; /* Will call us back */
173 r
= session_stop(s
, true);
177 return sd_bus_reply_method_return(message
, NULL
);
180 int bus_session_method_activate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
181 Session
*s
= userdata
;
187 r
= session_activate(s
);
191 return sd_bus_reply_method_return(message
, NULL
);
194 int bus_session_method_lock(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
195 Session
*s
= userdata
;
201 r
= bus_verify_polkit_async(
204 "org.freedesktop.login1.lock-sessions",
208 &s
->manager
->polkit_registry
,
213 return 1; /* Will call us back */
215 r
= session_send_lock(s
, strstr(sd_bus_message_get_member(message
), "Lock"));
219 return sd_bus_reply_method_return(message
, NULL
);
222 static int method_set_idle_hint(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
223 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
224 Session
*s
= userdata
;
231 r
= sd_bus_message_read(message
, "b", &b
);
235 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
239 r
= sd_bus_creds_get_euid(creds
, &uid
);
243 if (uid
!= 0 && uid
!= s
->user
->uid
)
244 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may set idle hint");
246 session_set_idle_hint(s
, b
);
248 return sd_bus_reply_method_return(message
, NULL
);
251 static int method_set_locked_hint(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
252 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
253 Session
*s
= userdata
;
260 r
= sd_bus_message_read(message
, "b", &b
);
264 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
268 r
= sd_bus_creds_get_euid(creds
, &uid
);
272 if (uid
!= 0 && uid
!= s
->user
->uid
)
273 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may set locked hint");
275 session_set_locked_hint(s
, b
);
277 return sd_bus_reply_method_return(message
, NULL
);
280 int bus_session_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
281 Session
*s
= userdata
;
290 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
297 who
= kill_who_from_string(swho
);
299 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid kill parameter '%s'", swho
);
302 if (!SIGNAL_VALID(signo
))
303 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid signal %i", signo
);
305 r
= bus_verify_polkit_async(
308 "org.freedesktop.login1.manage",
312 &s
->manager
->polkit_registry
,
317 return 1; /* Will call us back */
319 r
= session_kill(s
, who
, signo
);
323 return sd_bus_reply_method_return(message
, NULL
);
326 static int method_take_control(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
327 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
328 Session
*s
= userdata
;
335 r
= sd_bus_message_read(message
, "b", &force
);
339 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_EUID
, &creds
);
343 r
= sd_bus_creds_get_euid(creds
, &uid
);
347 if (uid
!= 0 && (force
|| uid
!= s
->user
->uid
))
348 return sd_bus_error_setf(error
, SD_BUS_ERROR_ACCESS_DENIED
, "Only owner of session may take control");
350 r
= session_set_controller(s
, sd_bus_message_get_sender(message
), force
, true);
354 return sd_bus_reply_method_return(message
, NULL
);
357 static int method_release_control(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
358 Session
*s
= userdata
;
363 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
364 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
366 session_drop_controller(s
);
368 return sd_bus_reply_method_return(message
, NULL
);
371 static int method_take_device(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
372 Session
*s
= userdata
;
373 uint32_t major
, minor
;
381 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
385 if (!DEVICE_MAJOR_VALID(major
) || !DEVICE_MINOR_VALID(minor
))
386 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Device major/minor is not valid.");
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
, true, &sd
);
405 r
= session_device_save(sd
);
409 r
= sd_bus_reply_method_return(message
, "hb", sd
->fd
, !sd
->active
);
417 session_device_free(sd
);
421 static int method_release_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 (!DEVICE_MAJOR_VALID(major
) || !DEVICE_MINOR_VALID(minor
))
436 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Device major/minor is not valid.");
438 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
439 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
441 dev
= makedev(major
, minor
);
442 sd
= hashmap_get(s
->devices
, &dev
);
444 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_NOT_TAKEN
, "Device not taken");
446 session_device_free(sd
);
449 return sd_bus_reply_method_return(message
, NULL
);
452 static int method_pause_device_complete(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
453 Session
*s
= userdata
;
454 uint32_t major
, minor
;
462 r
= sd_bus_message_read(message
, "uu", &major
, &minor
);
466 if (!DEVICE_MAJOR_VALID(major
) || !DEVICE_MINOR_VALID(minor
))
467 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Device major/minor is not valid.");
469 if (!session_is_controller(s
, sd_bus_message_get_sender(message
)))
470 return sd_bus_error_setf(error
, BUS_ERROR_NOT_IN_CONTROL
, "You are not in control of this session");
472 dev
= makedev(major
, minor
);
473 sd
= hashmap_get(s
->devices
, &dev
);
475 return sd_bus_error_setf(error
, BUS_ERROR_DEVICE_NOT_TAKEN
, "Device not taken");
477 session_device_complete_pause(sd
);
479 return sd_bus_reply_method_return(message
, NULL
);
482 const sd_bus_vtable session_vtable
[] = {
483 SD_BUS_VTABLE_START(0),
485 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Session
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
486 SD_BUS_PROPERTY("User", "(uo)", property_get_user
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
487 SD_BUS_PROPERTY("Name", "s", property_get_name
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
488 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session
, timestamp
), SD_BUS_VTABLE_PROPERTY_CONST
),
489 SD_BUS_PROPERTY("VTNr", "u", NULL
, offsetof(Session
, vtnr
), SD_BUS_VTABLE_PROPERTY_CONST
),
490 SD_BUS_PROPERTY("Seat", "(so)", property_get_seat
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
491 SD_BUS_PROPERTY("TTY", "s", NULL
, offsetof(Session
, tty
), SD_BUS_VTABLE_PROPERTY_CONST
),
492 SD_BUS_PROPERTY("Display", "s", NULL
, offsetof(Session
, display
), SD_BUS_VTABLE_PROPERTY_CONST
),
493 SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool
, offsetof(Session
, remote
), SD_BUS_VTABLE_PROPERTY_CONST
),
494 SD_BUS_PROPERTY("RemoteHost", "s", NULL
, offsetof(Session
, remote_host
), SD_BUS_VTABLE_PROPERTY_CONST
),
495 SD_BUS_PROPERTY("RemoteUser", "s", NULL
, offsetof(Session
, remote_user
), SD_BUS_VTABLE_PROPERTY_CONST
),
496 SD_BUS_PROPERTY("Service", "s", NULL
, offsetof(Session
, service
), SD_BUS_VTABLE_PROPERTY_CONST
),
497 SD_BUS_PROPERTY("Desktop", "s", NULL
, offsetof(Session
, desktop
), SD_BUS_VTABLE_PROPERTY_CONST
),
498 SD_BUS_PROPERTY("Scope", "s", NULL
, offsetof(Session
, scope
), SD_BUS_VTABLE_PROPERTY_CONST
),
499 SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid
, offsetof(Session
, leader
), SD_BUS_VTABLE_PROPERTY_CONST
),
500 SD_BUS_PROPERTY("Audit", "u", NULL
, offsetof(Session
, audit_id
), SD_BUS_VTABLE_PROPERTY_CONST
),
501 SD_BUS_PROPERTY("Type", "s", property_get_type
, offsetof(Session
, type
), SD_BUS_VTABLE_PROPERTY_CONST
),
502 SD_BUS_PROPERTY("Class", "s", property_get_class
, offsetof(Session
, class), SD_BUS_VTABLE_PROPERTY_CONST
),
503 SD_BUS_PROPERTY("Active", "b", property_get_active
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
504 SD_BUS_PROPERTY("State", "s", property_get_state
, 0, 0),
505 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
506 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
507 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
508 SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
510 SD_BUS_METHOD("Terminate", NULL
, NULL
, bus_session_method_terminate
, SD_BUS_VTABLE_UNPRIVILEGED
),
511 SD_BUS_METHOD("Activate", NULL
, NULL
, bus_session_method_activate
, SD_BUS_VTABLE_UNPRIVILEGED
),
512 SD_BUS_METHOD("Lock", NULL
, NULL
, bus_session_method_lock
, SD_BUS_VTABLE_UNPRIVILEGED
),
513 SD_BUS_METHOD("Unlock", NULL
, NULL
, bus_session_method_lock
, SD_BUS_VTABLE_UNPRIVILEGED
),
514 SD_BUS_METHOD("SetIdleHint", "b", NULL
, method_set_idle_hint
, SD_BUS_VTABLE_UNPRIVILEGED
),
515 SD_BUS_METHOD("SetLockedHint", "b", NULL
, method_set_locked_hint
, SD_BUS_VTABLE_UNPRIVILEGED
),
516 SD_BUS_METHOD("Kill", "si", NULL
, bus_session_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
517 SD_BUS_METHOD("TakeControl", "b", NULL
, method_take_control
, SD_BUS_VTABLE_UNPRIVILEGED
),
518 SD_BUS_METHOD("ReleaseControl", NULL
, NULL
, method_release_control
, SD_BUS_VTABLE_UNPRIVILEGED
),
519 SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device
, SD_BUS_VTABLE_UNPRIVILEGED
),
520 SD_BUS_METHOD("ReleaseDevice", "uu", NULL
, method_release_device
, SD_BUS_VTABLE_UNPRIVILEGED
),
521 SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL
, method_pause_device_complete
, SD_BUS_VTABLE_UNPRIVILEGED
),
523 SD_BUS_SIGNAL("PauseDevice", "uus", 0),
524 SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
525 SD_BUS_SIGNAL("Lock", NULL
, 0),
526 SD_BUS_SIGNAL("Unlock", NULL
, 0),
531 int session_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
532 Manager
*m
= userdata
;
542 if (streq(path
, "/org/freedesktop/login1/session/self")) {
543 sd_bus_message
*message
;
545 message
= sd_bus_get_current_message(bus
);
549 r
= manager_get_session_from_creds(m
, message
, NULL
, error
, &session
);
553 _cleanup_free_
char *e
= NULL
;
556 p
= startswith(path
, "/org/freedesktop/login1/session/");
560 e
= bus_label_unescape(p
);
564 session
= hashmap_get(m
->sessions
, e
);
573 char *session_bus_path(Session
*s
) {
574 _cleanup_free_
char *t
= NULL
;
578 t
= bus_label_escape(s
->id
);
582 return strappend("/org/freedesktop/login1/session/", t
);
585 int session_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
586 _cleanup_strv_free_
char **l
= NULL
;
587 sd_bus_message
*message
;
588 Manager
*m
= userdata
;
597 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
600 p
= session_bus_path(session
);
604 r
= strv_consume(&l
, p
);
609 message
= sd_bus_get_current_message(bus
);
611 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
614 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_SESSION
|SD_BUS_CREDS_AUGMENT
, &creds
);
616 r
= sd_bus_creds_get_session(creds
, &name
);
618 session
= hashmap_get(m
->sessions
, name
);
620 r
= strv_extend(&l
, "/org/freedesktop/login1/session/self");
628 *nodes
= TAKE_PTR(l
);
633 int session_send_signal(Session
*s
, bool new_session
) {
634 _cleanup_free_
char *p
= NULL
;
638 p
= session_bus_path(s
);
642 return sd_bus_emit_signal(
644 "/org/freedesktop/login1",
645 "org.freedesktop.login1.Manager",
646 new_session
? "SessionNew" : "SessionRemoved",
650 int session_send_changed(Session
*s
, const char *properties
, ...) {
651 _cleanup_free_
char *p
= NULL
;
659 p
= session_bus_path(s
);
663 l
= strv_from_stdarg_alloca(properties
);
665 return sd_bus_emit_properties_changed_strv(s
->manager
->bus
, p
, "org.freedesktop.login1.Session", l
);
668 int session_send_lock(Session
*s
, bool lock
) {
669 _cleanup_free_
char *p
= NULL
;
673 p
= session_bus_path(s
);
677 return sd_bus_emit_signal(
680 "org.freedesktop.login1.Session",
681 lock
? "Lock" : "Unlock",
685 int session_send_lock_all(Manager
*m
, bool lock
) {
692 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
695 k
= session_send_lock(session
, lock
);
703 static bool session_ready(Session
*s
) {
706 /* Returns true when the session is ready, i.e. all jobs we enqueued for it are done (regardless if successful or not) */
708 return !s
->scope_job
&&
709 !s
->user
->service_job
;
712 int session_send_create_reply(Session
*s
, sd_bus_error
*error
) {
713 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*c
= NULL
;
714 _cleanup_close_
int fifo_fd
= -1;
715 _cleanup_free_
char *p
= NULL
;
719 /* This is called after the session scope and the user service were successfully created, and finishes where
720 * bus_manager_create_session() left off. */
722 if (!s
->create_message
)
725 if (!sd_bus_error_is_set(error
) && !session_ready(s
))
728 c
= TAKE_PTR(s
->create_message
);
730 return sd_bus_reply_method_error(c
, error
);
732 fifo_fd
= session_create_fifo(s
);
736 /* Update the session state file before we notify the client about the result. */
739 p
= session_bus_path(s
);
743 log_debug("Sending reply about created session: "
744 "id=%s object_path=%s uid=%u runtime_path=%s "
745 "session_fd=%d seat=%s vtnr=%u",
748 (uint32_t) s
->user
->uid
,
749 s
->user
->runtime_path
,
751 s
->seat
? s
->seat
->id
: "",
754 return sd_bus_reply_method_return(
758 s
->user
->runtime_path
,
760 (uint32_t) s
->user
->uid
,
761 s
->seat
? s
->seat
->id
: "",