2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2012-07-18 19:07:51 +02:00
|
|
|
#pragma once
|
2011-05-24 00:19:22 +02:00
|
|
|
|
|
|
|
typedef struct Session Session;
|
2013-06-20 03:45:08 +02:00
|
|
|
typedef enum KillWho KillWho;
|
2011-05-24 00:19:22 +02:00
|
|
|
|
|
|
|
#include "list.h"
|
2015-06-09 14:27:33 +02:00
|
|
|
#include "login-util.h"
|
2015-11-18 22:46:33 +01:00
|
|
|
#include "logind-user.h"
|
logind: make "self" and "auto" magic strings when operating on seats + sessions
Most of the operations one can do on sessions so far accepted an empty
session name as a shortcut for the caller's session. This is quite
useful traditionally, but much less useful than it used to be, since
most user code now (rightfully) runs in --user context, not in a
session.
With this change we tweak the logic a bit: we introduce the two special
session and seat names "self" and "auto". The former refers to the
session/seat the client is in, and is hence mostly equivalent to te
empty string "" as before. However, the latter refers to the
session/seat the client is in if that exists, with a fallback of the
user's display session if not. Clients can hence reference "auto"
instead of the empty string if they really don't want to think much
about sessions.
Why "self" btw? Previously, we'd already expose a special dbus object
with the path /org/freedesktop/login1/session/self (and similar for the
seat), matching what the empty string did for bus calls that took a
session name. With this scheme we reuse this identifier and introduce
"auto" in a similar way.
Of course this means real-life seats and sessions can never be named
"self" or "auto", but they aren't anyway: valid seat names have to start
with "seat" anyway, and sessions are generated server-side as either a
numeric value or "c" suffixed with a counter ID.
Fixes: #12399
2019-04-28 17:55:36 +02:00
|
|
|
#include "string-util.h"
|
2011-05-24 00:19:22 +02:00
|
|
|
|
2012-06-21 16:14:53 +02:00
|
|
|
typedef enum SessionState {
|
2013-07-02 01:46:30 +02:00
|
|
|
SESSION_OPENING, /* Session scope is being created */
|
2012-06-21 16:14:53 +02:00
|
|
|
SESSION_ONLINE, /* Logged in */
|
|
|
|
SESSION_ACTIVE, /* Logged in and in the fg */
|
2013-07-02 01:46:30 +02:00
|
|
|
SESSION_CLOSING, /* Logged out, but scope is still there */
|
2012-06-21 16:14:53 +02:00
|
|
|
_SESSION_STATE_MAX,
|
|
|
|
_SESSION_STATE_INVALID = -1
|
|
|
|
} SessionState;
|
|
|
|
|
2012-02-14 21:33:51 +01:00
|
|
|
typedef enum SessionClass {
|
|
|
|
SESSION_USER,
|
|
|
|
SESSION_GREETER,
|
|
|
|
SESSION_LOCK_SCREEN,
|
2013-04-09 22:18:16 +02:00
|
|
|
SESSION_BACKGROUND,
|
2012-02-14 21:33:51 +01:00
|
|
|
_SESSION_CLASS_MAX,
|
|
|
|
_SESSION_CLASS_INVALID = -1
|
|
|
|
} SessionClass;
|
|
|
|
|
2013-04-09 22:18:16 +02:00
|
|
|
typedef enum SessionType {
|
|
|
|
SESSION_UNSPECIFIED,
|
|
|
|
SESSION_TTY,
|
|
|
|
SESSION_X11,
|
2014-02-05 18:27:43 +01:00
|
|
|
SESSION_WAYLAND,
|
2014-04-09 21:22:48 +02:00
|
|
|
SESSION_MIR,
|
2014-08-14 02:59:02 +02:00
|
|
|
SESSION_WEB,
|
2013-04-09 22:18:16 +02:00
|
|
|
_SESSION_TYPE_MAX,
|
|
|
|
_SESSION_TYPE_INVALID = -1
|
|
|
|
} SessionType;
|
|
|
|
|
2014-05-19 02:03:20 +02:00
|
|
|
#define SESSION_TYPE_IS_GRAPHICAL(type) IN_SET(type, SESSION_X11, SESSION_WAYLAND, SESSION_MIR)
|
|
|
|
|
2013-06-20 03:45:08 +02:00
|
|
|
enum KillWho {
|
2011-07-13 19:58:35 +02:00
|
|
|
KILL_LEADER,
|
|
|
|
KILL_ALL,
|
|
|
|
_KILL_WHO_MAX,
|
|
|
|
_KILL_WHO_INVALID = -1
|
2013-06-20 03:45:08 +02:00
|
|
|
};
|
2011-07-13 19:58:35 +02:00
|
|
|
|
2018-08-07 13:49:34 +02:00
|
|
|
typedef enum TTYValidity {
|
|
|
|
TTY_FROM_PAM,
|
|
|
|
TTY_FROM_UTMP,
|
|
|
|
TTY_UTMP_INCONSISTENT, /* may happen on ssh sessions with multiplexed TTYs */
|
|
|
|
_TTY_VALIDITY_MAX,
|
|
|
|
_TTY_VALIDITY_INVALID = -1,
|
|
|
|
} TTYValidity;
|
|
|
|
|
2011-05-24 00:19:22 +02:00
|
|
|
struct Session {
|
|
|
|
Manager *manager;
|
|
|
|
|
2014-07-18 20:01:13 +02:00
|
|
|
const char *id;
|
2018-10-19 20:00:46 +02:00
|
|
|
unsigned position;
|
2011-05-24 00:19:22 +02:00
|
|
|
SessionType type;
|
2020-02-23 04:44:42 +01:00
|
|
|
SessionType original_type;
|
2012-02-14 21:33:51 +01:00
|
|
|
SessionClass class;
|
2011-05-24 00:19:22 +02:00
|
|
|
|
|
|
|
char *state_file;
|
|
|
|
|
|
|
|
User *user;
|
|
|
|
|
|
|
|
dual_timestamp timestamp;
|
|
|
|
|
|
|
|
char *display;
|
2018-08-07 13:49:34 +02:00
|
|
|
char *tty;
|
|
|
|
TTYValidity tty_validity;
|
2011-05-24 00:19:22 +02:00
|
|
|
|
|
|
|
bool remote;
|
2011-05-26 02:21:16 +02:00
|
|
|
char *remote_user;
|
2011-05-24 00:19:22 +02:00
|
|
|
char *remote_host;
|
2011-06-24 18:50:50 +02:00
|
|
|
char *service;
|
2014-02-05 20:34:11 +01:00
|
|
|
char *desktop;
|
2013-07-02 01:46:30 +02:00
|
|
|
|
|
|
|
char *scope;
|
|
|
|
char *scope_job;
|
2011-06-24 18:50:50 +02:00
|
|
|
|
2011-05-24 00:19:22 +02:00
|
|
|
Seat *seat;
|
2018-10-19 20:00:46 +02:00
|
|
|
unsigned vtnr;
|
2013-11-28 15:10:24 +01:00
|
|
|
int vtfd;
|
2011-05-24 00:19:22 +02:00
|
|
|
|
|
|
|
pid_t leader;
|
2011-05-26 02:21:16 +02:00
|
|
|
uint32_t audit_id;
|
2011-05-24 00:19:22 +02:00
|
|
|
|
2011-06-29 00:06:04 +02:00
|
|
|
int fifo_fd;
|
|
|
|
char *fifo_path;
|
2011-05-24 00:19:22 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
sd_event_source *fifo_event_source;
|
|
|
|
|
2011-06-17 15:59:18 +02:00
|
|
|
bool idle_hint;
|
|
|
|
dual_timestamp idle_hint_timestamp;
|
|
|
|
|
2016-05-11 19:34:13 +02:00
|
|
|
bool locked_hint;
|
|
|
|
|
2011-05-25 00:55:58 +02:00
|
|
|
bool in_gc_queue:1;
|
2011-06-21 21:46:13 +02:00
|
|
|
bool started:1;
|
2014-02-06 18:32:14 +01:00
|
|
|
bool stopping:1;
|
2011-05-24 00:19:22 +02:00
|
|
|
|
2017-03-16 11:17:09 +01:00
|
|
|
bool was_active:1;
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
sd_bus_message *create_message;
|
2013-07-02 01:46:30 +02:00
|
|
|
|
2018-08-07 10:40:50 +02:00
|
|
|
/* Set up when a client requested to release the session via the bus */
|
2014-02-06 18:32:14 +01:00
|
|
|
sd_event_source *timer_event_source;
|
|
|
|
|
2013-09-17 17:39:56 +02:00
|
|
|
char *controller;
|
logind: introduce session-devices
A session-device is a device that is bound to a seat and used by a
session-controller to run the session. This currently includes DRM, fbdev
and evdev devices. A session-device can be created via RequestDevice() on
the dbus API of the session. You can drop it via ReleaseDevice() again.
Once the session is destroyed or you drop control of the session, all
session-devices are automatically destroyed.
Session devices follow the session "active" state. A device can be
active/running or inactive/paused. Whenever a session is not the active
session, no session-device of it can be active. That is, if a session is
not in foreground, all session-devices are paused.
Whenever a session becomes active, all devices are resumed/activated by
logind. If it fails, a device may stay paused.
With every session-device you request, you also get a file-descriptor
back. logind keeps a copy of this fd and uses kernel specific calls to
pause/resume the file-descriptors. For example, a DRM fd is muted
by logind as long as a given session is not active. Hence, the fd of the
application is also muted. Once the session gets active, logind unmutes
the fd and the application will get DRM access again.
This, however, requires kernel support. DRM devices provide DRM-Master for
synchronization, evdev devices have EVIOCREVOKE (pending on
linux-input-ML). fbdev devices do not provide such synchronization methods
(and never will).
Note that for evdev devices, we call EVIOCREVOKE once a session gets
inactive. However, this cannot be undone (the fd is still valid but mostly
unusable). So we reopen a new fd once the session is activated and send it
together with the ResumeDevice() signal.
With this infrastructure in place, compositors can now run without
CAP_SYS_ADMIN (that is, without being root). They use RequestControl() to
acquire a session and listen for devices via udev_monitor. For every
device they want to open, they call RequestDevice() on logind. This
returns a fd which they can use now. They no longer have to open the
devices themselves or call any privileged ioctls. This is all done by
logind.
Session-switches are still bound to VTs. Hence, compositors will get
notified via the usual VT mechanisms and can cleanup their state. Once the
VT switch is acknowledged as usual, logind will get notified via sysfs and
pause the old-session's devices and resume the devices of the new session.
To allow using this infrastructure with systems without VTs, we provide
notification signals. logind sends PauseDevice("force") dbus signals to
the current session controller for every device that it pauses. And it
sends ResumeDevice signals for every device that it resumes. For
seats with VTs this is sent _after_ the VT switch is acknowledged. Because
the compositor already acknowledged that it cleaned-up all devices.
However, for seats without VTs, this is used to notify the active
compositor that the session is about to be deactivated. That is, logind
sends PauseDevice("force") for each active device and then performs the
session-switch. The session-switch changes the "Active" property of the
session which can be monitored by the compositor. The new session is
activated and the ResumeDevice events are sent.
For seats without VTs, this is a forced session-switch. As this is not
backwards-compatible (xserver actually crashes, weston drops the related
devices, ..) we also provide an acknowledged session-switch. Note that
this is never used for sessions with VTs. You use the acknowledged
VT-switch on these seats.
An acknowledged session switch sends PauseDevice("pause") instead of
PauseDevice("force") to the active session. It schedules a short timeout
and waits for the session to acknowledge each of them with
PauseDeviceComplete(). Once all are acknowledged, or the session ran out
of time, a PauseDevice("force") is sent for all remaining active devices
and the session switch is performed.
Note that this is only partially implemented, yet, as we don't allow
multi-session without VTs, yet. A follow up commit will hook it up and
implemented the acknowledgements+timeout.
The implementation is quite simple. We use major/minor exclusively to
identify devices on the bus. On RequestDevice() we retrieve the
udev_device from the major/minor and search for an existing "Device"
object. If no exists, we create it. This guarantees us that we are
notified whenever the device changes seats or is removed.
We create a new SessionDevice object and link it to the related Session
and Device. Session->devices is a hashtable to lookup SessionDevice
objects via major/minor. Device->session_devices is a linked list so we
can release all linked session-devices once a device vanishes.
Now we only have to hook this up in seat_set_active() so we correctly
change device states during session-switches. As mentioned earlier, these
are forced state-changes as VTs are currently used exclusively for
multi-session implementations.
Everything else are hooks to release all session-devices once the
controller changes or a session is closed or removed.
2013-09-17 23:39:04 +02:00
|
|
|
Hashmap *devices;
|
2015-08-05 15:58:39 +02:00
|
|
|
sd_bus_track *track;
|
2013-09-17 17:39:56 +02:00
|
|
|
|
2011-05-24 00:19:22 +02:00
|
|
|
LIST_FIELDS(Session, sessions_by_user);
|
|
|
|
LIST_FIELDS(Session, sessions_by_seat);
|
2011-05-25 00:55:58 +02:00
|
|
|
|
|
|
|
LIST_FIELDS(Session, gc_queue);
|
2011-05-24 00:19:22 +02:00
|
|
|
};
|
|
|
|
|
2018-08-03 18:53:09 +02:00
|
|
|
int session_new(Session **ret, Manager *m, const char *id);
|
|
|
|
Session* session_free(Session *s);
|
|
|
|
|
|
|
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Session *, session_free);
|
|
|
|
|
2013-06-20 03:45:08 +02:00
|
|
|
void session_set_user(Session *s, User *u);
|
2018-08-07 12:08:24 +02:00
|
|
|
int session_set_leader(Session *s, pid_t pid);
|
2018-02-15 13:14:35 +01:00
|
|
|
bool session_may_gc(Session *s, bool drop_not_started);
|
2011-05-25 00:55:58 +02:00
|
|
|
void session_add_to_gc_queue(Session *s);
|
2011-05-24 00:19:22 +02:00
|
|
|
int session_activate(Session *s);
|
|
|
|
bool session_is_active(Session *s);
|
2011-06-17 15:59:18 +02:00
|
|
|
int session_get_idle_hint(Session *s, dual_timestamp *t);
|
2020-01-06 20:13:16 +01:00
|
|
|
int session_set_idle_hint(Session *s, bool b);
|
2016-05-11 19:34:13 +02:00
|
|
|
int session_get_locked_hint(Session *s);
|
|
|
|
void session_set_locked_hint(Session *s, bool b);
|
2020-02-23 04:44:42 +01:00
|
|
|
void session_set_type(Session *s, SessionType t);
|
2011-06-29 00:06:04 +02:00
|
|
|
int session_create_fifo(Session *s);
|
2018-08-06 21:44:45 +02:00
|
|
|
int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error);
|
2014-02-09 02:29:56 +01:00
|
|
|
int session_stop(Session *s, bool force);
|
2013-08-13 17:59:28 +02:00
|
|
|
int session_finalize(Session *s);
|
2015-03-15 21:37:39 +01:00
|
|
|
int session_release(Session *s);
|
2011-05-24 00:19:22 +02:00
|
|
|
int session_save(Session *s);
|
|
|
|
int session_load(Session *s);
|
2011-07-13 19:58:35 +02:00
|
|
|
int session_kill(Session *s, KillWho who, int signo);
|
2011-05-24 00:19:22 +02:00
|
|
|
|
2012-06-21 16:14:53 +02:00
|
|
|
SessionState session_get_state(Session *u);
|
|
|
|
|
2013-05-03 04:51:50 +02:00
|
|
|
const char* session_state_to_string(SessionState t) _const_;
|
|
|
|
SessionState session_state_from_string(const char *s) _pure_;
|
2012-06-21 16:14:53 +02:00
|
|
|
|
2013-05-03 04:51:50 +02:00
|
|
|
const char* session_type_to_string(SessionType t) _const_;
|
|
|
|
SessionType session_type_from_string(const char *s) _pure_;
|
2011-05-24 00:19:22 +02:00
|
|
|
|
2013-05-03 04:51:50 +02:00
|
|
|
const char* session_class_to_string(SessionClass t) _const_;
|
|
|
|
SessionClass session_class_from_string(const char *s) _pure_;
|
2012-02-14 21:33:51 +01:00
|
|
|
|
2013-05-03 04:51:50 +02:00
|
|
|
const char *kill_who_to_string(KillWho k) _const_;
|
|
|
|
KillWho kill_who_from_string(const char *s) _pure_;
|
2013-09-17 17:39:56 +02:00
|
|
|
|
2018-08-07 13:49:34 +02:00
|
|
|
const char* tty_validity_to_string(TTYValidity t) _const_;
|
|
|
|
TTYValidity tty_validity_from_string(const char *s) _pure_;
|
|
|
|
|
login: pause devices before acknowledging VT switches
If a session controller does not need synchronous VT switches, we allow
them to pass VT control to logind, which acknowledges all VT switches
unconditionally. This works fine with all sessions using the dbus API,
but causes out-of-sync device use if we switch to legacy sessions that
are notified via VT signals. Those are processed before logind notices
the session-switch via sysfs. Therefore, leaving the old session still
active for a short amount of time.
This, in fact, may cause the legacy session to prepare graphics devices
before the old session was deactivated, and thus, maybe causing the old
session to interfer with graphics device usage.
Fix this by releasing devices immediately before acknowledging VT
switches. This way, sessions without VT handlers are required to support
async session switching (which they do in that case, anyway).
2014-09-19 13:26:39 +02:00
|
|
|
void session_leave_vt(Session *s);
|
2013-11-28 15:10:24 +01:00
|
|
|
|
2013-09-17 17:39:56 +02:00
|
|
|
bool session_is_controller(Session *s, const char *sender);
|
2017-04-26 14:20:41 +02:00
|
|
|
int session_set_controller(Session *s, const char *sender, bool force, bool prepare);
|
2013-09-17 17:39:56 +02:00
|
|
|
void session_drop_controller(Session *s);
|
2015-02-18 12:55:25 +01:00
|
|
|
|
logind: make "self" and "auto" magic strings when operating on seats + sessions
Most of the operations one can do on sessions so far accepted an empty
session name as a shortcut for the caller's session. This is quite
useful traditionally, but much less useful than it used to be, since
most user code now (rightfully) runs in --user context, not in a
session.
With this change we tweak the logic a bit: we introduce the two special
session and seat names "self" and "auto". The former refers to the
session/seat the client is in, and is hence mostly equivalent to te
empty string "" as before. However, the latter refers to the
session/seat the client is in if that exists, with a fallback of the
user's display session if not. Clients can hence reference "auto"
instead of the empty string if they really don't want to think much
about sessions.
Why "self" btw? Previously, we'd already expose a special dbus object
with the path /org/freedesktop/login1/session/self (and similar for the
seat), matching what the empty string did for bus calls that took a
session name. With this scheme we reuse this identifier and introduce
"auto" in a similar way.
Of course this means real-life seats and sessions can never be named
"self" or "auto", but they aren't anyway: valid seat names have to start
with "seat" anyway, and sessions are generated server-side as either a
numeric value or "c" suffixed with a counter ID.
Fixes: #12399
2019-04-28 17:55:36 +02:00
|
|
|
static inline bool SESSION_IS_SELF(const char *name) {
|
|
|
|
return isempty(name) || streq(name, "self");
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool SESSION_IS_AUTO(const char *name) {
|
|
|
|
return streq_ptr(name, "auto");
|
|
|
|
}
|