Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SharedDirectoryDeleteRequest and SharedDirectoryDeleteResponse #34051

Merged
merged 12 commits into from
Nov 18, 2023
51 changes: 45 additions & 6 deletions lib/srv/desktop/rdp/rdpclient/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ use crate::{
handle_fastpath_pdu, handle_rdp_channel_ids, handle_remote_copy, ssl, CGOErrCode,
CGOKeyboardEvent, CGOMousePointerEvent, CGOPointerButton, CGOPointerWheel, CgoHandle,
};
use bitflags::Flags;
#[cfg(feature = "fips")]
use boring::error::ErrorStack;
use bytes::BytesMut;
Expand Down Expand Up @@ -333,6 +332,10 @@ impl Client {
Client::handle_tdp_sd_create_response(x224_processor.clone(), res)
.await?;
}
ClientFunction::HandleTdpSdDeleteResponse(res) => {
Client::handle_tdp_sd_delete_response(x224_processor.clone(), res)
.await?;
}
ClientFunction::WriteCliprdr(f) => {
Client::write_cliprdr(x224_processor.clone(), &mut write_stream, f)
.await?;
Expand Down Expand Up @@ -534,18 +537,29 @@ impl Client {
.await?
}

async fn handle_tdp_sd_delete_response(
x224_processor: Arc<Mutex<X224Processor>>,
res: tdp::SharedDirectoryDeleteResponse,
) -> ClientResult<()> {
global::TOKIO_RT
.spawn_blocking(move || {
debug!("received tdp: {:?}", res);
let mut x224_processor = Self::x224_lock(&x224_processor)?;
let rdpdr = Self::rdpdr_backend(&mut x224_processor)?;
rdpdr.handle_tdp_sd_delete_response(res)?;
Ok(())
})
.await?
}

async fn add_drive(
x224_processor: Arc<Mutex<X224Processor>>,
sda: tdp::SharedDirectoryAnnounce,
) -> ClientResult<ClientDeviceListAnnounce> {
global::TOKIO_RT
.spawn_blocking(move || {
let mut x224_processor = Self::x224_lock(&x224_processor)?;
let rdpdr = x224_processor.get_svc_processor_mut::<Rdpdr>().ok_or(
ClientError::InternalError(
"get_svc_processor_mut::<Rdpdr>() returned None".to_string(),
),
)?;
let rdpdr = Self::get_svc_processor_mut::<Rdpdr>(&mut x224_processor)?;
let pdu = rdpdr.add_drive(sda.directory_id, sda.name);
Ok(pdu)
})
Expand Down Expand Up @@ -617,6 +631,29 @@ impl Client {
)))
}

/// Returns a mutable reference to the [`StaticVirtualChannelProcessor`] of type `S`.
///
/// # Example
///
/// ```
/// let mut x224_processor = Self::x224_lock(&x224_processor)?;
/// let cliprdr = Self::get_svc_processor_mut::<Cliprdr>(&mut x224_processor)?;
/// // Now we can call mutating methods on the Cliprdr processor.
/// ```
fn get_svc_processor_mut<'a, S>(
x224_processor: &'a mut MutexGuard<'_, X224Processor>,
) -> Result<&'a mut S, ClientError>
where
S: StaticVirtualChannelProcessor + 'static,
{
x224_processor
.get_svc_processor_mut::<S>()
.ok_or(ClientError::InternalError(format!(
"get_svc_processor_mut::<{}>() returned None",
std::any::type_name::<S>(),
)))
}

