wayland: implement wp-security-manager-v1
This commit is contained in:
parent
886339ff96
commit
1fceffe235
16 changed files with 417 additions and 11 deletions
|
|
@ -141,6 +141,7 @@ Jay supports the following wayland protocols:
|
||||||
| wp_fractional_scale_manager_v1 | 1 | |
|
| wp_fractional_scale_manager_v1 | 1 | |
|
||||||
| wp_linux_drm_syncobj_manager_v1 | 1 | |
|
| wp_linux_drm_syncobj_manager_v1 | 1 | |
|
||||||
| wp_presentation | 1 | |
|
| wp_presentation | 1 | |
|
||||||
|
| wp_security_context_manager_v1 | 1 | |
|
||||||
| wp_single_pixel_buffer_manager_v1 | 1 | |
|
| wp_single_pixel_buffer_manager_v1 | 1 | |
|
||||||
| wp_tearing_control_manager_v1 | 1[^no_tearing] | |
|
| wp_tearing_control_manager_v1 | 1[^no_tearing] | |
|
||||||
| wp_viewporter | 1 | |
|
| wp_viewporter | 1 | |
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- Add support for wp-security-manager-v1.
|
||||||
|
|
||||||
# 1.1.0 (2024-04-22)
|
# 1.1.0 (2024-04-22)
|
||||||
|
|
||||||
- Screencasts now support window capture.
|
- Screencasts now support window capture.
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ impl Acceptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, caps: ClientCaps) {
|
async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, effective_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,
|
||||||
|
|
@ -181,7 +181,10 @@ async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, caps: ClientCaps) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let id = state.clients.id();
|
let id = state.clients.id();
|
||||||
if let Err(e) = state.clients.spawn(id, &state, fd, caps) {
|
if let Err(e) = state
|
||||||
|
.clients
|
||||||
|
.spawn(id, &state, fd, effective_caps, ClientCaps::all())
|
||||||
|
{
|
||||||
log::error!("Could not spawn a client: {}", ErrorFmt(e));
|
log::error!("Could not spawn a client: {}", ErrorFmt(e));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,8 @@ impl Clients {
|
||||||
id: ClientId,
|
id: ClientId,
|
||||||
global: &Rc<State>,
|
global: &Rc<State>,
|
||||||
socket: Rc<OwnedFd>,
|
socket: Rc<OwnedFd>,
|
||||||
caps: ClientCaps,
|
effective_caps: ClientCaps,
|
||||||
|
bounding_caps: ClientCaps,
|
||||||
) -> Result<(), ClientError> {
|
) -> Result<(), ClientError> {
|
||||||
let (uid, pid) = {
|
let (uid, pid) = {
|
||||||
let mut cred = c::ucred {
|
let mut cred = c::ucred {
|
||||||
|
|
@ -132,7 +133,16 @@ impl Clients {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.spawn2(id, global, socket, uid, pid, caps, false)?;
|
self.spawn2(
|
||||||
|
id,
|
||||||
|
global,
|
||||||
|
socket,
|
||||||
|
uid,
|
||||||
|
pid,
|
||||||
|
effective_caps,
|
||||||
|
bounding_caps,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,7 +153,8 @@ impl Clients {
|
||||||
socket: Rc<OwnedFd>,
|
socket: Rc<OwnedFd>,
|
||||||
uid: c::uid_t,
|
uid: c::uid_t,
|
||||||
pid: c::pid_t,
|
pid: c::pid_t,
|
||||||
caps: ClientCaps,
|
effective_caps: ClientCaps,
|
||||||
|
bounding_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 {
|
||||||
|
|
@ -157,7 +168,8 @@ impl Clients {
|
||||||
shutdown: Default::default(),
|
shutdown: Default::default(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
is_xwayland,
|
is_xwayland,
|
||||||
caps,
|
effective_caps,
|
||||||
|
bounding_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(),
|
||||||
|
|
@ -183,7 +195,7 @@ impl Clients {
|
||||||
uid,
|
uid,
|
||||||
client.data.socket.raw(),
|
client.data.socket.raw(),
|
||||||
data.pid_info.comm,
|
data.pid_info.comm,
|
||||||
caps,
|
effective_caps,
|
||||||
);
|
);
|
||||||
self.clients.borrow_mut().insert(client.data.id, client);
|
self.clients.borrow_mut().insert(client.data.id, client);
|
||||||
Ok(data)
|
Ok(data)
|
||||||
|
|
@ -211,7 +223,7 @@ impl Clients {
|
||||||
{
|
{
|
||||||
let clients = self.clients.borrow();
|
let clients = self.clients.borrow();
|
||||||
for client in clients.values() {
|
for client in clients.values() {
|
||||||
if client.data.caps.contains(required_caps)
|
if client.data.effective_caps.contains(required_caps)
|
||||||
&& (!xwayland_only || client.data.is_xwayland)
|
&& (!xwayland_only || client.data.is_xwayland)
|
||||||
{
|
{
|
||||||
f(&client.data);
|
f(&client.data);
|
||||||
|
|
@ -272,7 +284,8 @@ pub struct Client {
|
||||||
shutdown: AsyncEvent,
|
shutdown: AsyncEvent,
|
||||||
pub tracker: Tracker<Client>,
|
pub tracker: Tracker<Client>,
|
||||||
pub is_xwayland: bool,
|
pub is_xwayland: bool,
|
||||||
pub caps: ClientCaps,
|
pub effective_caps: ClientCaps,
|
||||||
|
pub bounding_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>>,
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,7 @@ fn start_compositor2(
|
||||||
wait_for_sync_obj: Rc::new(WaitForSyncObj::new(&ring, &engine)),
|
wait_for_sync_obj: Rc::new(WaitForSyncObj::new(&ring, &engine)),
|
||||||
explicit_sync_enabled: Cell::new(true),
|
explicit_sync_enabled: Cell::new(true),
|
||||||
keyboard_state_ids: Default::default(),
|
keyboard_state_ids: Default::default(),
|
||||||
|
security_context_acceptors: Default::default(),
|
||||||
});
|
});
|
||||||
state.tracker.register(ClientId::from_raw(0));
|
state.tracker.register(ClientId::from_raw(0));
|
||||||
create_dummy_output(&state);
|
create_dummy_output(&state);
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ use {
|
||||||
wp_cursor_shape_manager_v1::WpCursorShapeManagerV1Global,
|
wp_cursor_shape_manager_v1::WpCursorShapeManagerV1Global,
|
||||||
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global,
|
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global,
|
||||||
wp_presentation::WpPresentationGlobal,
|
wp_presentation::WpPresentationGlobal,
|
||||||
|
wp_security_context_manager_v1::WpSecurityContextManagerV1Global,
|
||||||
wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1Global,
|
wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1Global,
|
||||||
wp_tearing_control_manager_v1::WpTearingControlManagerV1Global,
|
wp_tearing_control_manager_v1::WpTearingControlManagerV1Global,
|
||||||
wp_viewporter::WpViewporterGlobal,
|
wp_viewporter::WpViewporterGlobal,
|
||||||
|
|
@ -184,6 +185,7 @@ impl Globals {
|
||||||
add_singleton!(ZwpVirtualKeyboardManagerV1Global);
|
add_singleton!(ZwpVirtualKeyboardManagerV1Global);
|
||||||
add_singleton!(ZwpInputMethodManagerV2Global);
|
add_singleton!(ZwpInputMethodManagerV2Global);
|
||||||
add_singleton!(ZwpTextInputManagerV3Global);
|
add_singleton!(ZwpTextInputManagerV3Global);
|
||||||
|
add_singleton!(WpSecurityContextManagerV1Global);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
|
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
|
||||||
|
|
@ -249,7 +251,7 @@ impl Globals {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notify_all(&self, registry: &Rc<WlRegistry>) {
|
pub fn notify_all(&self, registry: &Rc<WlRegistry>) {
|
||||||
let caps = registry.client.caps;
|
let caps = registry.client.effective_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 {
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ pub mod wp_linux_drm_syncobj_manager_v1;
|
||||||
pub mod wp_linux_drm_syncobj_timeline_v1;
|
pub mod wp_linux_drm_syncobj_timeline_v1;
|
||||||
pub mod wp_presentation;
|
pub mod wp_presentation;
|
||||||
pub mod wp_presentation_feedback;
|
pub mod wp_presentation_feedback;
|
||||||
|
pub mod wp_security_context_manager_v1;
|
||||||
|
pub mod wp_security_context_v1;
|
||||||
pub mod wp_single_pixel_buffer_manager_v1;
|
pub mod wp_single_pixel_buffer_manager_v1;
|
||||||
pub mod wp_tearing_control_manager_v1;
|
pub mod wp_tearing_control_manager_v1;
|
||||||
pub mod wp_viewporter;
|
pub mod wp_viewporter;
|
||||||
|
|
|
||||||
|
|
@ -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.caps, self.client.is_xwayland)?;
|
let global = globals.get(name, self.client.effective_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(),
|
||||||
|
|
|
||||||
107
src/ifs/wp_security_context_manager_v1.rs
Normal file
107
src/ifs/wp_security_context_manager_v1.rs
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientError},
|
||||||
|
globals::{Global, GlobalName},
|
||||||
|
ifs::wp_security_context_v1::WpSecurityContextV1,
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
wire::{wp_security_context_manager_v1::*, WpSecurityContextManagerV1Id},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct WpSecurityContextManagerV1Global {
|
||||||
|
pub name: GlobalName,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpSecurityContextManagerV1Global {
|
||||||
|
pub fn new(name: GlobalName) -> Self {
|
||||||
|
Self { name }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_(
|
||||||
|
self: Rc<Self>,
|
||||||
|
id: WpSecurityContextManagerV1Id,
|
||||||
|
client: &Rc<Client>,
|
||||||
|
version: Version,
|
||||||
|
) -> Result<(), WpSecurityContextManagerV1Error> {
|
||||||
|
let obj = Rc::new(WpSecurityContextManagerV1 {
|
||||||
|
id,
|
||||||
|
client: client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version,
|
||||||
|
});
|
||||||
|
track!(client, obj);
|
||||||
|
client.add_client_obj(&obj)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global_base!(
|
||||||
|
WpSecurityContextManagerV1Global,
|
||||||
|
WpSecurityContextManagerV1,
|
||||||
|
WpSecurityContextManagerV1Error
|
||||||
|
);
|
||||||
|
|
||||||
|
impl Global for WpSecurityContextManagerV1Global {
|
||||||
|
fn singleton(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_add_global!(WpSecurityContextManagerV1Global);
|
||||||
|
|
||||||
|
pub struct WpSecurityContextManagerV1 {
|
||||||
|
pub id: WpSecurityContextManagerV1Id,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpSecurityContextManagerV1RequestHandler for WpSecurityContextManagerV1 {
|
||||||
|
type Error = WpSecurityContextManagerV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_listener(&self, req: CreateListener, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let obj = Rc::new(WpSecurityContextV1 {
|
||||||
|
id: req.id,
|
||||||
|
client: self.client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
listen_fd: req.listen_fd,
|
||||||
|
close_fd: req.close_fd,
|
||||||
|
sandbox_engine: Default::default(),
|
||||||
|
app_id: Default::default(),
|
||||||
|
instance_id: Default::default(),
|
||||||
|
committed: Default::default(),
|
||||||
|
});
|
||||||
|
track!(self.client, obj);
|
||||||
|
self.client.add_client_obj(&obj)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = WpSecurityContextManagerV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for WpSecurityContextManagerV1 {}
|
||||||
|
|
||||||
|
simple_add_obj!(WpSecurityContextManagerV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum WpSecurityContextManagerV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
}
|
||||||
|
efrom!(WpSecurityContextManagerV1Error, ClientError);
|
||||||
119
src/ifs/wp_security_context_v1.rs
Normal file
119
src/ifs/wp_security_context_v1.rs
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientCaps, ClientError},
|
||||||
|
leaks::Tracker,
|
||||||
|
object::{Object, Version},
|
||||||
|
wire::{wp_security_context_v1::*, WpSecurityContextV1Id},
|
||||||
|
},
|
||||||
|
std::{
|
||||||
|
cell::{Cell, RefCell},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
thiserror::Error,
|
||||||
|
uapi::OwnedFd,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct WpSecurityContextV1 {
|
||||||
|
pub id: WpSecurityContextV1Id,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
pub version: Version,
|
||||||
|
pub listen_fd: Rc<OwnedFd>,
|
||||||
|
pub close_fd: Rc<OwnedFd>,
|
||||||
|
pub sandbox_engine: RefCell<Option<String>>,
|
||||||
|
pub app_id: RefCell<Option<String>>,
|
||||||
|
pub instance_id: RefCell<Option<String>>,
|
||||||
|
pub committed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpSecurityContextV1 {
|
||||||
|
fn check_committed(&self) -> Result<(), WpSecurityContextV1Error> {
|
||||||
|
if self.committed.get() {
|
||||||
|
return Err(WpSecurityContextV1Error::Committed);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpSecurityContextV1RequestHandler for WpSecurityContextV1 {
|
||||||
|
type Error = WpSecurityContextV1Error;
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_sandbox_engine(
|
||||||
|
&self,
|
||||||
|
req: SetSandboxEngine<'_>,
|
||||||
|
_slf: &Rc<Self>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
self.check_committed()?;
|
||||||
|
let val = &mut *self.sandbox_engine.borrow_mut();
|
||||||
|
if val.is_some() {
|
||||||
|
return Err(WpSecurityContextV1Error::EnginSet);
|
||||||
|
}
|
||||||
|
*val = Some(req.name.to_string());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_app_id(&self, req: SetAppId<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.check_committed()?;
|
||||||
|
let val = &mut *self.app_id.borrow_mut();
|
||||||
|
if val.is_some() {
|
||||||
|
return Err(WpSecurityContextV1Error::AppSet);
|
||||||
|
}
|
||||||
|
*val = Some(req.app_id.to_string());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_instance_id(&self, req: SetInstanceId<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.check_committed()?;
|
||||||
|
let val = &mut *self.instance_id.borrow_mut();
|
||||||
|
if val.is_some() {
|
||||||
|
return Err(WpSecurityContextV1Error::InstanceSet);
|
||||||
|
}
|
||||||
|
*val = Some(req.instance_id.to_string());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn commit(&self, _req: Commit, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.check_committed()?;
|
||||||
|
self.committed.set(true);
|
||||||
|
let caps = ClientCaps::none() & self.client.bounding_caps;
|
||||||
|
self.client.state.security_context_acceptors.spawn(
|
||||||
|
&self.client.state,
|
||||||
|
self.sandbox_engine.take(),
|
||||||
|
self.app_id.take(),
|
||||||
|
self.instance_id.take(),
|
||||||
|
&self.listen_fd,
|
||||||
|
&self.close_fd,
|
||||||
|
caps,
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = WpSecurityContextV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for WpSecurityContextV1 {}
|
||||||
|
|
||||||
|
simple_add_obj!(WpSecurityContextV1);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum WpSecurityContextV1Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
#[error("The sandbox engine has already been set")]
|
||||||
|
EnginSet,
|
||||||
|
#[error("The app id has already been set")]
|
||||||
|
AppSet,
|
||||||
|
#[error("The instance id has already been set")]
|
||||||
|
InstanceSet,
|
||||||
|
#[error("The context has already been committed")]
|
||||||
|
Committed,
|
||||||
|
}
|
||||||
|
efrom!(WpSecurityContextV1Error, ClientError);
|
||||||
|
|
@ -76,6 +76,7 @@ mod rect;
|
||||||
mod renderer;
|
mod renderer;
|
||||||
mod scale;
|
mod scale;
|
||||||
mod screenshoter;
|
mod screenshoter;
|
||||||
|
mod security_context_acceptor;
|
||||||
mod sighand;
|
mod sighand;
|
||||||
mod state;
|
mod state;
|
||||||
mod tasks;
|
mod tasks;
|
||||||
|
|
|
||||||
123
src/security_context_acceptor.rs
Normal file
123
src/security_context_acceptor.rs
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
async_engine::SpawnedFuture,
|
||||||
|
client::ClientCaps,
|
||||||
|
state::State,
|
||||||
|
utils::{copyhashmap::CopyHashMap, errorfmt::ErrorFmt},
|
||||||
|
},
|
||||||
|
std::{
|
||||||
|
cell::Cell,
|
||||||
|
fmt::{Display, Formatter},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
uapi::{c, OwnedFd},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SecurityContextAcceptors {
|
||||||
|
ids: AcceptorIds,
|
||||||
|
acceptors: CopyHashMap<AcceptorId, Rc<Acceptor>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
linear_ids!(AcceptorIds, AcceptorId, u64);
|
||||||
|
|
||||||
|
struct Acceptor {
|
||||||
|
id: AcceptorId,
|
||||||
|
state: Rc<State>,
|
||||||
|
sandbox_engine: Option<String>,
|
||||||
|
app_id: Option<String>,
|
||||||
|
instance_id: Option<String>,
|
||||||
|
listen_fd: Rc<OwnedFd>,
|
||||||
|
close_fd: Rc<OwnedFd>,
|
||||||
|
caps: ClientCaps,
|
||||||
|
listen_future: Cell<Option<SpawnedFuture<()>>>,
|
||||||
|
close_future: Cell<Option<SpawnedFuture<()>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SecurityContextAcceptors {
|
||||||
|
pub fn clear(&self) {
|
||||||
|
for (_, acceptor) in self.acceptors.lock().drain() {
|
||||||
|
acceptor.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn(
|
||||||
|
&self,
|
||||||
|
state: &Rc<State>,
|
||||||
|
sandbox_engine: Option<String>,
|
||||||
|
app_id: Option<String>,
|
||||||
|
instance_id: Option<String>,
|
||||||
|
listen_fd: &Rc<OwnedFd>,
|
||||||
|
close_fd: &Rc<OwnedFd>,
|
||||||
|
caps: ClientCaps,
|
||||||
|
) {
|
||||||
|
let acceptor = Rc::new(Acceptor {
|
||||||
|
id: self.ids.next(),
|
||||||
|
state: state.clone(),
|
||||||
|
sandbox_engine,
|
||||||
|
app_id,
|
||||||
|
instance_id,
|
||||||
|
listen_fd: listen_fd.clone(),
|
||||||
|
close_fd: close_fd.clone(),
|
||||||
|
caps,
|
||||||
|
listen_future: Cell::new(None),
|
||||||
|
close_future: Cell::new(None),
|
||||||
|
});
|
||||||
|
log::info!("Creating security acceptor {acceptor}");
|
||||||
|
acceptor
|
||||||
|
.listen_future
|
||||||
|
.set(Some(state.eng.spawn(acceptor.clone().accept())));
|
||||||
|
acceptor
|
||||||
|
.close_future
|
||||||
|
.set(Some(state.eng.spawn(acceptor.clone().close())));
|
||||||
|
self.acceptors.set(acceptor.id, acceptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Acceptor {
|
||||||
|
fn kill(&self) {
|
||||||
|
log::info!("Destroying security acceptor {self}");
|
||||||
|
self.listen_future.take();
|
||||||
|
self.close_future.take();
|
||||||
|
self.state
|
||||||
|
.security_context_acceptors
|
||||||
|
.acceptors
|
||||||
|
.remove(&self.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn accept(self: Rc<Self>) {
|
||||||
|
let s = &self.state;
|
||||||
|
loop {
|
||||||
|
let fd = match s.ring.accept(&self.listen_fd, c::SOCK_CLOEXEC).await {
|
||||||
|
Ok(fd) => fd,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not accept a client: {}", ErrorFmt(e));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let id = s.clients.id();
|
||||||
|
if let Err(e) = s.clients.spawn(id, s, fd, self.caps, self.caps) {
|
||||||
|
log::error!("Could not spawn a client: {}", ErrorFmt(e));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn close(self: Rc<Self>) {
|
||||||
|
let _ = self.state.ring.poll(&self.close_fd, 0).await;
|
||||||
|
self.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Acceptor {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}/{}/{}",
|
||||||
|
self.sandbox_engine.as_deref().unwrap_or(""),
|
||||||
|
self.app_id.as_deref().unwrap_or(""),
|
||||||
|
self.instance_id.as_deref().unwrap_or(""),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -51,6 +51,7 @@ use {
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
renderer::{RenderResult, Renderer},
|
renderer::{RenderResult, Renderer},
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
|
security_context_acceptor::SecurityContextAcceptors,
|
||||||
theme::{Color, Theme},
|
theme::{Color, Theme},
|
||||||
tree::{
|
tree::{
|
||||||
ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, Node, NodeIds,
|
ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, Node, NodeIds,
|
||||||
|
|
@ -181,6 +182,7 @@ pub struct State {
|
||||||
pub wait_for_sync_obj: Rc<WaitForSyncObj>,
|
pub wait_for_sync_obj: Rc<WaitForSyncObj>,
|
||||||
pub explicit_sync_enabled: Cell<bool>,
|
pub explicit_sync_enabled: Cell<bool>,
|
||||||
pub keyboard_state_ids: KeyboardStateIds,
|
pub keyboard_state_ids: KeyboardStateIds,
|
||||||
|
pub security_context_acceptors: SecurityContextAcceptors,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Drop for State {
|
// impl Drop for State {
|
||||||
|
|
@ -744,6 +746,7 @@ impl State {
|
||||||
self.render_ctx_watchers.clear();
|
self.render_ctx_watchers.clear();
|
||||||
self.workspace_watchers.clear();
|
self.workspace_watchers.clear();
|
||||||
self.toplevel_lists.clear();
|
self.toplevel_lists.clear();
|
||||||
|
self.security_context_acceptors.clear();
|
||||||
self.slow_clients.clear();
|
self.slow_clients.clear();
|
||||||
for (_, h) in self.input_device_handlers.borrow_mut().drain() {
|
for (_, h) in self.input_device_handlers.borrow_mut().drain() {
|
||||||
h.async_event.clear();
|
h.async_event.clear();
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,7 @@ async fn run(
|
||||||
uapi::getuid(),
|
uapi::getuid(),
|
||||||
pid,
|
pid,
|
||||||
ClientCaps::all(),
|
ClientCaps::all(),
|
||||||
|
ClientCaps::all(),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
let client = match client {
|
let client = match client {
|
||||||
|
|
|
||||||
9
wire/wp_security_context_manager_v1.txt
Normal file
9
wire/wp_security_context_manager_v1.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
request destroy {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request create_listener {
|
||||||
|
id: id(wp_security_context_v1),
|
||||||
|
listen_fd: fd,
|
||||||
|
close_fd: fd,
|
||||||
|
}
|
||||||
19
wire/wp_security_context_v1.txt
Normal file
19
wire/wp_security_context_v1.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
request destroy {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_sandbox_engine {
|
||||||
|
name: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_app_id {
|
||||||
|
app_id: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
request set_instance_id {
|
||||||
|
instance_id: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
request commit {
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue