1#![cfg_attr(doc, doc = include_str!("../README.md"))]
2#![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")]
3#![allow(clippy::arithmetic_side_effects)] use ironrdp_core::{decode_cursor, impl_as_any, ReadCursor};
6use ironrdp_pdu::gcc::ChannelName;
7use ironrdp_pdu::{decode_err, pdu_other_err, PduResult};
8use ironrdp_svc::{CompressionCondition, SvcClientProcessor, SvcMessage, SvcProcessor};
9use pdu::efs::{
10 Capabilities, ClientDeviceListAnnounce, ClientDeviceListRemove, ClientNameRequest, ClientNameRequestUnicodeFlag,
11 CoreCapability, CoreCapabilityKind, DeviceControlRequest, DeviceIoRequest, DeviceType, Devices,
12 ServerDeviceAnnounceResponse, VersionAndIdPdu, VersionAndIdPduKind,
13};
14use pdu::esc::{ScardCall, ScardIoCtlCode};
15use pdu::RdpdrPdu;
16use tracing::{debug, trace, warn};
17
18pub mod backend;
19pub mod pdu;
20
21pub use self::backend::noop::NoopRdpdrBackend;
22pub use self::backend::RdpdrBackend;
23use crate::pdu::efs::ServerDriveIoRequest;
24
25#[derive(Debug)]
34pub struct Rdpdr {
35 computer_name: String,
40 capabilities: Capabilities,
41 device_list: Devices,
45 backend: Box<dyn RdpdrBackend>,
46}
47
48impl_as_any!(Rdpdr);
49
50impl Rdpdr {
51 pub const NAME: ChannelName = ChannelName::from_static(b"rdpdr\0\0\0");
52
53 pub fn new(backend: Box<dyn RdpdrBackend>, computer_name: String) -> Self {
55 Self {
56 computer_name,
57 capabilities: Capabilities::new(),
58 device_list: Devices::new(),
59 backend,
60 }
61 }
62
63 #[must_use]
64 pub fn with_smartcard(mut self, device_id: u32) -> Self {
65 self.capabilities.add_smartcard();
66 self.device_list.add_smartcard(device_id);
67 self
68 }
69
70 #[must_use]
76 pub fn with_drives(mut self, initial_drives: Option<Vec<(u32, String)>>) -> Self {
77 self.capabilities.add_drive();
78 if let Some(initial_drives) = initial_drives {
79 for (device_id, path) in initial_drives {
80 self.device_list.add_drive(device_id, path);
81 }
82 }
83 self
84 }
85
86 pub fn add_drive(&mut self, device_id: u32, name: String) -> ClientDeviceListAnnounce {
89 self.device_list.add_drive(device_id, name.clone());
90 ClientDeviceListAnnounce::new_drive(device_id, name)
91 }
92
93 pub fn remove_device(&mut self, device_id: u32) -> Option<ClientDeviceListRemove> {
94 Some(ClientDeviceListRemove::remove_device(
95 self.device_list.remove_device(device_id)?,
96 ))
97 }
98
99 pub fn downcast_backend<T: RdpdrBackend>(&self) -> Option<&T> {
100 self.backend.as_any().downcast_ref::<T>()
101 }
102
103 pub fn downcast_backend_mut<T: RdpdrBackend>(&mut self) -> Option<&mut T> {
104 self.backend.as_any_mut().downcast_mut::<T>()
105 }
106
107 fn handle_server_announce(&mut self, req: VersionAndIdPdu) -> PduResult<Vec<SvcMessage>> {
108 let client_announce_reply =
109 RdpdrPdu::VersionAndIdPdu(VersionAndIdPdu::new_client_announce_reply(req).map_err(|e| decode_err!(e))?);
110 trace!("sending {:?}", client_announce_reply);
111
112 let client_name_request = RdpdrPdu::ClientNameRequest(ClientNameRequest::new(
113 self.computer_name.clone(),
114 ClientNameRequestUnicodeFlag::Unicode,
115 ));
116 trace!("sending {:?}", client_name_request);
117
118 Ok(vec![
119 SvcMessage::from(client_announce_reply),
120 SvcMessage::from(client_name_request),
121 ])
122 }
123
124 fn handle_server_capability(&mut self, _req: CoreCapability) -> PduResult<Vec<SvcMessage>> {
125 let res = RdpdrPdu::CoreCapability(CoreCapability::new_response(self.capabilities.clone_inner()));
126 trace!("sending {:?}", res);
127 Ok(vec![SvcMessage::from(res)])
128 }
129
130 fn handle_client_id_confirm(&mut self) -> PduResult<Vec<SvcMessage>> {
131 let res = RdpdrPdu::ClientDeviceListAnnounce(ClientDeviceListAnnounce {
132 device_list: self.device_list.clone_inner(),
133 });
134 trace!("sending {:?}", res);
135 Ok(vec![SvcMessage::from(res)])
136 }
137
138 fn handle_server_device_announce_response(
139 &mut self,
140 pdu: ServerDeviceAnnounceResponse,
141 ) -> PduResult<Vec<SvcMessage>> {
142 self.backend.handle_server_device_announce_response(pdu)?;
143 Ok(Vec::new())
144 }
145
146 fn handle_device_io_request(
147 &mut self,
148 dev_io_req: DeviceIoRequest,
149 src: &mut ReadCursor<'_>,
150 ) -> PduResult<Vec<SvcMessage>> {
151 match self
152 .device_list
153 .for_device_type(dev_io_req.device_id)
154 .map_err(|e| decode_err!(e))?
155 {
156 DeviceType::Smartcard => {
157 let req =
158 DeviceControlRequest::<ScardIoCtlCode>::decode(dev_io_req, src).map_err(|e| decode_err!(e))?;
159 let call = ScardCall::decode(req.io_control_code, src).map_err(|e| decode_err!(e))?;
160
161 debug!(?req);
162 debug!(?req.io_control_code, ?call);
163
164 self.backend.handle_scard_call(req, call)?;
165
166 Ok(Vec::new())
167 }
168 DeviceType::Filesystem => {
169 let req = ServerDriveIoRequest::decode(dev_io_req, src).map_err(|e| decode_err!(e))?;
170
171 debug!(?req);
172
173 Ok(self.backend.handle_drive_io_request(req)?)
174 }
175 _ => {
176 warn!(?dev_io_req, "received packet for unsupported device type");
178 Ok(Vec::new())
179 }
180 }
181 }
182}
183
184impl SvcProcessor for Rdpdr {
185 fn channel_name(&self) -> ChannelName {
186 Self::NAME
187 }
188
189 fn compression_condition(&self) -> CompressionCondition {
190 CompressionCondition::WhenRdpDataIsCompressed
191 }
192
193 fn process(&mut self, payload: &[u8]) -> PduResult<Vec<SvcMessage>> {
194 let mut src = ReadCursor::new(payload);
195 let pdu = decode_cursor::<RdpdrPdu>(&mut src).map_err(|e| decode_err!(e))?;
196 debug!("Received {:?}", pdu);
197
198 match pdu {
199 RdpdrPdu::VersionAndIdPdu(pdu) if pdu.kind == VersionAndIdPduKind::ServerAnnounceRequest => {
200 self.handle_server_announce(pdu)
201 }
202 RdpdrPdu::CoreCapability(pdu) if pdu.kind == CoreCapabilityKind::ServerCoreCapabilityRequest => {
203 self.handle_server_capability(pdu)
204 }
205 RdpdrPdu::VersionAndIdPdu(pdu) if pdu.kind == VersionAndIdPduKind::ServerClientIdConfirm => {
206 self.handle_client_id_confirm()
207 }
208 RdpdrPdu::ServerDeviceAnnounceResponse(pdu) => self.handle_server_device_announce_response(pdu),
209 RdpdrPdu::DeviceIoRequest(pdu) => self.handle_device_io_request(pdu, &mut src),
210 RdpdrPdu::UserLoggedon => Ok(vec![]),
211 RdpdrPdu::ClientNameRequest(_)
214 | RdpdrPdu::ClientDeviceListAnnounce(_)
215 | RdpdrPdu::ClientDeviceListRemove(_)
216 | RdpdrPdu::VersionAndIdPdu(_)
217 | RdpdrPdu::CoreCapability(_)
218 | RdpdrPdu::DeviceControlResponse(_)
219 | RdpdrPdu::DeviceCreateResponse(_)
220 | RdpdrPdu::ClientDriveQueryInformationResponse(_)
221 | RdpdrPdu::DeviceCloseResponse(_)
222 | RdpdrPdu::ClientDriveQueryDirectoryResponse(_)
223 | RdpdrPdu::ClientDriveQueryVolumeInformationResponse(_)
224 | RdpdrPdu::DeviceReadResponse(_)
225 | RdpdrPdu::DeviceWriteResponse(_)
226 | RdpdrPdu::ClientDriveSetInformationResponse(_)
227 | RdpdrPdu::EmptyResponse => Err(pdu_other_err!("Rdpdr", "received unexpected packet")),
228 }
229 }
230}
231
232impl SvcClientProcessor for Rdpdr {}