/// Returns a mutable reference to the [`TeleportCliprdrBackend`] of the [`Cliprdr`] processor.
fn cliprdr_backend(
x224_processor: &mut X224Processor,
Expand Down Expand Up @@ -667,6 +704,8 @@ pub enum ClientFunction {
HandleTdpSdInfoResponse(tdp::SharedDirectoryInfoResponse),
/// Corresponds to [`Client::handle_tdp_sd_create_response`]
HandleTdpSdCreateResponse(tdp::SharedDirectoryCreateResponse),
/// Corresponds to [`Client::handle_tdp_sd_delete_response`]
HandleTdpSdDeleteResponse(tdp::SharedDirectoryDeleteResponse),
/// Corresponds to [`Client::write_cliprdr`]
WriteCliprdr(Box<dyn ClipboardFn>),
/// Corresponds to [`Client::update_clipboard`]
Expand Down
3 changes: 1 addition & 2 deletions lib/srv/desktop/rdp/rdpclient/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,7 @@ pub unsafe extern "C" fn client_handle_tdp_sd_delete_response(
cgo_handle: CgoHandle,
res: CGOSharedDirectoryDeleteResponse,
) -> CGOErrCode {
warn!("unimplemented: client_handle_tdp_sd_delete_response");
CGOErrCode::ErrCodeSuccess
call_function_on_handle(cgo_handle, ClientFunction::HandleTdpSdDeleteResponse(res))
}

/// client_handle_tdp_sd_list_response handles a TDP Shared Directory List Response message.
Expand Down
16 changes: 15 additions & 1 deletion lib/srv/desktop/rdp/rdpclient/src/rdpdr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ pub(crate) mod tdp;

use self::filesystem::FilesystemBackend;
use self::scard::ScardBackend;
use self::tdp::{SharedDirectoryCreateResponse, SharedDirectoryInfoResponse};
use self::tdp::{
SharedDirectoryCreateResponse, SharedDirectoryDeleteResponse, SharedDirectoryInfoResponse,
};
use crate::client::{ClientFunction, ClientHandle};
use crate::CgoHandle;
use ironrdp_pdu::{custom_err, PduResult};
Expand Down Expand Up @@ -120,6 +122,18 @@ impl TeleportRdpdrBackend {
}
}

pub fn handle_tdp_sd_delete_response(
&mut self,
tdp_resp: SharedDirectoryDeleteResponse,
) -> PduResult<()> {
if let Some(resp) = self.fs.handle_tdp_sd_delete_response(tdp_resp)? {
self.write_rdpdr(resp)
} else {
// Nothing to send back to the server
Ok(())
}
ibeckermayer marked this conversation as resolved.
Show resolved Hide resolved
}

fn write_rdpdr(&mut self, pdu: RdpdrPdu) -> PduResult<()> {
self.client_handle
.blocking_send(ClientFunction::WriteRdpdr(pdu))
Expand Down
118 changes: 94 additions & 24 deletions lib/srv/desktop/rdp/rdpclient/src/rdpdr/filesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ use ironrdp_rdpdr::pdu::{
};
use std::collections::HashMap;

use crate::{tdp_sd_create_request, tdp_sd_info_request, CGOErrCode, CgoHandle};
use crate::{
tdp_sd_create_request, tdp_sd_delete_request, tdp_sd_info_request, CGOErrCode, CgoHandle,
};

use super::{
path::UnixPath,
tdp::{self, TdpErrCode},
tdp::{self, SharedDirectoryDeleteRequest, TdpErrCode},
};

/// `FilesystemBackend` implements the filesystem redirection backend as described in [\[MS-RDPEFS\]: Remote Desktop Protocol: File System Virtual Channel Extension].
Expand All @@ -38,10 +40,12 @@ pub struct FilesystemBackend {
/// See the documentation of FileCacheObject
/// for more detail on how this is used.
file_cache: FileCache,
/// CompletionId -> SharedDirectoryInfoResponseHandler
/// CompletionId -> [`SharedDirectoryInfoResponseHandler`]
pending_tdp_sd_info_resp_handlers: HashMap<u32, SharedDirectoryInfoResponseHandler>,
/// CompletionId -> SharedDirectoryCreateResponseHandler
/// CompletionId -> [`SharedDirectoryCreateResponseHandler`]
pending_sd_create_resp_handlers: HashMap<u32, SharedDirectoryCreateResponseHandler>,
/// CompletionId -> [`SharedDirectoryDeleteResponseHandler`]
pending_sd_delete_resp_handlers: HashMap<u32, SharedDirectoryDeleteResponseHandler>,
}

impl FilesystemBackend {
Expand All @@ -51,6 +55,7 @@ impl FilesystemBackend {
file_cache: FileCache::new(),
pending_tdp_sd_info_resp_handlers: HashMap::new(),
pending_sd_create_resp_handlers: HashMap::new(),
pending_sd_delete_resp_handlers: HashMap::new(),
}
}

Expand Down Expand Up @@ -249,10 +254,8 @@ impl FilesystemBackend {
))
}

/// Sends a [`tdp::SharedDirectoryCreateRequest`] to the browser based on the passed
/// [`efs::DeviceCreateRequest`]. Adds a [`SharedDirectoryCreateResponseHandler`] to
/// [`Self::pending_sd_create_resp_handlers`] to send an RDP [`efs::DeviceCreateResponse`]
/// back to the RDP server when the browser responds with a [`tdp::SharedDirectoryCreateResponse`].
/// Helper function for writing a [`tdp::SharedDirectoryCreateRequest`] to the browser
/// and handling the [`tdp::SharedDirectoryCreateResponse`] that is received in response.
fn tdp_sd_create(
&mut self,
rdp_req: efs::DeviceCreateRequest,
Expand Down Expand Up @@ -285,36 +288,73 @@ impl FilesystemBackend {
Ok(())
}

/// Helper function for combining a TDP SharedDirectoryDeleteRequest
/// with a TDP SharedDirectoryCreateRequest to overwrite a file, based
/// on an RDP DeviceCreateRequest.
/// Helper function for combining a [`tdp::SharedDirectoryDeleteRequest`]
/// with a [`tdp::SharedDirectoryCreateRequest`] to overwrite a file.
fn tdp_sd_overwrite(&mut self, rdp_req: efs::DeviceCreateRequest) -> PduResult<()> {
todo!()
let tdp_req = SharedDirectoryDeleteRequest::from(&rdp_req);
self.send_tdp_sd_delete_request(tdp_req)?;
self.pending_sd_delete_resp_handlers.insert(
rdp_req.device_io_request.completion_id,
SharedDirectoryDeleteResponseHandler::new(Box::new(
move |this: &mut FilesystemBackend,
tdp_resp: tdp::SharedDirectoryDeleteResponse|
-> PduResult<Option<RdpdrPdu>> {
match tdp_resp.err_code {
TdpErrCode::Nil => {
this.tdp_sd_create(rdp_req, tdp::FileType::File)?;
Ok(None)
}
_ => Self::make_device_create_response(&rdp_req, NtStatus::UNSUCCESSFUL, 0),
}
},
)),
);
Ok(())
}

/// Sends a [`tdp::SharedDirectoryInfoRequest`] to the browser.
fn send_tdp_sd_info_request(&self, req: tdp::SharedDirectoryInfoRequest) -> PduResult<()> {
debug!("sending tdp: {:?}", req);
let mut req = req.into_cgo()?;
fn send_tdp_sd_info_request(&self, tdp_req: tdp::SharedDirectoryInfoRequest) -> PduResult<()> {
debug!("sending tdp: {:?}", tdp_req);
let mut req = tdp_req.into_cgo()?;
let err = unsafe { tdp_sd_info_request(self.cgo_handle, req.cgo()) };
if err != CGOErrCode::ErrCodeSuccess {
FilesystemBackendError(format!(
"failed to send TDP Shared Directory Info Request: {:?}",
err
return Err(custom_err!(
"FilesystemBackend::send_tdp_sd_info_request",
FilesystemBackendError(format!("call to tdp_sd_info_request failed: {:?}", err))
));
};
Ok(())
}

/// Sends a [`tdp::SharedDirectoryCreateRequest`] to the browser.
fn send_tdp_sd_create_request(&self, req: tdp::SharedDirectoryCreateRequest) -> PduResult<()> {
debug!("sending tdp: {:?}", req);
let mut req = req.into_cgo()?;
fn send_tdp_sd_create_request(
&self,
tdp_req: tdp::SharedDirectoryCreateRequest,
) -> PduResult<()> {
debug!("sending tdp: {:?}", tdp_req);
let mut req = tdp_req.into_cgo()?;
let err = unsafe { tdp_sd_create_request(self.cgo_handle, req.cgo()) };
if err != CGOErrCode::ErrCodeSuccess {
return Err(other_err!(
"FilesystemBackend::send_tdp_sd_create",
"call to tdp_sd_create_request failed",
return Err(custom_err!(
"FilesystemBackend::send_tdp_sd_create_request",
FilesystemBackendError(format!("call to tdp_sd_create_request failed: {:?}", err))
));
};
Ok(())
}

/// Sends a [`tdp::SharedDirectoryDeleteRequest`] to the browser.
fn send_tdp_sd_delete_request(
&self,
tdp_req: tdp::SharedDirectoryDeleteRequest,
) -> PduResult<()> {
debug!("sending tdp: {:?}", tdp_req);
let mut req = tdp_req.into_cgo()?;
let err = unsafe { tdp_sd_delete_request(self.cgo_handle, req.cgo()) };
if err != CGOErrCode::ErrCodeSuccess {
return Err(custom_err!(
"FilesystemBackend::send_tdp_sd_delete_request",
FilesystemBackendError(format!("call to tdp_sd_create_request failed: {:?}", err))
));
};
Ok(())
Expand Down Expand Up @@ -368,6 +408,30 @@ impl FilesystemBackend {
}
}

/// Called from the Go code when a [`tdp::SharedDirectoryDeleteResponse`] is received from the browser.
///
/// Calls the [`SharedDirectoryDeleteResponseHandler`] associated with the completion id of the
/// [`tdp::SharedDirectoryDeleteResponse`].
pub fn handle_tdp_sd_delete_response(
&mut self,
res: tdp::SharedDirectoryDeleteResponse,
) -> PduResult<Option<RdpdrPdu>> {
if let Some(handler) = self
.pending_sd_delete_resp_handlers
.remove(&res.completion_id)
{
handler.call(self, res)
} else {
Err(custom_err!(
"FilesystemBackend::client_handle_tdp_sd_delete_response",
FilesystemBackendError(format!(
"received invalid completion id: {}",
res.completion_id
))
))
}
}

/// Helper function for creating an RDP [`efs::DeviceCreateResponse`] from an RDP [`efs::DeviceCreateRequest`].
fn make_device_create_response(
device_create_request: &efs::DeviceCreateRequest,
Expand Down Expand Up @@ -663,3 +727,9 @@ response_handler!(
CreateResponseHandlerFunction,
tdp::SharedDirectoryCreateResponse
);

response_handler!(
SharedDirectoryDeleteResponseHandler,
DeleteResponseHandlerFunction,
tdp::SharedDirectoryDeleteResponse
);
49 changes: 47 additions & 2 deletions lib/srv/desktop/rdp/rdpclient/src/rdpdr/tdp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use super::path::UnixPath;
use crate::{
util::{self, from_c_string, from_go_array},
CGOSharedDirectoryAnnounce, CGOSharedDirectoryCreateRequest, CGOSharedDirectoryCreateResponse,
CGOSharedDirectoryInfoRequest, CGOSharedDirectoryInfoResponse, CGOSharedDirectoryListResponse,
CGOSharedDirectoryReadResponse,
CGOSharedDirectoryDeleteRequest, CGOSharedDirectoryInfoRequest, CGOSharedDirectoryInfoResponse,
CGOSharedDirectoryListResponse, CGOSharedDirectoryReadResponse,
};
use ironrdp_pdu::{custom_err, PduResult};
use ironrdp_rdpdr::pdu::efs::DeviceCreateRequest;
Expand Down Expand Up @@ -323,6 +323,51 @@ pub struct SharedDirectoryDeleteRequest {
pub path: UnixPath,
}

impl SharedDirectoryDeleteRequest {
/// Converts this request into a [`SharedDirectoryDeleteRequest`].
///
/// Returns a tuple containing the [`SharedDirectoryDeleteRequest`] and a [`CString`],
/// which is the memory backing the [`SharedDirectoryDeleteRequest::path`] field.
/// It is the caller's responsibility to ensure that the [`CString`] lives until
/// the [`SharedDirectoryDeleteRequest::path`] is copied into Go-owned memory.
///
/// See the example for [`SharedDirectoryCreateRequest`]'s `into_cgo`.
pub fn into_cgo2(self) -> PduResult<(CGOSharedDirectoryDeleteRequest, CString)> {
let path = self.path.to_cstring()?;
Ok((
CGOSharedDirectoryDeleteRequest {
completion_id: self.completion_id,
directory_id: self.directory_id,
path: path.as_ptr(),
},
path,
))
}

/// See [`CGOWithStrings`].
pub fn into_cgo(self) -> PduResult<CGOWithStrings<CGOSharedDirectoryDeleteRequest>> {
let path = self.path.to_cstring()?;
Ok(CGOWithStrings {
cgo: CGOSharedDirectoryDeleteRequest {
completion_id: self.completion_id,
directory_id: self.directory_id,
path: path.as_ptr(),
},
_strings: vec![path],
})
}
}

impl From<&DeviceCreateRequest> for SharedDirectoryDeleteRequest {
fn from(req: &DeviceCreateRequest) -> SharedDirectoryDeleteRequest {
SharedDirectoryDeleteRequest {
completion_id: req.device_io_request.completion_id,
directory_id: req.device_io_request.device_id,
path: UnixPath::from(&req.path),
}
}
}

/// SharedDirectoryDeleteResponse is sent by the TDP client to the server
/// to acknowledge a SharedDirectoryDeleteRequest was received and executed.
#[derive(Debug)]
Expand Down
Loading