2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
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-25 13:14:12 +01:00
|
|
|
#include "bus-util.h"
|
|
|
|
#include "fd-util.h"
|
logind: add SetBrightness() bus call for setting brightness of leds/backlight devices associated with a seat
This augments the drm/input device management by adding a single method
call for setting the brightness of an "leds" or "backlight" kernel class
device.
This method call requires no privileges to call, but a caller can only
change the brightness on sessions that are currently active, and they
must own the session.
This does not do enumeration of such class devices, feature or range
probing, chnage notification; it doesn't help associating graphics or
input devices with their backlight or leds devices. For all that clients
should go directly to udev/sysfs. The SetBrightness() call is just for
executing the actual change operation, that is otherwise privileged.
Example line:
busctl call org.freedesktop.login1 /org/freedesktop/login1/session/self org.freedesktop.login1.Session SetBrightness ssu "backlight" "intel_backlight" 200
The parameter the SetBrightness() call takes are the kernel subsystem
(i.e. "leds" or "backlight"), the device name, and the brightness
value.
On some hw setting the brightness is slow, and implementation and write
access to the sysfs knobs exposes this slowness. Due to this we'll fork
off a writer process in the background so that logind doesn't have to
block. Moreover, write requestes are coalesced: when a write request is
enqueued while one is already being executed it is queued. When another
write reques is then enqueued the earlier one is replaced by the newer
one, so that only one queued write request per device remains at any
time. Method replies are sent as soon as the first write request that
happens after the request was received is completed.
It is recommended that bus clients turn off the "expect_reply" flag on
the dbus messages they send though, that relieves logind from sending
completion notification and is particularly a good idea if clients
implement reactive UI sliders that send a quick secession of write
requests.
Replaces: #12413
2019-04-28 11:07:56 +02:00
|
|
|
#include "logind-brightness.h"
|
2019-04-30 15:05:14 +02:00
|
|
|
#include "logind-dbus.h"
|
|
|
|
#include "logind-seat-dbus.h"
|
|
|
|
#include "logind-session-dbus.h"
|
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
|
|
|
#include "logind-session-device.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "logind-session.h"
|
2019-04-30 15:05:14 +02:00
|
|
|
#include "logind-user-dbus.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "logind.h"
|
2018-12-04 08:26:09 +01:00
|
|
|
#include "missing_capability.h"
|
logind: add SetBrightness() bus call for setting brightness of leds/backlight devices associated with a seat
This augments the drm/input device management by adding a single method
call for setting the brightness of an "leds" or "backlight" kernel class
device.
This method call requires no privileges to call, but a caller can only
change the brightness on sessions that are currently active, and they
must own the session.
This does not do enumeration of such class devices, feature or range
probing, chnage notification; it doesn't help associating graphics or
input devices with their backlight or leds devices. For all that clients
should go directly to udev/sysfs. The SetBrightness() call is just for
executing the actual change operation, that is otherwise privileged.
Example line:
busctl call org.freedesktop.login1 /org/freedesktop/login1/session/self org.freedesktop.login1.Session SetBrightness ssu "backlight" "intel_backlight" 200
The parameter the SetBrightness() call takes are the kernel subsystem
(i.e. "leds" or "backlight"), the device name, and the brightness
value.
On some hw setting the brightness is slow, and implementation and write
access to the sysfs knobs exposes this slowness. Due to this we'll fork
off a writer process in the background so that logind doesn't have to
block. Moreover, write requestes are coalesced: when a write request is
enqueued while one is already being executed it is queued. When another
write reques is then enqueued the earlier one is replaced by the newer
one, so that only one queued write request per device remains at any
time. Method replies are sent as soon as the first write request that
happens after the request was received is completed.
It is recommended that bus clients turn off the "expect_reply" flag on
the dbus messages they send though, that relieves logind from sending
completion notification and is particularly a good idea if clients
implement reactive UI sliders that send a quick secession of write
requests.
Replaces: #12413
2019-04-28 11:07:56 +02:00
|
|
|
#include "path-util.h"
|
2016-04-08 11:27:28 +02:00
|
|
|
#include "signal-util.h"
|
2018-06-29 12:13:33 +02:00
|
|
|
#include "stat-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "strv.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 "user-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "util.h"
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
static int property_get_user(
|
|
|
|
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
|
|
|
|
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
Session *s = userdata;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(reply);
|
2011-05-26 02:21:16 +02:00
|
|
|
assert(s);
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
p = user_bus_path(s->user);
|
|
|
|
if (!p)
|
2011-05-26 02:21:16 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2019-08-07 16:22:35 +02:00
|
|
|
return sd_bus_message_append(reply, "(uo)", (uint32_t) s->user->user_record->uid, p);
|
2013-11-05 01:10:21 +01:00
|
|
|
}
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
static int property_get_name(
|
|
|
|
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-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(bus);
|
|
|
|
assert(reply);
|
|
|
|
assert(s);
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2019-08-07 16:22:35 +02:00
|
|
|
return sd_bus_message_append(reply, "s", s->user->user_record->user_name);
|
2011-05-26 02:21:16 +02:00
|
|
|
}
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
static int property_get_seat(
|
|
|
|
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-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
Session *s = userdata;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(bus);
|
|
|
|
assert(reply);
|
|
|
|
assert(s);
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
p = s->seat ? seat_bus_path(s->seat) : strdup("/");
|
2011-05-26 02:21:16 +02:00
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
return sd_bus_message_append(reply, "(so)", s->seat ? s->seat->id : "", p);
|
|
|
|
}
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, session_type, SessionType);
|
|
|
|
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, session_class, SessionClass);
|
2018-05-14 03:02:55 +02:00
|
|
|
static BUS_DEFINE_PROPERTY_GET(property_get_active, "b", Session, session_is_active);
|
|
|
|
static BUS_DEFINE_PROPERTY_GET2(property_get_state, "s", Session, session_get_state, session_state_to_string);
|
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-17 15:59:18 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(reply);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
return sd_bus_message_append(reply, "b", session_get_idle_hint(s, NULL) > 0);
|
2011-06-17 15:59:18 +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
|
|
|
|
|
|
|
Session *s = userdata;
|
2015-06-16 01:08:12 +02:00
|
|
|
dual_timestamp t = DUAL_TIMESTAMP_NULL;
|
2011-06-17 15:59:18 +02:00
|
|
|
uint64_t u;
|
2012-09-21 13:38:40 +02:00
|
|
|
int r;
|
2011-06-17 15:59:18 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(bus);
|
|
|
|
assert(reply);
|
2011-06-17 15:59:18 +02:00
|
|
|
assert(s);
|
|
|
|
|
2012-09-21 13:38:40 +02:00
|
|
|
r = session_get_idle_hint(s, &t);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2011-06-17 15:59:18 +02:00
|
|
|
u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
return sd_bus_message_append(reply, "t", u);
|
2011-06-17 15:59:18 +02:00
|
|
|
}
|
|
|
|
|
2016-05-11 19:34:13 +02:00
|
|
|
static int property_get_locked_hint(
|
|
|
|
sd_bus *bus,
|
|
|
|
const char *path,
|
|
|
|
const char *interface,
|
|
|
|
const char *property,
|
|
|
|
sd_bus_message *reply,
|
|
|
|
void *userdata,
|
|
|
|
sd_bus_error *error) {
|
|
|
|
|
|
|
|
Session *s = userdata;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(reply);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
return sd_bus_message_append(reply, "b", session_get_locked_hint(s) > 0);
|
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
|
|
|
int r;
|
2012-06-21 16:14:53 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(message);
|
2012-06-21 16:14:53 +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,
|
2019-08-07 16:22:35 +02:00
|
|
|
s->user->user_record->uid,
|
2015-02-18 12:55:25 +01:00
|
|
|
&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 = session_stop(s, /* force = */ true);
|
2013-11-05 01:10:21 +01:00
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2012-06-21 16:14:53 +02:00
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
2012-06-21 16:14:53 +02:00
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
|
|
|
int r;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(message);
|
|
|
|
assert(s);
|
2011-05-26 02:21:16 +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(s);
|
|
|
|
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);
|
2013-11-05 01:10:21 +01:00
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(message);
|
|
|
|
assert(s);
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2015-02-18 12:55:25 +01:00
|
|
|
r = bus_verify_polkit_async(
|
|
|
|
message,
|
|
|
|
CAP_SYS_ADMIN,
|
|
|
|
"org.freedesktop.login1.lock-sessions",
|
2015-09-05 16:07:16 +02:00
|
|
|
NULL,
|
2015-02-18 12:55:25 +01:00
|
|
|
false,
|
2019-08-07 16:22:35 +02:00
|
|
|
s->user->user_record->uid,
|
2015-02-18 12:55:25 +01:00
|
|
|
&s->manager->polkit_registry,
|
|
|
|
error);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return 1; /* Will call us back */
|
|
|
|
|
|
|
|
r = session_send_lock(s, strstr(sd_bus_message_get_member(message), "Lock"));
|
2013-11-05 01:10:21 +01:00
|
|
|
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_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
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;
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
|
|
|
uid_t uid;
|
|
|
|
int r, b;
|
2012-01-16 00:23:59 +01:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(message);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
r = sd_bus_message_read(message, "b", &b);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2012-01-16 00:23:59 +01:00
|
|
|
|
bus: use EUID over UID and fix unix-creds
Whenever a process performs an action on an object, the kernel uses the
EUID of the process to do permission checks and to apply on any newly
created objects. The UID of a process is only used if someone *ELSE* acts
on the process. That is, the UID of a process defines who owns the
process, the EUID defines what privileges are used by this process when
performing an action.
Process limits, on the other hand, are always applied to the real UID, not
the effective UID. This is, because a process has a user object linked,
which always corresponds to its UID. A process never has a user object
linked for its EUID. Thus, accounting (and limits) is always done on the
real UID.
This commit fixes all sd-bus users to use the EUID when performing
privilege checks and alike. Furthermore, it fixes unix-creds to be parsed
as EUID, not UID (as the kernel always takes the EUID on UDS). Anyone
using UID (eg., to do user-accounting) has to fall back to the EUID as UDS
does not transmit the UID.
2015-01-18 13:55:55 +01:00
|
|
|
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
|
2013-11-28 17:50:02 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
bus: use EUID over UID and fix unix-creds
Whenever a process performs an action on an object, the kernel uses the
EUID of the process to do permission checks and to apply on any newly
created objects. The UID of a process is only used if someone *ELSE* acts
on the process. That is, the UID of a process defines who owns the
process, the EUID defines what privileges are used by this process when
performing an action.
Process limits, on the other hand, are always applied to the real UID, not
the effective UID. This is, because a process has a user object linked,
which always corresponds to its UID. A process never has a user object
linked for its EUID. Thus, accounting (and limits) is always done on the
real UID.
This commit fixes all sd-bus users to use the EUID when performing
privilege checks and alike. Furthermore, it fixes unix-creds to be parsed
as EUID, not UID (as the kernel always takes the EUID on UDS). Anyone
using UID (eg., to do user-accounting) has to fall back to the EUID as UDS
does not transmit the UID.
2015-01-18 13:55:55 +01:00
|
|
|
r = sd_bus_creds_get_euid(creds, &uid);
|
2013-11-05 01:10:21 +01:00
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2013-11-05 01:10:21 +01:00
|
|
|
|
2019-08-07 16:22:35 +02:00
|
|
|
if (uid != 0 && uid != s->user->user_record->uid)
|
2014-09-17 20:10:44 +02:00
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set idle hint");
|
2013-11-05 01:10:21 +01:00
|
|
|
|
2020-01-06 20:13:16 +01:00
|
|
|
r = session_set_idle_hint(s, b);
|
|
|
|
if (r == -ENOTTY)
|
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Idle hint control is not supported on non-graphical sessions.");
|
|
|
|
if (r < 0)
|
|
|
|
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);
|
2013-11-05 01:10:21 +01:00
|
|
|
}
|
|
|
|
|
2016-05-11 19:34:13 +02:00
|
|
|
static int method_set_locked_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
|
|
|
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
|
|
|
Session *s = userdata;
|
|
|
|
uid_t uid;
|
|
|
|
int r, b;
|
|
|
|
|
|
|
|
assert(message);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
r = sd_bus_message_read(message, "b", &b);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_creds_get_euid(creds, &uid);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-08-07 16:22:35 +02:00
|
|
|
if (uid != 0 && uid != s->user->user_record->uid)
|
2016-05-11 19:34:13 +02:00
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set locked hint");
|
|
|
|
|
|
|
|
session_set_locked_hint(s, b);
|
|
|
|
|
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
|
|
|
const char *swho;
|
|
|
|
int32_t signo;
|
|
|
|
KillWho who;
|
2011-06-21 19:20:05 +02:00
|
|
|
int r;
|
|
|
|
|
2011-05-26 02:21:16 +02:00
|
|
|
assert(message);
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(s);
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
r = sd_bus_message_read(message, "si", &swho, &signo);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2013-11-05 01:10:21 +01:00
|
|
|
|
|
|
|
if (isempty(swho))
|
|
|
|
who = KILL_ALL;
|
|
|
|
else {
|
|
|
|
who = kill_who_from_string(swho);
|
|
|
|
if (who < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
|
2013-11-05 01:10:21 +01:00
|
|
|
}
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2016-04-08 11:27:28 +02:00
|
|
|
if (!SIGNAL_VALID(signo))
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
|
2011-06-21 19:20:05 +02:00
|
|
|
|
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,
|
2019-08-07 16:22:35 +02:00
|
|
|
s->user->user_record->uid,
|
2015-02-18 12:55:25 +01:00
|
|
|
&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_kill(s, who, signo);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
2013-11-05 01:10:21 +01:00
|
|
|
}
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_take_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
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;
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
|
|
|
int r, force;
|
|
|
|
uid_t uid;
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(message);
|
|
|
|
assert(s);
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
r = sd_bus_message_read(message, "b", &force);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-06-21 19:20:05 +02:00
|
|
|
|
bus: use EUID over UID and fix unix-creds
Whenever a process performs an action on an object, the kernel uses the
EUID of the process to do permission checks and to apply on any newly
created objects. The UID of a process is only used if someone *ELSE* acts
on the process. That is, the UID of a process defines who owns the
process, the EUID defines what privileges are used by this process when
performing an action.
Process limits, on the other hand, are always applied to the real UID, not
the effective UID. This is, because a process has a user object linked,
which always corresponds to its UID. A process never has a user object
linked for its EUID. Thus, accounting (and limits) is always done on the
real UID.
This commit fixes all sd-bus users to use the EUID when performing
privilege checks and alike. Furthermore, it fixes unix-creds to be parsed
as EUID, not UID (as the kernel always takes the EUID on UDS). Anyone
using UID (eg., to do user-accounting) has to fall back to the EUID as UDS
does not transmit the UID.
2015-01-18 13:55:55 +01:00
|
|
|
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
|
2013-11-28 17:50:02 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
bus: use EUID over UID and fix unix-creds
Whenever a process performs an action on an object, the kernel uses the
EUID of the process to do permission checks and to apply on any newly
created objects. The UID of a process is only used if someone *ELSE* acts
on the process. That is, the UID of a process defines who owns the
process, the EUID defines what privileges are used by this process when
performing an action.
Process limits, on the other hand, are always applied to the real UID, not
the effective UID. This is, because a process has a user object linked,
which always corresponds to its UID. A process never has a user object
linked for its EUID. Thus, accounting (and limits) is always done on the
real UID.
This commit fixes all sd-bus users to use the EUID when performing
privilege checks and alike. Furthermore, it fixes unix-creds to be parsed
as EUID, not UID (as the kernel always takes the EUID on UDS). Anyone
using UID (eg., to do user-accounting) has to fall back to the EUID as UDS
does not transmit the UID.
2015-01-18 13:55:55 +01:00
|
|
|
r = sd_bus_creds_get_euid(creds, &uid);
|
2013-11-05 01:10:21 +01:00
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2019-08-07 16:22:35 +02:00
|
|
|
if (uid != 0 && (force || uid != s->user->user_record->uid))
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control");
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2017-04-26 14:20:41 +02:00
|
|
|
r = session_set_controller(s, sd_bus_message_get_sender(message), 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-21 19:20:05 +02:00
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
2013-11-05 01:10:21 +01:00
|
|
|
}
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_release_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(message);
|
|
|
|
assert(s);
|
2011-06-29 19:53:27 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
if (!session_is_controller(s, sd_bus_message_get_sender(message)))
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
|
2011-06-29 19:53:27 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
session_drop_controller(s);
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
2013-11-05 01:10:21 +01:00
|
|
|
}
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2020-02-23 04:44:42 +01:00
|
|
|
static int method_set_type(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
|
|
|
Session *s = userdata;
|
|
|
|
const char *t;
|
|
|
|
SessionType type;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(message);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
r = sd_bus_message_read(message, "s", &t);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
type = session_type_from_string(t);
|
|
|
|
if (type < 0)
|
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
|
|
|
"Invalid session type '%s'", t);
|
|
|
|
|
|
|
|
if (!session_is_controller(s, sd_bus_message_get_sender(message)))
|
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set type");
|
|
|
|
|
|
|
|
session_set_type(s, type);
|
|
|
|
|
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
|
|
|
}
|
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
|
|
|
uint32_t major, minor;
|
|
|
|
SessionDevice *sd;
|
|
|
|
dev_t dev;
|
|
|
|
int r;
|
2011-07-13 19:58:35 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(message);
|
|
|
|
assert(s);
|
2011-07-13 19:58:35 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
r = sd_bus_message_read(message, "uu", &major, &minor);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2013-11-05 01:10:21 +01:00
|
|
|
|
2018-06-29 12:13:33 +02:00
|
|
|
if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
|
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
if (!session_is_controller(s, sd_bus_message_get_sender(message)))
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
|
2013-11-05 01:10:21 +01:00
|
|
|
|
|
|
|
dev = makedev(major, minor);
|
|
|
|
sd = hashmap_get(s->devices, &dev);
|
|
|
|
if (sd)
|
|
|
|
/* We don't allow retrieving a device multiple times.
|
|
|
|
* The related ReleaseDevice call is not ref-counted.
|
|
|
|
* The caller should use dup() if it requires more
|
|
|
|
* than one fd (it would be functionally
|
|
|
|
* equivalent). */
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken");
|
2013-11-05 01:10:21 +01:00
|
|
|
|
2017-03-16 11:17:09 +01:00
|
|
|
r = session_device_new(s, dev, true, &sd);
|
2013-11-05 01:10:21 +01:00
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2011-07-13 19:58:35 +02:00
|
|
|
|
2017-03-16 11:17:09 +01:00
|
|
|
r = session_device_save(sd);
|
|
|
|
if (r < 0)
|
|
|
|
goto error;
|
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active);
|
2013-11-05 01:10:21 +01:00
|
|
|
if (r < 0)
|
2017-03-16 11:17:09 +01:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
session_save(s);
|
2017-08-26 15:19:26 +02:00
|
|
|
return 1;
|
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
|
|
|
|
2017-03-16 11:17:09 +01:00
|
|
|
error:
|
|
|
|
session_device_free(sd);
|
2013-11-05 01:10:21 +01:00
|
|
|
return r;
|
|
|
|
}
|
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
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_release_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
|
|
|
uint32_t major, minor;
|
|
|
|
SessionDevice *sd;
|
|
|
|
dev_t dev;
|
|
|
|
int r;
|
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
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(message);
|
|
|
|
assert(s);
|
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
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
r = sd_bus_message_read(message, "uu", &major, &minor);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
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
|
|
|
|
2018-06-29 12:13:33 +02:00
|
|
|
if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
|
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
if (!session_is_controller(s, sd_bus_message_get_sender(message)))
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
|
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
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
dev = makedev(major, minor);
|
|
|
|
sd = hashmap_get(s->devices, &dev);
|
|
|
|
if (!sd)
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
|
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
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
session_device_free(sd);
|
2017-03-16 11:17:09 +01:00
|
|
|
session_save(s);
|
|
|
|
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_return(message, NULL);
|
2013-11-05 01:10:21 +01:00
|
|
|
}
|
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
|
|
|
|
2015-04-29 18:35:10 +02:00
|
|
|
static int method_pause_device_complete(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *s = userdata;
|
|
|
|
uint32_t major, minor;
|
|
|
|
SessionDevice *sd;
|
|
|
|
dev_t dev;
|
|
|
|
int r;
|
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
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(message);
|
|
|
|
assert(s);
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
r = sd_bus_message_read(message, "uu", &major, &minor);
|
|
|
|
if (r < 0)
|
2013-11-21 19:34:37 +01:00
|
|
|
return r;
|
2013-11-05 01:10:21 +01:00
|
|
|
|
2018-06-29 12:13:33 +02:00
|
|
|
if (!DEVICE_MAJOR_VALID(major) || !DEVICE_MINOR_VALID(minor))
|
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Device major/minor is not valid.");
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
if (!session_is_controller(s, sd_bus_message_get_sender(message)))
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session");
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
dev = makedev(major, minor);
|
|
|
|
sd = hashmap_get(s->devices, &dev);
|
|
|
|
if (!sd)
|
2013-11-21 19:34:37 +01:00
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken");
|
2011-06-21 19:20:05 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
session_device_complete_pause(sd);
|
2011-06-21 19:20:05 +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
|
|
|
}
|
|
|
|
|
logind: add SetBrightness() bus call for setting brightness of leds/backlight devices associated with a seat
This augments the drm/input device management by adding a single method
call for setting the brightness of an "leds" or "backlight" kernel class
device.
This method call requires no privileges to call, but a caller can only
change the brightness on sessions that are currently active, and they
must own the session.
This does not do enumeration of such class devices, feature or range
probing, chnage notification; it doesn't help associating graphics or
input devices with their backlight or leds devices. For all that clients
should go directly to udev/sysfs. The SetBrightness() call is just for
executing the actual change operation, that is otherwise privileged.
Example line:
busctl call org.freedesktop.login1 /org/freedesktop/login1/session/self org.freedesktop.login1.Session SetBrightness ssu "backlight" "intel_backlight" 200
The parameter the SetBrightness() call takes are the kernel subsystem
(i.e. "leds" or "backlight"), the device name, and the brightness
value.
On some hw setting the brightness is slow, and implementation and write
access to the sysfs knobs exposes this slowness. Due to this we'll fork
off a writer process in the background so that logind doesn't have to
block. Moreover, write requestes are coalesced: when a write request is
enqueued while one is already being executed it is queued. When another
write reques is then enqueued the earlier one is replaced by the newer
one, so that only one queued write request per device remains at any
time. Method replies are sent as soon as the first write request that
happens after the request was received is completed.
It is recommended that bus clients turn off the "expect_reply" flag on
the dbus messages they send though, that relieves logind from sending
completion notification and is particularly a good idea if clients
implement reactive UI sliders that send a quick secession of write
requests.
Replaces: #12413
2019-04-28 11:07:56 +02:00
|
|
|
static int method_set_brightness(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
|
|
|
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
|
|
|
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
|
|
|
|
const char *subsystem, *name, *seat;
|
|
|
|
Session *s = userdata;
|
|
|
|
uint32_t brightness;
|
|
|
|
uid_t uid;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(message);
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
r = sd_bus_message_read(message, "ssu", &subsystem, &name, &brightness);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (!STR_IN_SET(subsystem, "backlight", "leds"))
|
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Subsystem type %s not supported, must be one of 'backlight' or 'leds'.", subsystem);
|
|
|
|
if (!filename_is_valid(name))
|
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Not a valid device name %s, refusing.", name);
|
|
|
|
|
|
|
|
if (!s->seat)
|
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_NOT_YOUR_DEVICE, "Your session has no seat, refusing.");
|
|
|
|
if (s->seat->active != s)
|
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_NOT_YOUR_DEVICE, "Session is not in foreground, refusing.");
|
|
|
|
|
|
|
|
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_creds_get_euid(creds, &uid);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-08-07 16:22:35 +02:00
|
|
|
if (uid != 0 && uid != s->user->user_record->uid)
|
logind: add SetBrightness() bus call for setting brightness of leds/backlight devices associated with a seat
This augments the drm/input device management by adding a single method
call for setting the brightness of an "leds" or "backlight" kernel class
device.
This method call requires no privileges to call, but a caller can only
change the brightness on sessions that are currently active, and they
must own the session.
This does not do enumeration of such class devices, feature or range
probing, chnage notification; it doesn't help associating graphics or
input devices with their backlight or leds devices. For all that clients
should go directly to udev/sysfs. The SetBrightness() call is just for
executing the actual change operation, that is otherwise privileged.
Example line:
busctl call org.freedesktop.login1 /org/freedesktop/login1/session/self org.freedesktop.login1.Session SetBrightness ssu "backlight" "intel_backlight" 200
The parameter the SetBrightness() call takes are the kernel subsystem
(i.e. "leds" or "backlight"), the device name, and the brightness
value.
On some hw setting the brightness is slow, and implementation and write
access to the sysfs knobs exposes this slowness. Due to this we'll fork
off a writer process in the background so that logind doesn't have to
block. Moreover, write requestes are coalesced: when a write request is
enqueued while one is already being executed it is queued. When another
write reques is then enqueued the earlier one is replaced by the newer
one, so that only one queued write request per device remains at any
time. Method replies are sent as soon as the first write request that
happens after the request was received is completed.
It is recommended that bus clients turn off the "expect_reply" flag on
the dbus messages they send though, that relieves logind from sending
completion notification and is particularly a good idea if clients
implement reactive UI sliders that send a quick secession of write
requests.
Replaces: #12413
2019-04-28 11:07:56 +02:00
|
|
|
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may change brightness.");
|
|
|
|
|
|
|
|
r = sd_device_new_from_subsystem_sysname(&d, subsystem, name);
|
|
|
|
if (r < 0)
|
|
|
|
return sd_bus_error_set_errnof(error, r, "Failed to open device %s:%s: %m", subsystem, name);
|
|
|
|
|
|
|
|
if (sd_device_get_property_value(d, "ID_SEAT", &seat) >= 0 && !streq_ptr(seat, s->seat->id))
|
|
|
|
return sd_bus_error_setf(error, BUS_ERROR_NOT_YOUR_DEVICE, "Device %s:%s does not belong to your seat %s, refusing.", subsystem, name, s->seat->id);
|
|
|
|
|
|
|
|
r = manager_write_brightness(s->manager, d, brightness, message);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-04-23 01:00:07 +02:00
|
|
|
static int session_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;
|
2011-05-26 02:21:16 +02:00
|
|
|
Manager *m = userdata;
|
2013-11-05 01:10:21 +01:00
|
|
|
Session *session;
|
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 20:52:39 +01:00
|
|
|
int r;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
assert(bus);
|
|
|
|
assert(path);
|
|
|
|
assert(interface);
|
|
|
|
assert(found);
|
|
|
|
assert(m);
|
2011-05-26 02:21:16 +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/session/");
|
|
|
|
if (!p)
|
|
|
|
return 0;
|
2011-05-26 02:21:16 +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
|
|
|
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_session_from_creds(m, message, e, error, &session);
|
|
|
|
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-05-26 02:21:16 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
*found = session;
|
|
|
|
return 1;
|
2011-05-26 02:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
char *session_bus_path(Session *s) {
|
2013-06-20 03:45:08 +02:00
|
|
|
_cleanup_free_ char *t = NULL;
|
2011-05-26 02:21:16 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2014-03-11 19:03:50 +01:00
|
|
|
t = bus_label_escape(s->id);
|
2011-05-26 02:21:16 +02:00
|
|
|
if (!t)
|
|
|
|
return NULL;
|
|
|
|
|
2019-07-11 19:14:16 +02:00
|
|
|
return strjoin("/org/freedesktop/login1/session/", t);
|
2011-05-26 02:21:16 +02:00
|
|
|
}
|
2011-06-21 20:43:34 +02:00
|
|
|
|
2020-04-23 01:00:07 +02:00
|
|
|
static int session_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;
|
2013-11-05 01:10:21 +01:00
|
|
|
Manager *m = userdata;
|
|
|
|
Session *session;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
assert(path);
|
|
|
|
assert(nodes);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(session, m->sessions) {
|
2013-11-05 01:10:21 +01:00
|
|
|
char *p;
|
|
|
|
|
|
|
|
p = session_bus_path(session);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
session = hashmap_get(m->sessions, name);
|
|
|
|
if (session) {
|
|
|
|
r = strv_extend(&l, "/org/freedesktop/login1/session/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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
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) {
|
|
|
|
r = strv_extend(&l, "/org/freedesktop/login1/session/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-06-21 20:43:34 +02:00
|
|
|
int session_send_signal(Session *s, bool new_session) {
|
2013-03-18 19:38:48 +01:00
|
|
|
_cleanup_free_ char *p = NULL;
|
2011-06-21 20:43:34 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
p = session_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_session ? "SessionNew" : "SessionRemoved",
|
|
|
|
"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 session_send_changed(Session *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 = session_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.Session", l);
|
2011-06-21 21:46:13 +02:00
|
|
|
}
|
2011-07-09 02:58:05 +02:00
|
|
|
|
|
|
|
int session_send_lock(Session *s, bool lock) {
|
2013-03-18 19:38:48 +01:00
|
|
|
_cleanup_free_ char *p = NULL;
|
2011-07-09 02:58:05 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
p = session_bus_path(s);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
return sd_bus_emit_signal(
|
|
|
|
s->manager->bus,
|
|
|
|
p,
|
|
|
|
"org.freedesktop.login1.Session",
|
|
|
|
lock ? "Lock" : "Unlock",
|
|
|
|
NULL);
|
2011-07-09 02:58:05 +02:00
|
|
|
}
|
2012-10-28 17:25:23 +01:00
|
|
|
|
|
|
|
int session_send_lock_all(Manager *m, bool lock) {
|
|
|
|
Session *session;
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
2020-09-08 11:58:29 +02:00
|
|
|
HASHMAP_FOREACH(session, m->sessions) {
|
2012-10-28 17:25:23 +01:00
|
|
|
int k;
|
|
|
|
|
|
|
|
k = session_send_lock(session, lock);
|
|
|
|
if (k < 0)
|
|
|
|
r = k;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2013-07-02 01:46:30 +02:00
|
|
|
|
2018-08-06 19:34:39 +02:00
|
|
|
static bool session_ready(Session *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
/* Returns true when the session is ready, i.e. all jobs we enqueued for it are done (regardless if successful or not) */
|
|
|
|
|
|
|
|
return !s->scope_job &&
|
|
|
|
!s->user->service_job;
|
|
|
|
}
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
int session_send_create_reply(Session *s, sd_bus_error *error) {
|
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_message_unrefp) sd_bus_message *c = NULL;
|
2013-11-05 01:10:21 +01:00
|
|
|
_cleanup_close_ int fifo_fd = -1;
|
|
|
|
_cleanup_free_ char *p = NULL;
|
2013-07-02 01:46:30 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2018-08-06 19:34:39 +02:00
|
|
|
/* This is called after the session scope and the user service were successfully created, and finishes where
|
2014-01-08 23:45:38 +01:00
|
|
|
* bus_manager_create_session() left off. */
|
2013-07-26 17:32:19 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
if (!s->create_message)
|
|
|
|
return 0;
|
2013-07-02 01:46:30 +02:00
|
|
|
|
2018-08-06 19:34:39 +02:00
|
|
|
if (!sd_bus_error_is_set(error) && !session_ready(s))
|
2014-01-08 23:45:38 +01:00
|
|
|
return 0;
|
|
|
|
|
2018-08-06 19:34:09 +02:00
|
|
|
c = TAKE_PTR(s->create_message);
|
2013-11-05 01:10:21 +01:00
|
|
|
if (error)
|
2013-11-21 01:51:16 +01:00
|
|
|
return sd_bus_reply_method_error(c, error);
|
2013-07-02 01:46:30 +02:00
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
fifo_fd = session_create_fifo(s);
|
|
|
|
if (fifo_fd < 0)
|
|
|
|
return fifo_fd;
|
2013-07-02 01:46:30 +02:00
|
|
|
|
2018-08-06 19:34:39 +02:00
|
|
|
/* Update the session state file before we notify the client about the result. */
|
2013-11-13 18:06:34 +01:00
|
|
|
session_save(s);
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
p = session_bus_path(s);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
2013-07-02 01:46:30 +02:00
|
|
|
|
2013-11-06 23:24:16 +01:00
|
|
|
log_debug("Sending reply about created session: "
|
2014-02-19 23:17:45 +01:00
|
|
|
"id=%s object_path=%s uid=%u runtime_path=%s "
|
|
|
|
"session_fd=%d seat=%s vtnr=%u",
|
2013-11-06 23:24:16 +01:00
|
|
|
s->id,
|
|
|
|
p,
|
2019-08-07 16:22:35 +02:00
|
|
|
(uint32_t) s->user->user_record->uid,
|
2013-11-06 23:24:16 +01:00
|
|
|
s->user->runtime_path,
|
|
|
|
fifo_fd,
|
|
|
|
s->seat ? s->seat->id : "",
|
|
|
|
(uint32_t) s->vtnr);
|
|
|
|
|
2013-11-05 01:10:21 +01:00
|
|
|
return sd_bus_reply_method_return(
|
2013-11-26 05:05:00 +01:00
|
|
|
c, "soshusub",
|
2013-11-05 01:10:21 +01:00
|
|
|
s->id,
|
|
|
|
p,
|
|
|
|
s->user->runtime_path,
|
|
|
|
fifo_fd,
|
2019-08-07 16:22:35 +02:00
|
|
|
(uint32_t) s->user->user_record->uid,
|
2013-11-05 01:10:21 +01:00
|
|
|
s->seat ? s->seat->id : "",
|
|
|
|
(uint32_t) s->vtnr,
|
|
|
|
false);
|
2013-07-02 01:46:30 +02:00
|
|
|
}
|
2020-04-23 01:00:07 +02:00
|
|
|
|
|
|
|
static const sd_bus_vtable session_vtable[] = {
|
|
|
|
SD_BUS_VTABLE_START(0),
|
|
|
|
|
|
|
|
SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
|
|
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
|
|
|
|
SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
|
|
SD_BUS_PROPERTY("State", "s", property_get_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
|
|
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_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
|
|
|
|
|
|
|
SD_BUS_METHOD("Terminate",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
bus_session_method_terminate,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD("Activate",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
bus_session_method_activate,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD("Lock",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
bus_session_method_lock,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD("Unlock",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
bus_session_method_lock,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD_WITH_NAMES("SetIdleHint",
|
|
|
|
"b",
|
|
|
|
SD_BUS_PARAM(idle),
|
|
|
|
NULL,,
|
|
|
|
method_set_idle_hint,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD_WITH_NAMES("SetLockedHint",
|
|
|
|
"b",
|
|
|
|
SD_BUS_PARAM(locked),
|
|
|
|
NULL,,
|
|
|
|
method_set_locked_hint,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD_WITH_NAMES("Kill",
|
|
|
|
"si",
|
|
|
|
SD_BUS_PARAM(who)
|
|
|
|
SD_BUS_PARAM(signal_number),
|
|
|
|
NULL,,
|
|
|
|
bus_session_method_kill,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD_WITH_NAMES("TakeControl",
|
|
|
|
"b",
|
|
|
|
SD_BUS_PARAM(force),
|
|
|
|
NULL,,
|
|
|
|
method_take_control,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD("ReleaseControl",
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
method_release_control,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD_WITH_NAMES("SetType",
|
|
|
|
"s",
|
|
|
|
SD_BUS_PARAM(type),
|
|
|
|
NULL,,
|
|
|
|
method_set_type,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD_WITH_NAMES("TakeDevice",
|
|
|
|
"uu",
|
|
|
|
SD_BUS_PARAM(major)
|
|
|
|
SD_BUS_PARAM(minor),
|
|
|
|
"hb",
|
|
|
|
SD_BUS_PARAM(fd)
|
|
|
|
SD_BUS_PARAM(inactive),
|
|
|
|
method_take_device,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD_WITH_NAMES("ReleaseDevice",
|
|
|
|
"uu",
|
|
|
|
SD_BUS_PARAM(major)
|
|
|
|
SD_BUS_PARAM(minor),
|
|
|
|
NULL,,
|
|
|
|
method_release_device,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD_WITH_NAMES("PauseDeviceComplete",
|
|
|
|
"uu",
|
|
|
|
SD_BUS_PARAM(major)
|
|
|
|
SD_BUS_PARAM(minor),
|
|
|
|
NULL,,
|
|
|
|
method_pause_device_complete,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
SD_BUS_METHOD_WITH_NAMES("SetBrightness",
|
|
|
|
"ssu",
|
|
|
|
SD_BUS_PARAM(subsystem)
|
|
|
|
SD_BUS_PARAM(name)
|
|
|
|
SD_BUS_PARAM(brightness),
|
|
|
|
NULL,,
|
|
|
|
method_set_brightness,
|
|
|
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
|
|
|
|
|
|
|
SD_BUS_SIGNAL_WITH_NAMES("PauseDevice",
|
|
|
|
"uus",
|
|
|
|
SD_BUS_PARAM(major)
|
|
|
|
SD_BUS_PARAM(minor)
|
|
|
|
SD_BUS_PARAM(type),
|
|
|
|
0),
|
|
|
|
SD_BUS_SIGNAL_WITH_NAMES("ResumeDevice",
|
|
|
|
"uuh",
|
|
|
|
SD_BUS_PARAM(major)
|
|
|
|
SD_BUS_PARAM(minor)
|
|
|
|
SD_BUS_PARAM(fd),
|
|
|
|
0),
|
|
|
|
SD_BUS_SIGNAL("Lock", NULL, 0),
|
|
|
|
SD_BUS_SIGNAL("Unlock", NULL, 0),
|
|
|
|
|
|
|
|
SD_BUS_VTABLE_END
|
|
|
|
};
|
|
|
|
|
|
|
|
const BusObjectImplementation session_object = {
|
|
|
|
"/org/freedesktop/login1/session",
|
|
|
|
"org.freedesktop.login1.Session",
|
|
|
|
.fallback_vtables = BUS_FALLBACK_VTABLES({session_vtable, session_object_find}),
|
|
|
|
.node_enumerator = session_node_enumerator,
|
|
|
|
};
|