2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2011-05-26 02:21:16 +02:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2014-12-10 19:00:46 +01:00
|
|
|
#include "bus-common-errors.h"
|
2020-06-28 16:43:29 +02:00
|
|
|
#include "bus-get-properties.h"
|
2014-03-11 19:03:50 +01:00
|
|
|
#include "bus-label.h"
|
2020-01-22 11:39:22 +01:00
|
|
|
#include "bus-polkit.h"
|
2015-10-27 00:42:07 +01:00
|
|
|
#include "bus-util.h"
|
2019-04-30 15:05:14 +02:00
|
|
|
#include "logind-dbus.h"
|
|
|
|
#include "logind-seat-dbus.h"
|
2011-05-26 02:21:16 +02:00
|
|
|
#include "logind-seat.h"
|
2019-04-30 15:05:14 +02:00
|
|
|
#include "logind-session-dbus.h"
|
2015-10-27 00:42:07 +01:00
|
|
|
#include "logind.h"
|
2018-12-04 08:26:09 +01:00
|
|
|
#include "missing_capability.h"
|
2015-10-27 00:42:07 +01:00
|
|
|
#include "strv.h"
|
|
|
|
#include "user-util.h"
|
|
|
|
#include "util.h"
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2020-04-17 13:57:40 +02:00
|
|
|
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_const_true, "b", true);
|
2018-05-14 03:02:55 +02:00
|
|
|
static BUS_DEFINE_PROPERTY_GET(property_get_can_tty, "b", Seat, seat_can_tty);
|
|
|
|
static BUS_DEFINE_PROPERTY_GET(property_get_can_graphical, "b", Seat, seat_can_graphical);
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
static int property_get_active_session(
|
|
|
|
sd_bus *bus,
|
|
|
|
const char *path,
|
|
|
|
const char *interface,
|
|
|
|
const char *property,
|
|
|
|
sd_bus_message *reply,
|
2013-11-21 19:34:37 +01:00
|
|
|
void *userdata,
|
|
|
|
sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
|
2013-04-18 09:11:22 +02:00
|
|
|
_cleanup_free_ char *p = NULL;
|
2013-11-05 01:10:21 +01:00
|
|
|
Seat *s = userdata;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(bus);
|
|
|
|
assert(reply);
|
2011-05-26 02:21:16 +02:00
|
|
|
assert(s);
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
p = s->active ? session_bus_path(s->active) : strdup("/");
|
|
|
|
if (!p)
|
2011-05-26 02:21:16 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p);
|
|
|
|
}
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
static int property_get_sessions(
|
|
|
|
sd_bus *bus,
|
|
|
|
const char *path,
|
|
|
|
const char *interface,
|
|
|
|
const char *property,
|
|
|
|
sd_bus_message *reply,
|
2013-11-21 19:34:37 +01:00
|
|
|
void *userdata,
|
|
|
|
sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
|
|
|
|
Seat *s = userdata;
|
2011-05-26 02:21:16 +02:00
|
|
|
Session *session;
|
2013-11-05 01:10:21 +01:00
|
|
|
int r;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(bus);
|
|
|
|
assert(reply);
|
2011-05-26 02:21:16 +02:00
|
|
|
assert(s);
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
r = sd_bus_message_open_container(reply, 'a', "(so)");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
|
|
|
LIST_FOREACH(sessions_by_seat, session, s->sessions) {
|
2013-04-18 09:11:22 +02:00
|
|
|
_cleanup_free_ char *p = NULL;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
|
|
|
p = session_bus_path(session);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
r = sd_bus_message_append(reply, "(so)", session->id, p);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
r = sd_bus_message_close_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
return 1;
|
2011-05-26 02:21:16 +02:00
|
|
|
}
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
static int property_get_idle_hint(
|
|
|
|
sd_bus *bus,
|
|
|
|
const char *path,
|
|
|
|
const char *interface,
|
|
|
|
const char *property,
|
|
|
|
sd_bus_message *reply,
|
2013-11-21 19:34:37 +01:00
|
|
|
void *userdata,
|
|
|
|
sd_bus_error *error) {
|
2011-06-15 15:37:39 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
Seat *s = userdata;
|
2012-06-21 13:48:01 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(bus);
|
|
|
|
assert(reply);
|
2012-06-21 13:48:01 +02:00
|
|
|
assert(s);
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0);
|
2012-06-21 13:48:01 +02:00
|
|
|
}
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
static int property_get_idle_since_hint(
|
|
|
|
sd_bus *bus,
|
|
|
|
const char *path,
|
|
|
|
const char *interface,
|
|
|
|
const char *property,
|
|
|
|
sd_bus_message *reply,
|
2013-11-21 19:34:37 +01:00
|
|
|
void *userdata,
|
|
|
|
sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
|
|
|
|
Seat *s = userdata;
|
|
|
|
dual_timestamp t;
|
|
|
|
uint64_t u;
|
|
|
|
int r;
|
2012-06-21 13:48:01 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(bus);
|
|
|
|
assert(reply);
|
2012-06-21 13:48:01 +02:00
|
|
|
assert(s);
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
r = seat_get_idle_hint(s, &t);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2012-06-21 13:48:01 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
|
2012-06-21 13:48:01 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
return sd_bus_message_append(reply, "t", u);
|
2012-06-21 13:48:01 +02:00
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
Seat *s = userdata;
|
|
|
|
int r;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(message);
|
2011-06-17 15:59:18 +02:00
|
|
|
assert(s);
|
|
|
|
|
2015-02-18 12:55:25 +01:00
|
|
|
r = bus_verify_polkit_async(
|
|
|
|
message,
|
|
|
|
CAP_KILL,
|
|
|
|
"org.freedesktop.login1.manage",
|
2015-09-05 16:07:16 +02:00
|
|
|
NULL,
|
2015-02-18 12:55:25 +01:00
|
|
|
false,
|
|
|
|
UID_INVALID,
|
|
|
|
&s->manager->polkit_registry,
|
|
|
|
error);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return 1; /* Will call us back */
|
|
|
|
|
2020-09-11 17:59:39 +02:00
|
|
|
r = seat_stop_sessions(s, /* force = */ true);
|
2013-11-05 01:10:21 +01:00
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
2011-06-17 15:59:18 +02:00
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
Seat *s = userdata;
|
|
|
|
const char *name;
|
|
|
|
Session *session;
|
|
|
|
int r;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(message);
|
2011-06-17 15:59:18 +02:00
|
|
|
assert(s);
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
r = sd_bus_message_read(message, "s", &name);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
session = hashmap_get(s->manager->sessions, name);
|
|
|
|
if (!session)
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
if (session->seat != s)
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2020-01-22 12:04:38 +01:00
|
|
|
r = bus_verify_polkit_async(
|
|
|
|
message,
|
|
|
|
CAP_SYS_ADMIN,
|
|
|
|
"org.freedesktop.login1.chvt",
|
|
|
|
NULL,
|
|
|
|
false,
|
|
|
|
UID_INVALID,
|
|
|
|
&s->manager->polkit_registry,
|
|
|
|
error);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return 1; /* Will call us back */
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
r = session_activate(session);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
2011-05-26 02:21:16 +02:00
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
Seat *s = userdata;
|
2018-10-19 20:00:46 +02:00
|
|
|
unsigned to;
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(message);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
r = sd_bus_message_read(message, "u", &to);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (to <= 0)
|
2020-01-22 12:04:38 +01:00
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid virtual terminal");
|
|
|
|
|
|
|
|
r = bus_verify_polkit_async(
|
|
|
|
message,
|
|
|
|
CAP_SYS_ADMIN,
|
|
|
|
"org.freedesktop.login1.chvt",
|
|
|
|
NULL,
|
|
|
|
false,
|
|
|
|
UID_INVALID,
|
|
|
|
&s->manager->polkit_registry,
|
|
|
|
error);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return 1; /* Will call us back */
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
|
|
|
|
r = seat_switch_to(s, to);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
Seat *s = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(message);
|
|
|
|
assert(s);
|
|
|
|
|
2020-01-22 12:04:38 +01:00
|
|
|
r = bus_verify_polkit_async(
|
|
|
|
message,
|
|
|
|
CAP_SYS_ADMIN,
|
|
|
|
"org.freedesktop.login1.chvt",
|
|
|
|
NULL,
|
|
|
|
false,
|
|
|
|
UID_INVALID,
|
|
|
|
&s->manager->polkit_registry,
|
|
|
|
error);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return 1; /* Will call us back */
|
|
|
|
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
r = seat_switch_to_next(s);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
Seat *s = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(message);
|
|
|
|
assert(s);
|
|
|
|
|
2020-01-22 12:04:38 +01:00
|
|
|
r = bus_verify_polkit_async(
|
|
|
|
message,
|
|
|
|
CAP_SYS_ADMIN,
|
|
|
|
"org.freedesktop.login1.chvt",
|
|
|
|
NULL,
|
|
|
|
false,
|
|
|
|
UID_INVALID,
|
|
|
|
&s->manager->polkit_registry,
|
|
|
|
error);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return 1; /* Will call us back */
|
|
|
|
|
logind: introduce session "positions"
logind has no concept of session ordering. Sessions have a unique name,
some attributes about the capabilities and that's already it. There is
currently no stable+total order on sessions. If we use the logind API to
switch between sessions, we are faced with an unordered list of sessions
we have no clue of.
This used to be no problem on seats with VTs or on seats with only a
single active session. However, with the introduction of multi-session
capability for seats without VTs, we need to find a way to order sessions
in a stable way.
This patch introduces session "positions". A position is a simple integer
assigned to a session which is never changed implicitly (currently, we
also don't change it explicitly, but that may be changed someday). For
seats with VTs, we force the position to be the same as the VTnr. Without
VTs, we simply find the lowest unassigned number and use it as position.
If position-assignment fails or if, for any reason, we decide to not
assign a position to a session, the position is set to 0 (which is treated
as invalid position).
During session_load() or if two sessions have the same VTnr, we may end up
with two sessions with the same position (this shouldn't happen, but lets
be fail-safe in case some other part of the stack fails). This case is
dealt with gracefully by ignoring any session but the first session
assigned to the position. Thus, session->pos is a hint, seat->positions[i]
is the definite position-assignment. Always verify both match in case you
need to modify them!
Additionally, we introduce SwitchTo(unsigned int) on the seat-dbus-API.
You can call it with any integer value != 0 and logind will try to switch
to the request position. If you implement a compositor or any other
session-controller, you simply watch for ctrl+alt+F1 to F12 and call
SwitchTo(Fx). logind will figure a way out deal with this number.
For convenience, we also introduce SwitchToNext/Previous(). It should be
called on ctrl+alt+Left/Right (like the kernel-console used to support).
Note that the public API (SwitchTo*()) is *not* bound to the underlying
logic that is implemented now. We don't export "session-positions" on the
dbus/C API! They are an implementation detail. Instead, the SwitchTo*()
API is supposed to be a hint to let logind choose the session-switching
logic. Any foreground session-controller is free to enumerate/order
existing sessions according to their needs and call Session.Activate()
manually. But the SwitchTo*() API provides a uniform behavior across
session-controllers.
Background: Session-switching keys depend on the active keymap. The XKB
specification provides the XKB_KEY_XF86Switch_VT_1-12 key-symbols which
have to be mapped by all keymaps to allow session-switching. It is usually
bound to ctrl+alt+Fx but may be set differently. A compositor passes any
keyboard input to XKB before passing it to clients. In case a key-press
invokes the XKB_KEY_XF86Switch_VT_x action, the keypress is *not*
forwarded to clients, but instead a session-switch is scheduled.
This actually prevents us from handling these keys outside of the session.
If an active compositor has a keymap with a different mapping of these
keys, and logind itself tries to catch these combinations, we end up with
the key-press sent to the compositor's clients *and* handled by logind.
This is *bad* and we must avoid this. The only situation where a
background process is allowed to handle key-presses is debugging and
emergency-keys. In these cases, we don't care for keymap mismatches and
accept the double-event. Another exception is unmapped keys like
PowerOff/Suspend (even though this one is controversial).
2013-11-30 11:39:48 +01:00
|
|
|
r = seat_switch_to_previous(s);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
|
|
|
}
|
|
|
|
|
2020-04-23 01:00:07 +02:00
|
|
|
static int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
|
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
|
|
|
_cleanup_free_ char *e = NULL;
|
|
|
|
sd_bus_message *message;
|
2013-11-05 01:10:21 +01:00
|
|
|
Manager *m = userdata;
|
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
|
|
|
const char *p;
|
2013-11-05 01:10:21 +01:00
|
|
|
Seat *seat;
|
2013-11-05 20:52:39 +01:00
|
|
|
int r;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(bus);
|
|
|
|
assert(path);
|
|
|
|
assert(interface);
|
|
|
|
assert(found);
|
|
|
|
assert(m);
|
2011-06-17 15:59:18 +02: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
|
|
|
p = startswith(path, "/org/freedesktop/login1/seat/");
|
|
|
|
if (!p)
|
|
|
|
return 0;
|
2013-11-05 20:52:39 +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
|
|
|
e = bus_label_unescape(p);
|
|
|
|
if (!e)
|
|
|
|
return -ENOMEM;
|
2013-11-05 20:52:39 +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
|
|
|
message = sd_bus_get_current_message(bus);
|
2013-11-05 20:52:39 +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
|
|
|
r = manager_get_seat_from_creds(m, message, e, error, &seat);
|
|
|
|
if (r == -ENXIO) {
|
|
|
|
sd_bus_error_free(error);
|
|
|
|
return 0;
|
2013-11-05 20:52:39 +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
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
*found = seat;
|
|
|
|
return 1;
|
|
|
|
}
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
char *seat_bus_path(Seat *s) {
|
|
|
|
_cleanup_free_ char *t = NULL;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(s);
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2014-03-11 19:03:50 +01:00
|
|
|
t = bus_label_escape(s->id);
|
2013-11-05 01:10:21 +01:00
|
|
|
if (!t)
|
|
|
|
return NULL;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2019-07-11 19:14:16 +02:00
|
|
|
return strjoin("/org/freedesktop/login1/seat/", t);
|
2011-05-26 02:21:16 +02:00
|
|
|
}
|
|
|
|
|
2020-04-23 01:00:07 +02:00
|
|
|
static int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
_cleanup_strv_free_ char **l = NULL;
|
2015-01-18 12:59:39 +01:00
|
|
|
sd_bus_message *message;
|
2011-05-26 02:21:16 +02:00
|
|
|
Manager *m = userdata;
|
2013-11-05 01:10:21 +01:00
|
|
|
Seat *seat;
|
2011-05-26 02:21:16 +02:00
|
|
|
int r;
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(bus);
|
|
|
|
assert(path);
|
|
|
|
assert(nodes);
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(seat, m->seats) {
|
2013-11-05 01:10:21 +01:00
|
|
|
char *p;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
p = seat_bus_path(seat);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2014-03-04 15:20:51 +01:00
|
|
|
r = strv_consume(&l, p);
|
|
|
|
if (r < 0)
|
2013-11-05 01:10:21 +01:00
|
|
|
return r;
|
2011-05-26 02:21:16 +02:00
|
|
|
}
|
|
|
|
|
2015-01-18 12:59:39 +01:00
|
|
|
message = sd_bus_get_current_message(bus);
|
|
|
|
if (message) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
2015-01-18 12:59:39 +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
|
|
|
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
|
2015-01-18 12:59:39 +01:00
|
|
|
if (r >= 0) {
|
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
|
|
|
bool may_auto = false;
|
|
|
|
const char *name;
|
|
|
|
|
2015-01-18 12:59:39 +01:00
|
|
|
r = sd_bus_creds_get_session(creds, &name);
|
|
|
|
if (r >= 0) {
|
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
|
|
|
Session *session;
|
|
|
|
|
2015-01-18 12:59:39 +01:00
|
|
|
session = hashmap_get(m->sessions, name);
|
|
|
|
if (session && session->seat) {
|
|
|
|
r = strv_extend(&l, "/org/freedesktop/login1/seat/self");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
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
|
|
|
|
|
|
|
may_auto = true;
|
2015-01-18 12:59:39 +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
|
|
|
|
|
|
|
if (!may_auto) {
|
|
|
|
uid_t uid;
|
|
|
|
|
|
|
|
r = sd_bus_creds_get_owner_uid(creds, &uid);
|
|
|
|
if (r >= 0) {
|
|
|
|
User *user;
|
|
|
|
|
|
|
|
user = hashmap_get(m->users, UID_TO_PTR(uid));
|
|
|
|
may_auto = user && user->display && user->display->seat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (may_auto) {
|
|
|
|
r = strv_extend(&l, "/org/freedesktop/login1/seat/auto");
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2015-01-18 12:59:39 +01:00
|
|
|
}
|
|
|
|
}
|
2015-01-09 01:44:40 +01:00
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*nodes = TAKE_PTR(l);
|
2013-11-05 01:10:21 +01:00
|
|
|
return 1;
|
2011-05-26 02:21:16 +02:00
|
|
|
}
|
2011-06-21 20:43:34 +02:00
|
|
|
|
|
|
|
int seat_send_signal(Seat *s, bool new_seat) {
|
2013-03-18 19:38:48 +01:00
|
|
|
_cleanup_free_ char *p = NULL;
|
2011-06-21 20:43:34 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
p = seat_bus_path(s);
|
|
|
|
if (!p)
|
2013-03-19 01:31:21 +01:00
|
|
|
return -ENOMEM;
|
2011-06-21 20:43:34 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
return sd_bus_emit_signal(
|
|
|
|
s->manager->bus,
|
|
|
|
"/org/freedesktop/login1",
|
|
|
|
"org.freedesktop.login1.Manager",
|
|
|
|
new_seat ? "SeatNew" : "SeatRemoved",
|
|
|
|
"so", s->id, p);
|
2011-06-21 20:43:34 +02:00
|
|
|
}
|
2011-06-21 21:46:13 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
int seat_send_changed(Seat *s, const char *properties, ...) {
|
2013-03-18 19:38:48 +01:00
|
|
|
_cleanup_free_ char *p = NULL;
|
2013-11-05 01:10:21 +01:00
|
|
|
char **l;
|
2011-06-21 21:46:13 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2011-06-24 19:42:45 +02:00
|
|
|
if (!s->started)
|
|
|
|
return 0;
|
|
|
|
|
2011-06-21 21:46:13 +02:00
|
|
|
p = seat_bus_path(s);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
l = strv_from_stdarg_alloca(properties);
|
2011-06-21 21:46:13 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
|
2011-06-21 21:46:13 +02:00
|
|
|
}
|
2020-04-23 01:00:07 +02:00
|
|
|
|
|
|
|
static const sd_bus_vtable seat_vtable[] = {
|
|
|
|
SD_BUS_VTABLE_START(0),
|
|
|
|
|
|
|
|
SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
|
|
SD_BUS_PROPERTY("CanMultiSession", "b", property_get_const_true, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
|
|
|
|
SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
|
|
SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
|
|
|
|
SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
|
|
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
|
|
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
|
|
|
|
|
|
SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
|
|
|
|
SD_BUS_METHOD_WITH_NAMES("ActivateSession",
|
|
|
|
"s",
|
|
|
|
SD_BUS_PARAM(session_id),
|
|
|
|
NULL,,
|
|
|
|
method_activate_session,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD_WITH_NAMES("SwitchTo",
|
|
|
|
"u",
|
|
|
|
SD_BUS_PARAM(vtnr),
|
|
|
|
NULL,,
|
|
|
|
method_switch_to,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
|
|
|
|
SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
|
|
|
|
SD_BUS_VTABLE_END
|
|
|
|
};
|
|
|
|
|
|
|
|
const BusObjectImplementation seat_object = {
|
|
|
|
"/org/freedesktop/login1/seat",
|
|
|
|
"org.freedesktop.login1.Seat",
|
|
|
|
.fallback_vtables = BUS_FALLBACK_VTABLES({seat_vtable, seat_object_find}),
|
|
|
|
.node_enumerator = seat_node_enumerator,
|
|
|
|
};
|