Compare commits
4 commits
debug-somm
...
main
Author | SHA1 | Date | |
---|---|---|---|
4dd591c492 | |||
fe9d51ccbe | |||
d133a2faa1 | |||
fd5bbe6915 |
5 changed files with 254 additions and 181 deletions
26
README.md
26
README.md
|
@ -52,6 +52,32 @@ This repo contains an example configuration at `config.toml` that allows a few b
|
||||||
desktop apps to function. It also demonstrates the use of `ask_cmd` and `notify_cmd` by defining filters on clipboard-related
|
desktop apps to function. It also demonstrates the use of `ask_cmd` and `notify_cmd` by defining filters on clipboard-related
|
||||||
requests. Detailed explanation of the configuration format is also contained in the example.
|
requests. Detailed explanation of the configuration format is also contained in the example.
|
||||||
|
|
||||||
|
To launch a program under `wl-mitm`, set its `WAYLAND_DISPLAY` env variable to whatever `listen` is under `[socket]` in `config.toml`.
|
||||||
|
Note that you may want to use another container and pass _only_ the `wl-mitm`'d socket through for proper isolation.
|
||||||
|
|
||||||
|
A Word on Filtering
|
||||||
|
---
|
||||||
|
|
||||||
|
`wl-mitm` gives you a ton of flexibility on filtering. In particular, you are allowed to filter _any_ request on _any_ object
|
||||||
|
in `config.toml`.
|
||||||
|
|
||||||
|
However, please keep in mind that while most requests can be filtered, Wayland (and most of its protocols) is not designed to handle
|
||||||
|
this type of filtering. While a lot of requests can be filtered without consequences, there are a significant number of them that
|
||||||
|
will result in irrecoverable de-sync between the client and the server. For example, _any_ message that creates a new object ID
|
||||||
|
(of the type `new_id`) _will_ result in undefined behavior if filtered.
|
||||||
|
|
||||||
|
`wl-mitm` does provide the ability to _reject_ a request with an explicit error. Unfortunately, errors in Wayland are usually
|
||||||
|
fatal, and clients are not designed to recover from them.
|
||||||
|
|
||||||
|
The most reliable (and the only protocol-compliant) way to prevent a client from using certain features is to block the
|
||||||
|
entire global object where that feature resides. These are usually "manager" objects that live in the global registry,
|
||||||
|
and can be blocked in `allowed_globals` inside `config.toml`. Each extension protocol has to expose _some_ manager object
|
||||||
|
in order for clients to access their functionalities, and thus blocking them there will prevent clients from even knowing
|
||||||
|
their existence. However, globals can't be selectively blocked using `ask_cmd`, because clients usually bind to them as soon
|
||||||
|
as they start.
|
||||||
|
|
||||||
|
Since `notify_cmd` never blocks a request, it is safe to use on _any_ request filter.
|
||||||
|
|
||||||
XWayland
|
XWayland
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -206,10 +206,9 @@ fn handle_interface(
|
||||||
let mut event_opcode = 0;
|
let mut event_opcode = 0;
|
||||||
let mut request_opcode = 0;
|
let mut request_opcode = 0;
|
||||||
|
|
||||||
loop {
|
let mut add_msg = |reader: &mut quick_xml::Reader<&[u8]>,
|
||||||
match reader.read_event().expect("Unable to parse XML file") {
|
e: quick_xml::events::BytesStart<'_>,
|
||||||
Event::Eof => panic!("Unexpected EOF"),
|
is_empty: bool| {
|
||||||
Event::Start(e) => {
|
|
||||||
let start_tag =
|
let start_tag =
|
||||||
str::from_utf8(e.local_name().into_inner()).expect("Unable to parse start tag");
|
str::from_utf8(e.local_name().into_inner()).expect("Unable to parse start tag");
|
||||||
if start_tag == "event" {
|
if start_tag == "event" {
|
||||||
|
@ -221,6 +220,7 @@ fn handle_interface(
|
||||||
WlMsgType::Event,
|
WlMsgType::Event,
|
||||||
interface_name_snake,
|
interface_name_snake,
|
||||||
e,
|
e,
|
||||||
|
is_empty,
|
||||||
));
|
));
|
||||||
} else if start_tag == "request" {
|
} else if start_tag == "request" {
|
||||||
// A request! Increment our opcode tracker for it!
|
// A request! Increment our opcode tracker for it!
|
||||||
|
@ -231,8 +231,19 @@ fn handle_interface(
|
||||||
WlMsgType::Request,
|
WlMsgType::Request,
|
||||||
interface_name_snake,
|
interface_name_snake,
|
||||||
e,
|
e,
|
||||||
|
is_empty,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match reader.read_event().expect("Unable to parse XML file") {
|
||||||
|
Event::Eof => panic!("Unexpected EOF"),
|
||||||
|
Event::Start(e) => {
|
||||||
|
add_msg(reader, e, false);
|
||||||
|
}
|
||||||
|
Event::Empty(e) => {
|
||||||
|
add_msg(reader, e, true);
|
||||||
}
|
}
|
||||||
Event::End(e) if e.local_name() == start.local_name() => break,
|
Event::End(e) if e.local_name() == start.local_name() => break,
|
||||||
_ => continue,
|
_ => continue,
|
||||||
|
@ -251,6 +262,7 @@ fn handle_request_or_event(
|
||||||
msg_type: WlMsgType,
|
msg_type: WlMsgType,
|
||||||
interface_name_snake: &str,
|
interface_name_snake: &str,
|
||||||
start: quick_xml::events::BytesStart<'_>,
|
start: quick_xml::events::BytesStart<'_>,
|
||||||
|
is_empty: bool,
|
||||||
) -> WlMsg {
|
) -> WlMsg {
|
||||||
let name_attr = start
|
let name_attr = start
|
||||||
.attributes()
|
.attributes()
|
||||||
|
@ -278,11 +290,13 @@ fn handle_request_or_event(
|
||||||
// Load arguments and their types from XML
|
// Load arguments and their types from XML
|
||||||
let mut args: Vec<(String, WlArgType)> = Vec::new();
|
let mut args: Vec<(String, WlArgType)> = Vec::new();
|
||||||
|
|
||||||
|
if !is_empty {
|
||||||
loop {
|
loop {
|
||||||
match reader.read_event().expect("Unable to parse XML file") {
|
match reader.read_event().expect("Unable to parse XML file") {
|
||||||
Event::Eof => panic!("Unexpected EOF"),
|
Event::Eof => panic!("Unexpected EOF"),
|
||||||
Event::Empty(e)
|
Event::Empty(e)
|
||||||
if str::from_utf8(e.local_name().into_inner()).expect("utf8 encoding error")
|
if str::from_utf8(e.local_name().into_inner())
|
||||||
|
.expect("utf8 encoding error")
|
||||||
== "arg" =>
|
== "arg" =>
|
||||||
{
|
{
|
||||||
let mut name: Option<String> = None;
|
let mut name: Option<String> = None;
|
||||||
|
@ -351,6 +365,7 @@ fn handle_request_or_event(
|
||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WlMsg {
|
WlMsg {
|
||||||
interface_name_snake: interface_name_snake.to_string(),
|
interface_name_snake: interface_name_snake.to_string(),
|
||||||
|
|
|
@ -192,28 +192,20 @@ impl WlMsg {
|
||||||
#opcode
|
#opcode
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_opcode(&self) -> u16 {
|
|
||||||
#opcode
|
|
||||||
}
|
|
||||||
|
|
||||||
fn object_type() -> crate::objects::WlObjectType {
|
fn object_type() -> crate::objects::WlObjectType {
|
||||||
crate::proto::#interface_name_snake_upper
|
crate::proto::#interface_name_snake_upper
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_object_type(&self) -> crate::objects::WlObjectType {
|
fn msg_name() -> &'static str {
|
||||||
crate::proto::#interface_name_snake_upper
|
|
||||||
}
|
|
||||||
|
|
||||||
fn self_msg_name(&self) -> &'static str {
|
|
||||||
#msg_name_snake
|
#msg_name_snake
|
||||||
}
|
}
|
||||||
|
|
||||||
fn static_type_id() -> std::any::TypeId {
|
fn is_destructor() -> bool {
|
||||||
std::any::TypeId::of::<#struct_name<'static>>()
|
#is_destructor
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_static_type_id(&self) -> std::any::TypeId {
|
fn num_consumed_fds() -> usize {
|
||||||
std::any::TypeId::of::<#struct_name<'static>>()
|
#num_consumed_fds
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused, private_interfaces, non_snake_case)]
|
#[allow(unused, private_interfaces, non_snake_case)]
|
||||||
|
@ -231,28 +223,22 @@ impl WlMsg {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn obj_id(&self) -> u32 {
|
fn _obj_id(&self) -> u32 {
|
||||||
self.obj_id
|
self.obj_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_destructor(&self) -> bool {
|
fn _known_objects_created(&self) -> Option<Vec<(u32, crate::objects::WlObjectType)>> {
|
||||||
#is_destructor
|
|
||||||
}
|
|
||||||
|
|
||||||
fn known_objects_created(&self) -> Option<Vec<(u32, crate::objects::WlObjectType)>> {
|
|
||||||
#known_objects_created
|
#known_objects_created
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_json(&self) -> String {
|
fn _to_json(&self) -> String {
|
||||||
serde_json::to_string(self).unwrap()
|
serde_json::to_string(self).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn num_consumed_fds(&self) -> usize {
|
|
||||||
#num_consumed_fds
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a> crate::proto::AnyWlParsedMessage<'a> for #struct_name<'a> {}
|
unsafe impl<'a> crate::proto::DowncastableWlParsedMessage<'a> for #struct_name<'a> {
|
||||||
|
type Static = #struct_name<'static>;
|
||||||
|
}
|
||||||
|
|
||||||
pub struct #parser_fn_name;
|
pub struct #parser_fn_name;
|
||||||
|
|
||||||
|
@ -261,7 +247,7 @@ impl WlMsg {
|
||||||
&self,
|
&self,
|
||||||
objects: &'obj crate::proto::WlObjects,
|
objects: &'obj crate::proto::WlObjects,
|
||||||
msg: &'msg crate::codec::WlRawMsg,
|
msg: &'msg crate::codec::WlRawMsg,
|
||||||
) -> crate::proto::WaylandProtocolParsingOutcome<Box<dyn crate::proto::AnyWlParsedMessage<'msg> + 'msg>> {
|
) -> crate::proto::WaylandProtocolParsingOutcome<Box<dyn crate::proto::AnyWlParsedMessage + 'msg>> {
|
||||||
#struct_name::try_from_msg(objects, msg).map(|r| Box::new(r) as Box<_>)
|
#struct_name::try_from_msg(objects, msg).map(|r| Box::new(r) as Box<_>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
129
src/proto.rs
129
src/proto.rs
|
@ -35,27 +35,27 @@ impl<T> WaylandProtocolParsingOutcome<T> {
|
||||||
|
|
||||||
/// Internal module used to seal the [WlParsedMessage] trait
|
/// Internal module used to seal the [WlParsedMessage] trait
|
||||||
mod __private {
|
mod __private {
|
||||||
pub(super) trait WlParsedMessagePrivate: Send {}
|
pub(super) trait WlParsedMessagePrivate: Sized {}
|
||||||
pub(super) struct WlParsedMessagePrivateToken;
|
pub(super) struct WlParsedMessagePrivateToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(private_bounds, private_interfaces)]
|
#[allow(private_bounds, private_interfaces)]
|
||||||
pub trait WlParsedMessage<'a>: __private::WlParsedMessagePrivate {
|
pub trait WlParsedMessage<'a>: __private::WlParsedMessagePrivate {
|
||||||
fn opcode() -> u16
|
fn opcode() -> u16;
|
||||||
where
|
fn object_type() -> WlObjectType;
|
||||||
Self: Sized;
|
fn msg_name() -> &'static str;
|
||||||
fn object_type() -> WlObjectType
|
/// Is this request / event a destructor? That is, does it destroy [Self::obj_id()]?
|
||||||
where
|
fn is_destructor() -> bool;
|
||||||
Self: Sized;
|
/// How many fds have been consumed in parsing this message?
|
||||||
fn static_type_id() -> TypeId
|
/// This is used to return any unused fds to the decoder.
|
||||||
where
|
fn num_consumed_fds() -> usize;
|
||||||
Self: Sized;
|
|
||||||
fn try_from_msg<'obj>(
|
fn try_from_msg<'obj>(
|
||||||
objects: &'obj WlObjects,
|
objects: &'obj WlObjects,
|
||||||
msg: &'a WlRawMsg,
|
msg: &'a WlRawMsg,
|
||||||
) -> WaylandProtocolParsingOutcome<Self>
|
) -> WaylandProtocolParsingOutcome<Self>
|
||||||
where
|
where
|
||||||
Self: Sized + 'a,
|
Self: 'a,
|
||||||
{
|
{
|
||||||
// Verify object type and opcode
|
// Verify object type and opcode
|
||||||
if objects.lookup_object(msg.obj_id) != Some(Self::object_type()) {
|
if objects.lookup_object(msg.obj_id) != Some(Self::object_type()) {
|
||||||
|
@ -74,19 +74,10 @@ pub trait WlParsedMessage<'a>: __private::WlParsedMessagePrivate {
|
||||||
_token: __private::WlParsedMessagePrivateToken,
|
_token: __private::WlParsedMessagePrivateToken,
|
||||||
) -> WaylandProtocolParsingOutcome<Self>
|
) -> WaylandProtocolParsingOutcome<Self>
|
||||||
where
|
where
|
||||||
Self: Sized + 'a;
|
Self: 'a;
|
||||||
|
|
||||||
// dyn-available methods
|
|
||||||
fn self_opcode(&self) -> u16;
|
|
||||||
fn self_object_type(&self) -> WlObjectType;
|
|
||||||
fn self_msg_name(&self) -> &'static str;
|
|
||||||
fn self_static_type_id(&self) -> TypeId;
|
|
||||||
|
|
||||||
/// The object ID which this message acts upon
|
/// The object ID which this message acts upon
|
||||||
fn obj_id(&self) -> u32;
|
fn _obj_id(&self) -> u32;
|
||||||
|
|
||||||
/// Is this request / event a destructor? That is, does it destroy [Self::obj_id()]?
|
|
||||||
fn is_destructor(&self) -> bool;
|
|
||||||
|
|
||||||
/// List of (object id, object type) pairs created by this message
|
/// List of (object id, object type) pairs created by this message
|
||||||
/// Note that this only includes objects created with a fixed, known interface
|
/// Note that this only includes objects created with a fixed, known interface
|
||||||
|
@ -94,43 +85,99 @@ pub trait WlParsedMessage<'a>: __private::WlParsedMessagePrivate {
|
||||||
/// serialized differently, and are not included here. However, the only
|
/// serialized differently, and are not included here. However, the only
|
||||||
/// widely-used message with that capability is [WlRegistryBindRequest],
|
/// widely-used message with that capability is [WlRegistryBindRequest],
|
||||||
/// which is already handled separately on its own.
|
/// which is already handled separately on its own.
|
||||||
fn known_objects_created(&self) -> Option<Vec<(u32, WlObjectType)>>;
|
fn _known_objects_created(&self) -> Option<Vec<(u32, WlObjectType)>>;
|
||||||
|
|
||||||
/// Serialize this message into a JSON string, for use with ask scripts
|
/// Serialize this message into a JSON string, for use with ask scripts
|
||||||
fn to_json(&self) -> String;
|
fn _to_json(&self) -> String;
|
||||||
|
|
||||||
/// How many fds have been consumed in parsing this message?
|
|
||||||
/// This is used to return any unused fds to the decoder.
|
|
||||||
fn num_consumed_fds(&self) -> usize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A version of [WlParsedMessage] that supports downcasting. By implementing this
|
/// A version of [WlParsedMessage] that supports downcasting. By implementing this
|
||||||
/// trait, you assert that the [WlParsedMessage::static_type_id] and
|
/// trait, you assert that the [DowncastableWlParsedMessage::Static] MUST correspond
|
||||||
/// [WlParsedMessage::self_static_type_id] implementations are sound: they MUST
|
/// to a version of the implementor type with a static lifetime.
|
||||||
/// return the [TypeId] of the implementing struct, assuming it had static lifetime.
|
|
||||||
///
|
///
|
||||||
/// Any implementor also asserts that the type implementing this trait
|
/// Any implementor also asserts that the type implementing this trait
|
||||||
/// does not contain any lifetime other than 'a, and that the implenetor struct is
|
/// does not contain any lifetime other than 'a, and that the implenetor struct is
|
||||||
/// _covariant_ with respect to lifetime 'a.
|
/// _covariant_ with respect to lifetime 'a.
|
||||||
///
|
///
|
||||||
/// This is required for the soundness of the downcast_ref implementation.
|
/// This is required for the soundness of the downcast_ref implementation.
|
||||||
pub unsafe trait AnyWlParsedMessage<'a>: WlParsedMessage<'a> {}
|
pub unsafe trait DowncastableWlParsedMessage<'a>: Send + WlParsedMessage<'a> {
|
||||||
|
type Static: 'static;
|
||||||
|
}
|
||||||
|
|
||||||
impl<'out, 'data: 'out> dyn AnyWlParsedMessage<'data> + 'data {
|
/// The implementation of dyn-available methods and downcasting for
|
||||||
|
/// [DowncastableWlParsedMessage]
|
||||||
|
pub trait AnyWlParsedMessage: Send {
|
||||||
|
fn static_type_id(&self) -> TypeId;
|
||||||
|
fn opcode(&self) -> u16;
|
||||||
|
fn object_type(&self) -> WlObjectType;
|
||||||
|
fn msg_name(&self) -> &'static str;
|
||||||
|
fn is_destructor(&self) -> bool;
|
||||||
|
fn obj_id(&self) -> u32;
|
||||||
|
fn known_objects_created(&self) -> Option<Vec<(u32, WlObjectType)>>;
|
||||||
|
fn to_json(&self) -> String;
|
||||||
|
fn num_consumed_fds(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> AnyWlParsedMessage for T
|
||||||
|
where
|
||||||
|
T: DowncastableWlParsedMessage<'a> + 'a,
|
||||||
|
{
|
||||||
|
fn static_type_id(&self) -> TypeId {
|
||||||
|
TypeId::of::<T::Static>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opcode(&self) -> u16 {
|
||||||
|
T::opcode()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn object_type(&self) -> WlObjectType {
|
||||||
|
T::object_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn msg_name(&self) -> &'static str {
|
||||||
|
T::msg_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_destructor(&self) -> bool {
|
||||||
|
T::is_destructor()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn obj_id(&self) -> u32 {
|
||||||
|
T::_obj_id(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn known_objects_created(&self) -> Option<Vec<(u32, WlObjectType)>> {
|
||||||
|
T::_known_objects_created(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_json(&self) -> String {
|
||||||
|
T::_to_json(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_consumed_fds(&self) -> usize {
|
||||||
|
T::num_consumed_fds()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'out, 'data: 'out> dyn AnyWlParsedMessage + 'data {
|
||||||
/// Downcast the type-erased, borrowed Wayland message to a concrete type. Note that the
|
/// Downcast the type-erased, borrowed Wayland message to a concrete type. Note that the
|
||||||
/// safety of this relies on a few invariants:
|
/// safety of this relies on a few invariants:
|
||||||
///
|
///
|
||||||
/// 1. 'data outlives 'out (guaranteed by the trait bound above)
|
/// 1. 'data outlives 'out (guaranteed by the trait bound above)
|
||||||
/// 2. The type implementing [AnyWlParsedMessage] does not contain any lifetime other than
|
/// 2. The type implementing [DowncastableWlParsedMessage] does not contain any lifetime other than
|
||||||
/// 'data (or 'a in the trait's definition).
|
/// 'data (or 'a in the trait's definition).
|
||||||
pub fn downcast_ref<T: AnyWlParsedMessage<'data> + 'data>(&'out self) -> Option<&'out T> {
|
pub fn downcast_ref<
|
||||||
if self.self_static_type_id() != T::static_type_id() {
|
T: AnyWlParsedMessage + DowncastableWlParsedMessage<'data> + 'data,
|
||||||
|
>(
|
||||||
|
&'data self,
|
||||||
|
) -> Option<&'out T> {
|
||||||
|
if self.static_type_id() != TypeId::of::<T::Static>() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: We have verified the type IDs match up.
|
// SAFETY: We have verified the type IDs match up.
|
||||||
//
|
//
|
||||||
// In addition, because [AnyWlParsedMessage]'s contract requires that no
|
// In addition, because [DowncastableWlParsedMessage]'s contract requires that no
|
||||||
// lifetime other than 'a ('data) is contained in the implemetor, the
|
// lifetime other than 'a ('data) is contained in the implemetor, the
|
||||||
// output type T cannot contain another lifetime that may be transmuted
|
// output type T cannot contain another lifetime that may be transmuted
|
||||||
// by this unsafe block.
|
// by this unsafe block.
|
||||||
|
@ -148,13 +195,13 @@ pub trait WlMsgParserFn: Send + Sync {
|
||||||
&self,
|
&self,
|
||||||
objects: &'obj WlObjects,
|
objects: &'obj WlObjects,
|
||||||
msg: &'msg WlRawMsg,
|
msg: &'msg WlRawMsg,
|
||||||
) -> WaylandProtocolParsingOutcome<Box<dyn AnyWlParsedMessage<'msg> + 'msg>>;
|
) -> WaylandProtocolParsingOutcome<Box<dyn AnyWlParsedMessage + 'msg>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Messages that can be converted back to [WlRawMsg]
|
/// Messages that can be converted back to [WlRawMsg]
|
||||||
pub trait WlConstructableMessage<'a>: Sized + WlParsedMessage<'a> {
|
pub trait WlConstructableMessage<'a>: Sized + WlParsedMessage<'a> {
|
||||||
fn build(&self) -> WlRawMsg {
|
fn build(&self) -> WlRawMsg {
|
||||||
WlRawMsg::build(self.obj_id(), Self::opcode(), |buf, fds| {
|
WlRawMsg::build(self._obj_id(), Self::opcode(), |buf, fds| {
|
||||||
self.build_inner(buf, fds)
|
self.build_inner(buf, fds)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -187,7 +234,7 @@ static WL_EVENT_REQUEST_PARSERS: LazyLock<(
|
||||||
pub fn decode_event<'obj, 'msg>(
|
pub fn decode_event<'obj, 'msg>(
|
||||||
objects: &'obj WlObjects,
|
objects: &'obj WlObjects,
|
||||||
msg: &'msg WlRawMsg,
|
msg: &'msg WlRawMsg,
|
||||||
) -> WaylandProtocolParsingOutcome<Box<dyn AnyWlParsedMessage<'msg> + 'msg>> {
|
) -> WaylandProtocolParsingOutcome<Box<dyn AnyWlParsedMessage + 'msg>> {
|
||||||
let Some(obj_type) = objects.lookup_object(msg.obj_id) else {
|
let Some(obj_type) = objects.lookup_object(msg.obj_id) else {
|
||||||
return WaylandProtocolParsingOutcome::Unknown;
|
return WaylandProtocolParsingOutcome::Unknown;
|
||||||
};
|
};
|
||||||
|
@ -207,7 +254,7 @@ pub fn decode_event<'obj, 'msg>(
|
||||||
pub fn decode_request<'obj, 'msg>(
|
pub fn decode_request<'obj, 'msg>(
|
||||||
objects: &'obj WlObjects,
|
objects: &'obj WlObjects,
|
||||||
msg: &'msg WlRawMsg,
|
msg: &'msg WlRawMsg,
|
||||||
) -> WaylandProtocolParsingOutcome<Box<dyn AnyWlParsedMessage<'msg> + 'msg>> {
|
) -> WaylandProtocolParsingOutcome<Box<dyn AnyWlParsedMessage + 'msg>> {
|
||||||
let Some(obj_type) = objects.lookup_object(msg.obj_id) else {
|
let Some(obj_type) = objects.lookup_object(msg.obj_id) else {
|
||||||
return WaylandProtocolParsingOutcome::Unknown;
|
return WaylandProtocolParsingOutcome::Unknown;
|
||||||
};
|
};
|
||||||
|
|
55
src/state.rs
55
src/state.rs
|
@ -8,10 +8,9 @@ use crate::{
|
||||||
objects::WlObjects,
|
objects::WlObjects,
|
||||||
proto::{
|
proto::{
|
||||||
AnyWlParsedMessage, WaylandProtocolParsingOutcome, WlDisplayDeleteIdEvent,
|
AnyWlParsedMessage, WaylandProtocolParsingOutcome, WlDisplayDeleteIdEvent,
|
||||||
WlKeyboardEnterEvent, WlParsedMessage, WlPointerEnterEvent, WlRegistryBindRequest,
|
WlKeyboardEnterEvent, WlPointerEnterEvent, WlRegistryBindRequest, WlRegistryGlobalEvent,
|
||||||
WlRegistryGlobalEvent, WlRegistryGlobalRemoveEvent, WlTouchDownEvent,
|
WlRegistryGlobalRemoveEvent, WlTouchDownEvent, XdgSurfaceGetToplevelRequest,
|
||||||
XdgSurfaceGetToplevelRequest, XdgToplevelSetAppIdRequest, XdgToplevelSetTitleRequest,
|
XdgToplevelSetAppIdRequest, XdgToplevelSetTitleRequest, XdgWmBaseGetXdgSurfaceRequest,
|
||||||
XdgWmBaseGetXdgSurfaceRequest,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -118,7 +117,7 @@ impl WlMitmState {
|
||||||
/// is not handled here.
|
/// is not handled here.
|
||||||
fn handle_created_or_destroyed_objects(
|
fn handle_created_or_destroyed_objects(
|
||||||
&mut self,
|
&mut self,
|
||||||
msg: &dyn AnyWlParsedMessage<'_>,
|
msg: &dyn AnyWlParsedMessage,
|
||||||
from_client: bool,
|
from_client: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(created_objects) = msg.known_objects_created() {
|
if let Some(created_objects) = msg.known_objects_created() {
|
||||||
|
@ -133,7 +132,7 @@ impl WlMitmState {
|
||||||
is_half_destroyed = self.objects.is_half_destroyed(id),
|
is_half_destroyed = self.objects.is_half_destroyed(id),
|
||||||
"Trying to create object via message {}::{} but the object ID is already used!",
|
"Trying to create object via message {}::{} but the object ID is already used!",
|
||||||
parent_obj.interface(),
|
parent_obj.interface(),
|
||||||
msg.self_msg_name()
|
msg.msg_name()
|
||||||
);
|
);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -145,7 +144,7 @@ impl WlMitmState {
|
||||||
obj_id = id,
|
obj_id = id,
|
||||||
"Created object via message {}::{}",
|
"Created object via message {}::{}",
|
||||||
parent_obj.interface(),
|
parent_obj.interface(),
|
||||||
msg.self_msg_name()
|
msg.msg_name()
|
||||||
);
|
);
|
||||||
self.objects.record_object(tt, id);
|
self.objects.record_object(tt, id);
|
||||||
}
|
}
|
||||||
|
@ -164,7 +163,7 @@ impl WlMitmState {
|
||||||
obj_id = msg.obj_id(),
|
obj_id = msg.obj_id(),
|
||||||
"Object destructed via destructor {}::{}",
|
"Object destructed via destructor {}::{}",
|
||||||
obj_type.interface(),
|
obj_type.interface(),
|
||||||
msg.self_msg_name()
|
msg.msg_name()
|
||||||
);
|
);
|
||||||
|
|
||||||
self.objects.remove_object(msg.obj_id(), from_client);
|
self.objects.remove_object(msg.obj_id(), from_client);
|
||||||
|
@ -179,13 +178,13 @@ impl WlMitmState {
|
||||||
|
|
||||||
fn prepare_command(
|
fn prepare_command(
|
||||||
&self,
|
&self,
|
||||||
msg: &dyn AnyWlParsedMessage<'_>,
|
msg: &dyn AnyWlParsedMessage,
|
||||||
cmd_str: &str,
|
cmd_str: &str,
|
||||||
desc: &str,
|
desc: &str,
|
||||||
) -> tokio::process::Command {
|
) -> tokio::process::Command {
|
||||||
let mut cmd = tokio::process::Command::new(cmd_str);
|
let mut cmd = tokio::process::Command::new(cmd_str);
|
||||||
cmd.arg(msg.self_object_type().interface());
|
cmd.arg(msg.object_type().interface());
|
||||||
cmd.arg(msg.self_msg_name());
|
cmd.arg(msg.msg_name());
|
||||||
cmd.arg(desc);
|
cmd.arg(desc);
|
||||||
cmd.env("WL_MITM_MSG_JSON", msg.to_json());
|
cmd.env("WL_MITM_MSG_JSON", msg.to_json());
|
||||||
|
|
||||||
|
@ -250,8 +249,8 @@ impl WlMitmState {
|
||||||
num_fds = raw_msg.fds.len(),
|
num_fds = raw_msg.fds.len(),
|
||||||
num_consumed_fds = msg.num_consumed_fds(),
|
num_consumed_fds = msg.num_consumed_fds(),
|
||||||
"{}::{}",
|
"{}::{}",
|
||||||
msg.self_object_type().interface(),
|
msg.object_type().interface(),
|
||||||
msg.self_msg_name(),
|
msg.msg_name(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +259,7 @@ impl WlMitmState {
|
||||||
if self.objects.is_half_destroyed(msg.obj_id()) {
|
if self.objects.is_half_destroyed(msg.obj_id()) {
|
||||||
error!(
|
error!(
|
||||||
obj_id = msg.obj_id(),
|
obj_id = msg.obj_id(),
|
||||||
opcode = msg.self_opcode(),
|
opcode = msg.opcode(),
|
||||||
"Client request detected on object already scheduled for destruction; aborting!"
|
"Client request detected on object already scheduled for destruction; aborting!"
|
||||||
);
|
);
|
||||||
return outcome.terminate();
|
return outcome.terminate();
|
||||||
|
@ -334,11 +333,11 @@ impl WlMitmState {
|
||||||
.config
|
.config
|
||||||
.filter
|
.filter
|
||||||
.requests
|
.requests
|
||||||
.get(msg.self_object_type().interface())
|
.get(msg.object_type().interface())
|
||||||
{
|
{
|
||||||
if let Some(filtered) = filtered_requests
|
if let Some(filtered) = filtered_requests
|
||||||
.iter()
|
.iter()
|
||||||
.find(|f| f.requests.contains(msg.self_msg_name()))
|
.find(|f| f.requests.contains(msg.msg_name()))
|
||||||
{
|
{
|
||||||
match filtered.action {
|
match filtered.action {
|
||||||
WlFilterRequestAction::Ask => {
|
WlFilterRequestAction::Ask => {
|
||||||
|
@ -346,8 +345,8 @@ impl WlMitmState {
|
||||||
info!(
|
info!(
|
||||||
ask_cmd = ask_cmd,
|
ask_cmd = ask_cmd,
|
||||||
"Running ask command for {}::{}",
|
"Running ask command for {}::{}",
|
||||||
msg.self_object_type().interface(),
|
msg.object_type().interface(),
|
||||||
msg.self_msg_name()
|
msg.msg_name()
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cmd = self.prepare_command(
|
let mut cmd = self.prepare_command(
|
||||||
|
@ -360,8 +359,8 @@ impl WlMitmState {
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
warn!(
|
warn!(
|
||||||
"Blocked {}::{} because of return status {}",
|
"Blocked {}::{} because of return status {}",
|
||||||
msg.self_object_type().interface(),
|
msg.object_type().interface(),
|
||||||
msg.self_msg_name(),
|
msg.msg_name(),
|
||||||
status
|
status
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -379,8 +378,8 @@ impl WlMitmState {
|
||||||
|
|
||||||
warn!(
|
warn!(
|
||||||
"Blocked {}::{} because of missing ask_cmd",
|
"Blocked {}::{} because of missing ask_cmd",
|
||||||
msg.self_object_type().interface(),
|
msg.object_type().interface(),
|
||||||
msg.self_msg_name()
|
msg.msg_name()
|
||||||
);
|
);
|
||||||
return match filtered.block_type {
|
return match filtered.block_type {
|
||||||
WlFilterRequestBlockType::Ignore => outcome.filtered(),
|
WlFilterRequestBlockType::Ignore => outcome.filtered(),
|
||||||
|
@ -394,8 +393,8 @@ impl WlMitmState {
|
||||||
info!(
|
info!(
|
||||||
notify_cmd = notify_cmd,
|
notify_cmd = notify_cmd,
|
||||||
"Running notify command for {}::{}",
|
"Running notify command for {}::{}",
|
||||||
msg.self_object_type().interface(),
|
msg.object_type().interface(),
|
||||||
msg.self_msg_name()
|
msg.msg_name()
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cmd = self.prepare_command(
|
let mut cmd = self.prepare_command(
|
||||||
|
@ -410,8 +409,8 @@ impl WlMitmState {
|
||||||
WlFilterRequestAction::Block => {
|
WlFilterRequestAction::Block => {
|
||||||
warn!(
|
warn!(
|
||||||
"Blocked {}::{}",
|
"Blocked {}::{}",
|
||||||
msg.self_object_type().interface(),
|
msg.object_type().interface(),
|
||||||
msg.self_msg_name()
|
msg.msg_name()
|
||||||
);
|
);
|
||||||
return match filtered.block_type {
|
return match filtered.block_type {
|
||||||
WlFilterRequestBlockType::Ignore => outcome.filtered(),
|
WlFilterRequestBlockType::Ignore => outcome.filtered(),
|
||||||
|
@ -458,8 +457,8 @@ impl WlMitmState {
|
||||||
num_fds = raw_msg.fds.len(),
|
num_fds = raw_msg.fds.len(),
|
||||||
num_consumed_fds = msg.num_consumed_fds(),
|
num_consumed_fds = msg.num_consumed_fds(),
|
||||||
"{}::{}",
|
"{}::{}",
|
||||||
msg.self_object_type().interface(),
|
msg.object_type().interface(),
|
||||||
msg.self_msg_name(),
|
msg.msg_name(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue