clients: use fine-grained capabilities for privileged protocols
This commit is contained in:
parent
e543646944
commit
ef53d72ff8
13 changed files with 78 additions and 55 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::SpawnedFuture,
|
async_engine::SpawnedFuture,
|
||||||
|
client::ClientCaps,
|
||||||
state::State,
|
state::State,
|
||||||
utils::{errorfmt::ErrorFmt, oserror::OsError, xrd::xrd},
|
utils::{errorfmt::ErrorFmt, oserror::OsError, xrd::xrd},
|
||||||
},
|
},
|
||||||
|
|
@ -145,12 +146,16 @@ impl Acceptor {
|
||||||
}
|
}
|
||||||
let acc = Rc::new(Acceptor { socket });
|
let acc = Rc::new(Acceptor { socket });
|
||||||
let futures = vec![
|
let futures = vec![
|
||||||
state
|
state.eng.spawn(accept(
|
||||||
.eng
|
acc.socket.secure.clone(),
|
||||||
.spawn(accept(acc.socket.secure.clone(), state.clone(), true)),
|
state.clone(),
|
||||||
state
|
ClientCaps::all(),
|
||||||
.eng
|
)),
|
||||||
.spawn(accept(acc.socket.insecure.clone(), state.clone(), false)),
|
state.eng.spawn(accept(
|
||||||
|
acc.socket.insecure.clone(),
|
||||||
|
state.clone(),
|
||||||
|
ClientCaps::none(),
|
||||||
|
)),
|
||||||
];
|
];
|
||||||
state.acceptor.set(Some(acc.clone()));
|
state.acceptor.set(Some(acc.clone()));
|
||||||
Ok((acc, futures))
|
Ok((acc, futures))
|
||||||
|
|
@ -166,7 +171,7 @@ impl Acceptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, secure: bool) {
|
async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, caps: ClientCaps) {
|
||||||
loop {
|
loop {
|
||||||
let fd = match state.ring.accept(&fd, c::SOCK_CLOEXEC).await {
|
let fd = match state.ring.accept(&fd, c::SOCK_CLOEXEC).await {
|
||||||
Ok(fd) => fd,
|
Ok(fd) => fd,
|
||||||
|
|
@ -176,7 +181,7 @@ async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, secure: bool) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let id = state.clients.id();
|
let id = state.clients.id();
|
||||||
if let Err(e) = state.clients.spawn(id, &state, fd, secure) {
|
if let Err(e) = state.clients.spawn(id, &state, fd, caps) {
|
||||||
log::error!("Could not spawn a client: {}", ErrorFmt(e));
|
log::error!("Could not spawn a client: {}", ErrorFmt(e));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,18 @@ mod error;
|
||||||
mod objects;
|
mod objects;
|
||||||
mod tasks;
|
mod tasks;
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
ClientCaps: u32;
|
||||||
|
CAP_DATA_CONTROL_MANAGER = 1 << 0,
|
||||||
|
CAP_VIRTUAL_KEYBOARD_MANAGER = 1 << 1,
|
||||||
|
CAP_FOREIGN_TOPLEVEL_LIST = 1 << 2,
|
||||||
|
CAP_IDLE_NOTIFIER = 1 << 3,
|
||||||
|
CAP_SESSION_LOCK_MANAGER = 1 << 4,
|
||||||
|
CAP_JAY_COMPOSITOR = 1 << 5,
|
||||||
|
CAP_LAYER_SHELL = 1 << 6,
|
||||||
|
CAP_SCREENCOPY_MANAGER = 1 << 7,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
pub struct ClientId(u64);
|
pub struct ClientId(u64);
|
||||||
|
|
||||||
|
|
@ -101,7 +113,7 @@ impl Clients {
|
||||||
id: ClientId,
|
id: ClientId,
|
||||||
global: &Rc<State>,
|
global: &Rc<State>,
|
||||||
socket: Rc<OwnedFd>,
|
socket: Rc<OwnedFd>,
|
||||||
secure: bool,
|
caps: ClientCaps,
|
||||||
) -> Result<(), ClientError> {
|
) -> Result<(), ClientError> {
|
||||||
let (uid, pid) = {
|
let (uid, pid) = {
|
||||||
let mut cred = c::ucred {
|
let mut cred = c::ucred {
|
||||||
|
|
@ -120,7 +132,7 @@ impl Clients {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.spawn2(id, global, socket, uid, pid, secure, false)?;
|
self.spawn2(id, global, socket, uid, pid, caps, false)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +143,7 @@ impl Clients {
|
||||||
socket: Rc<OwnedFd>,
|
socket: Rc<OwnedFd>,
|
||||||
uid: c::uid_t,
|
uid: c::uid_t,
|
||||||
pid: c::pid_t,
|
pid: c::pid_t,
|
||||||
secure: bool,
|
caps: ClientCaps,
|
||||||
is_xwayland: bool,
|
is_xwayland: bool,
|
||||||
) -> Result<Rc<Client>, ClientError> {
|
) -> Result<Rc<Client>, ClientError> {
|
||||||
let data = Rc::new(Client {
|
let data = Rc::new(Client {
|
||||||
|
|
@ -145,7 +157,7 @@ impl Clients {
|
||||||
shutdown: Default::default(),
|
shutdown: Default::default(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
is_xwayland,
|
is_xwayland,
|
||||||
secure,
|
caps,
|
||||||
last_enter_serial: Cell::new(0),
|
last_enter_serial: Cell::new(0),
|
||||||
pid_info: get_pid_info(uid, pid),
|
pid_info: get_pid_info(uid, pid),
|
||||||
serials: Default::default(),
|
serials: Default::default(),
|
||||||
|
|
@ -165,13 +177,13 @@ impl Clients {
|
||||||
data: data.clone(),
|
data: data.clone(),
|
||||||
};
|
};
|
||||||
log::info!(
|
log::info!(
|
||||||
"Client {} connected, pid: {}, uid: {}, fd: {}, secure: {}, comm: {:?}",
|
"Client {} connected, pid: {}, uid: {}, fd: {}, comm: {:?}, caps: {:?}",
|
||||||
id,
|
id,
|
||||||
pid,
|
pid,
|
||||||
uid,
|
uid,
|
||||||
client.data.socket.raw(),
|
client.data.socket.raw(),
|
||||||
secure,
|
|
||||||
data.pid_info.comm,
|
data.pid_info.comm,
|
||||||
|
caps,
|
||||||
);
|
);
|
||||||
self.clients.borrow_mut().insert(client.data.id, client);
|
self.clients.borrow_mut().insert(client.data.id, client);
|
||||||
Ok(data)
|
Ok(data)
|
||||||
|
|
@ -193,13 +205,15 @@ impl Clients {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn broadcast<B>(&self, secure: bool, xwayland_only: bool, mut f: B)
|
pub fn broadcast<B>(&self, required_caps: ClientCaps, xwayland_only: bool, mut f: B)
|
||||||
where
|
where
|
||||||
B: FnMut(&Rc<Client>),
|
B: FnMut(&Rc<Client>),
|
||||||
{
|
{
|
||||||
let clients = self.clients.borrow();
|
let clients = self.clients.borrow();
|
||||||
for client in clients.values() {
|
for client in clients.values() {
|
||||||
if (!secure || client.data.secure) && (!xwayland_only || client.data.is_xwayland) {
|
if client.data.caps.contains(required_caps)
|
||||||
|
&& (!xwayland_only || client.data.is_xwayland)
|
||||||
|
{
|
||||||
f(&client.data);
|
f(&client.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -258,7 +272,7 @@ pub struct Client {
|
||||||
shutdown: AsyncEvent,
|
shutdown: AsyncEvent,
|
||||||
pub tracker: Tracker<Client>,
|
pub tracker: Tracker<Client>,
|
||||||
pub is_xwayland: bool,
|
pub is_xwayland: bool,
|
||||||
pub secure: bool,
|
pub caps: ClientCaps,
|
||||||
pub last_enter_serial: Cell<u32>,
|
pub last_enter_serial: Cell<u32>,
|
||||||
pub pid_info: PidInfo,
|
pub pid_info: PidInfo,
|
||||||
pub serials: RefCell<VecDeque<SerialRange>>,
|
pub serials: RefCell<VecDeque<SerialRange>>,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
client::Client,
|
client::{Client, ClientCaps},
|
||||||
ifs::{
|
ifs::{
|
||||||
ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1Global,
|
ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1Global,
|
||||||
ext_idle_notifier_v1::ExtIdleNotifierV1Global,
|
ext_idle_notifier_v1::ExtIdleNotifierV1Global,
|
||||||
|
|
@ -113,8 +113,8 @@ pub trait Global: GlobalBase {
|
||||||
fn singleton(&self) -> bool;
|
fn singleton(&self) -> bool;
|
||||||
fn version(&self) -> u32;
|
fn version(&self) -> u32;
|
||||||
fn break_loops(&self) {}
|
fn break_loops(&self) {}
|
||||||
fn secure(&self) -> bool {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
false
|
ClientCaps::none()
|
||||||
}
|
}
|
||||||
fn xwayland_only(&self) -> bool {
|
fn xwayland_only(&self) -> bool {
|
||||||
false
|
false
|
||||||
|
|
@ -215,7 +215,7 @@ impl Globals {
|
||||||
|
|
||||||
fn insert(&self, state: &State, global: Rc<dyn Global>) {
|
fn insert(&self, state: &State, global: Rc<dyn Global>) {
|
||||||
self.insert_no_broadcast_(&global);
|
self.insert_no_broadcast_(&global);
|
||||||
self.broadcast(state, global.secure(), global.xwayland_only(), |r| {
|
self.broadcast(state, global.required_caps(), global.xwayland_only(), |r| {
|
||||||
r.send_global(&global)
|
r.send_global(&global)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -223,11 +223,13 @@ impl Globals {
|
||||||
pub fn get(
|
pub fn get(
|
||||||
&self,
|
&self,
|
||||||
name: GlobalName,
|
name: GlobalName,
|
||||||
allow_secure: bool,
|
client_caps: ClientCaps,
|
||||||
allow_xwayland_only: bool,
|
allow_xwayland_only: bool,
|
||||||
) -> Result<Rc<dyn Global>, GlobalsError> {
|
) -> Result<Rc<dyn Global>, GlobalsError> {
|
||||||
let global = self.take(name, false)?;
|
let global = self.take(name, false)?;
|
||||||
if (global.secure() && !allow_secure) || (global.xwayland_only() && !allow_xwayland_only) {
|
if client_caps.not_contains(global.required_caps())
|
||||||
|
|| (global.xwayland_only() && !allow_xwayland_only)
|
||||||
|
{
|
||||||
return Err(GlobalsError::GlobalDoesNotExist(name));
|
return Err(GlobalsError::GlobalDoesNotExist(name));
|
||||||
}
|
}
|
||||||
Ok(global)
|
Ok(global)
|
||||||
|
|
@ -236,7 +238,7 @@ impl Globals {
|
||||||
pub fn remove<T: WaylandGlobal>(&self, state: &State, global: &T) -> Result<(), GlobalsError> {
|
pub fn remove<T: WaylandGlobal>(&self, state: &State, global: &T) -> Result<(), GlobalsError> {
|
||||||
let _global = self.take(global.name(), true)?;
|
let _global = self.take(global.name(), true)?;
|
||||||
global.remove(self);
|
global.remove(self);
|
||||||
self.broadcast(state, global.secure(), global.xwayland_only(), |r| {
|
self.broadcast(state, global.required_caps(), global.xwayland_only(), |r| {
|
||||||
r.send_global_remove(global.name())
|
r.send_global_remove(global.name())
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -247,14 +249,16 @@ impl Globals {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notify_all(&self, registry: &Rc<WlRegistry>) {
|
pub fn notify_all(&self, registry: &Rc<WlRegistry>) {
|
||||||
let secure = registry.client.secure;
|
let caps = registry.client.caps;
|
||||||
let xwayland = registry.client.is_xwayland;
|
let xwayland = registry.client.is_xwayland;
|
||||||
let globals = self.registry.lock();
|
let globals = self.registry.lock();
|
||||||
macro_rules! emit {
|
macro_rules! emit {
|
||||||
($singleton:expr) => {
|
($singleton:expr) => {
|
||||||
for global in globals.values() {
|
for global in globals.values() {
|
||||||
if global.singleton() == $singleton {
|
if global.singleton() == $singleton {
|
||||||
if (secure || !global.secure()) && (xwayland || !global.xwayland_only()) {
|
if caps.contains(global.required_caps())
|
||||||
|
&& (xwayland || !global.xwayland_only())
|
||||||
|
{
|
||||||
registry.send_global(global);
|
registry.send_global(global);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -268,11 +272,11 @@ impl Globals {
|
||||||
fn broadcast<F: Fn(&Rc<WlRegistry>)>(
|
fn broadcast<F: Fn(&Rc<WlRegistry>)>(
|
||||||
&self,
|
&self,
|
||||||
state: &State,
|
state: &State,
|
||||||
secure: bool,
|
required_caps: ClientCaps,
|
||||||
xwayland_only: bool,
|
xwayland_only: bool,
|
||||||
f: F,
|
f: F,
|
||||||
) {
|
) {
|
||||||
state.clients.broadcast(secure, xwayland_only, |c| {
|
state.clients.broadcast(required_caps, xwayland_only, |c| {
|
||||||
let registries = c.lock_registries();
|
let registries = c.lock_registries();
|
||||||
for registry in registries.values() {
|
for registry in registries.values() {
|
||||||
f(registry);
|
f(registry);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientCaps, ClientError, CAP_FOREIGN_TOPLEVEL_LIST},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::{
|
ifs::{
|
||||||
ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
||||||
|
|
@ -145,8 +145,8 @@ impl Global for ExtForeignToplevelListV1Global {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn secure(&self) -> bool {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
true
|
CAP_FOREIGN_TOPLEVEL_LIST
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientCaps, ClientError, CAP_IDLE_NOTIFIER},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::ext_idle_notification_v1::ExtIdleNotificationV1,
|
ifs::ext_idle_notification_v1::ExtIdleNotificationV1,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
|
|
@ -117,8 +117,8 @@ impl Global for ExtIdleNotifierV1Global {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn secure(&self) -> bool {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
true
|
CAP_IDLE_NOTIFIER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientCaps, ClientError, CAP_SESSION_LOCK_MANAGER},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::ext_session_lock_v1::ExtSessionLockV1,
|
ifs::ext_session_lock_v1::ExtSessionLockV1,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
|
|
@ -98,8 +98,8 @@ impl Global for ExtSessionLockManagerV1Global {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn secure(&self) -> bool {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
true
|
CAP_SESSION_LOCK_MANAGER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientCaps, ClientError, CAP_DATA_CONTROL_MANAGER},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::ipc::{
|
ifs::ipc::{
|
||||||
zwlr_data_control_device_v1::{ZwlrDataControlDeviceV1, PRIMARY_SELECTION_SINCE},
|
zwlr_data_control_device_v1::{ZwlrDataControlDeviceV1, PRIMARY_SELECTION_SINCE},
|
||||||
|
|
@ -111,8 +111,8 @@ impl Global for ZwlrDataControlManagerV1Global {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn secure(&self) -> bool {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
true
|
CAP_DATA_CONTROL_MANAGER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
cli::CliLogLevel,
|
cli::CliLogLevel,
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientCaps, ClientError, CAP_JAY_COMPOSITOR},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::{
|
ifs::{
|
||||||
jay_idle::JayIdle,
|
jay_idle::JayIdle,
|
||||||
|
|
@ -68,8 +68,8 @@ impl Global for JayCompositorGlobal {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn secure(&self) -> bool {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
true
|
CAP_JAY_COMPOSITOR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ impl WlRegistryRequestHandler for WlRegistry {
|
||||||
fn bind(&self, bind: Bind, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn bind(&self, bind: Bind, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let name = GlobalName::from_raw(bind.name);
|
let name = GlobalName::from_raw(bind.name);
|
||||||
let globals = &self.client.state.globals;
|
let globals = &self.client.state.globals;
|
||||||
let global = globals.get(name, self.client.secure, self.client.is_xwayland)?;
|
let global = globals.get(name, self.client.caps, self.client.is_xwayland)?;
|
||||||
if global.interface().name() != bind.interface {
|
if global.interface().name() != bind.interface {
|
||||||
return Err(WlRegistryError::InvalidInterface(InterfaceError {
|
return Err(WlRegistryError::InvalidInterface(InterfaceError {
|
||||||
name: global.name(),
|
name: global.name(),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientCaps, ClientError, CAP_VIRTUAL_KEYBOARD_MANAGER},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::wl_seat::zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1,
|
ifs::wl_seat::zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
|
|
@ -61,8 +61,8 @@ impl Global for ZwpVirtualKeyboardManagerV1Global {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn secure(&self) -> bool {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
true
|
CAP_VIRTUAL_KEYBOARD_MANAGER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientCaps, ClientError, CAP_LAYER_SHELL},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::wl_surface::zwlr_layer_surface_v1::{ZwlrLayerSurfaceV1, ZwlrLayerSurfaceV1Error},
|
ifs::wl_surface::zwlr_layer_surface_v1::{ZwlrLayerSurfaceV1, ZwlrLayerSurfaceV1Error},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
|
|
@ -110,8 +110,8 @@ impl Global for ZwlrLayerShellV1Global {
|
||||||
4
|
4
|
||||||
}
|
}
|
||||||
|
|
||||||
fn secure(&self) -> bool {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
true
|
CAP_LAYER_SHELL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientCaps, ClientError, CAP_SCREENCOPY_MANAGER},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
ifs::zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
|
|
@ -59,8 +59,8 @@ impl Global for ZwlrScreencopyManagerV1Global {
|
||||||
3
|
3
|
||||||
}
|
}
|
||||||
|
|
||||||
fn secure(&self) -> bool {
|
fn required_caps(&self) -> ClientCaps {
|
||||||
true
|
CAP_SCREENCOPY_MANAGER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ mod xwm;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::ClientError,
|
client::{ClientCaps, ClientError},
|
||||||
compositor::DISPLAY,
|
compositor::DISPLAY,
|
||||||
forker::{ForkerError, ForkerProxy},
|
forker::{ForkerError, ForkerProxy},
|
||||||
ifs::{
|
ifs::{
|
||||||
|
|
@ -171,7 +171,7 @@ async fn run(
|
||||||
Rc::new(client1),
|
Rc::new(client1),
|
||||||
uapi::getuid(),
|
uapi::getuid(),
|
||||||
pid,
|
pid,
|
||||||
true,
|
ClientCaps::all(),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
let client = match client {
|
let client = match client {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue