mirror of
https://github.com/Devolutions/IronRDP.git
synced 2025-08-02 22:32:17 +00:00
feat: smartcard pin, autologon, GetReaderIconCall and GetReaderIconReturn (#230)
Includes #231
This commit is contained in:
parent
a29ff47f49
commit
47bc49b50e
10 changed files with 175 additions and 27 deletions
|
@ -53,14 +53,10 @@ where
|
||||||
{
|
{
|
||||||
let mut buf = WriteBuf::new();
|
let mut buf = WriteBuf::new();
|
||||||
|
|
||||||
debug!("CredSSP procedure");
|
|
||||||
|
|
||||||
while connector.is_credssp_step() {
|
while connector.is_credssp_step() {
|
||||||
single_connect_step(framed, &mut connector, &mut buf).await?;
|
single_connect_step(framed, &mut connector, &mut buf).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Remaining of connection sequence");
|
|
||||||
|
|
||||||
let result = loop {
|
let result = loop {
|
||||||
single_connect_step(framed, &mut connector, &mut buf).await?;
|
single_connect_step(framed, &mut connector, &mut buf).await?;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::str::FromStr;
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use clap::clap_derive::ValueEnum;
|
use clap::clap_derive::ValueEnum;
|
||||||
use clap::{crate_name, Parser};
|
use clap::{crate_name, Parser};
|
||||||
|
use ironrdp::connector::Credentials;
|
||||||
use ironrdp::pdu::rdp::capability_sets::MajorPlatformType;
|
use ironrdp::pdu::rdp::capability_sets::MajorPlatformType;
|
||||||
use ironrdp::{connector, pdu};
|
use ironrdp::{connector, pdu};
|
||||||
use tap::prelude::*;
|
use tap::prelude::*;
|
||||||
|
@ -220,6 +221,11 @@ struct Args {
|
||||||
/// starting from V8 to V10_7
|
/// starting from V8 to V10_7
|
||||||
#[clap(long, value_parser = parse_hex, default_value_t = 0)]
|
#[clap(long, value_parser = parse_hex, default_value_t = 0)]
|
||||||
capabilities: u32,
|
capabilities: u32,
|
||||||
|
|
||||||
|
/// Automatically logon to the server by passing the INFO_AUTOLOGON flag. This flag is
|
||||||
|
/// ignored if CredSSP is used (SecurityProtocol::Hybrid | SecurityProtocol::HybridEx).
|
||||||
|
#[clap(long)]
|
||||||
|
autologon: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
@ -276,8 +282,7 @@ impl Config {
|
||||||
};
|
};
|
||||||
|
|
||||||
let connector = connector::Config {
|
let connector = connector::Config {
|
||||||
username,
|
credentials: Credentials::UsernamePassword { username, password },
|
||||||
password,
|
|
||||||
domain: args.domain,
|
domain: args.domain,
|
||||||
security_protocol: SecurityProtocol::parse(args.security_protocol),
|
security_protocol: SecurityProtocol::parse(args.security_protocol),
|
||||||
keyboard_type: KeyboardType::parse(args.keyboard_type),
|
keyboard_type: KeyboardType::parse(args.keyboard_type),
|
||||||
|
@ -309,6 +314,7 @@ impl Config {
|
||||||
_ => MajorPlatformType::UNSPECIFIED,
|
_ => MajorPlatformType::UNSPECIFIED,
|
||||||
},
|
},
|
||||||
no_server_pointer: args.no_server_pointer,
|
no_server_pointer: args.no_server_pointer,
|
||||||
|
autologon: args.autologon,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|
|
@ -304,8 +304,9 @@ impl Sequence for ClientConnector {
|
||||||
//== Connection Initiation ==//
|
//== Connection Initiation ==//
|
||||||
// Exchange supported security protocols and a few other connection flags.
|
// Exchange supported security protocols and a few other connection flags.
|
||||||
ClientConnectorState::ConnectionInitiationSendRequest => {
|
ClientConnectorState::ConnectionInitiationSendRequest => {
|
||||||
|
debug!("Connection Initiation");
|
||||||
let connection_request = nego::ConnectionRequest {
|
let connection_request = nego::ConnectionRequest {
|
||||||
nego_data: Some(nego::NegoRequestData::cookie(self.config.username.clone())),
|
nego_data: Some(nego::NegoRequestData::cookie(self.config.credentials.username().into())),
|
||||||
flags: nego::RequestFlags::empty(),
|
flags: nego::RequestFlags::empty(),
|
||||||
protocol: self.config.security_protocol,
|
protocol: self.config.security_protocol,
|
||||||
};
|
};
|
||||||
|
@ -356,6 +357,7 @@ impl Sequence for ClientConnector {
|
||||||
{
|
{
|
||||||
ClientConnectorState::CredsspInitial { selected_protocol }
|
ClientConnectorState::CredsspInitial { selected_protocol }
|
||||||
} else {
|
} else {
|
||||||
|
debug!("Skipped CredSSP");
|
||||||
ClientConnectorState::BasicSettingsExchangeSendInitial { selected_protocol }
|
ClientConnectorState::BasicSettingsExchangeSendInitial { selected_protocol }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -364,9 +366,16 @@ impl Sequence for ClientConnector {
|
||||||
|
|
||||||
//== CredSSP ==//
|
//== CredSSP ==//
|
||||||
ClientConnectorState::CredsspInitial { selected_protocol } => {
|
ClientConnectorState::CredsspInitial { selected_protocol } => {
|
||||||
|
debug!("CredSSP");
|
||||||
|
if let crate::Credentials::SmartCard { .. } = self.config.credentials {
|
||||||
|
return Err(general_err!(
|
||||||
|
"CredSSP with smart card credentials is not currently supported"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let credentials = sspi::AuthIdentity {
|
let credentials = sspi::AuthIdentity {
|
||||||
username: self.config.username.clone(),
|
username: self.config.credentials.username().into(),
|
||||||
password: self.config.password.clone().into(),
|
password: self.config.credentials.secret().to_owned().into(),
|
||||||
domain: self.config.domain.clone(),
|
domain: self.config.domain.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -484,6 +493,7 @@ impl Sequence for ClientConnector {
|
||||||
//== Basic Settings Exchange ==//
|
//== Basic Settings Exchange ==//
|
||||||
// Exchange basic settings including Core Data, Security Data and Network Data.
|
// Exchange basic settings including Core Data, Security Data and Network Data.
|
||||||
ClientConnectorState::BasicSettingsExchangeSendInitial { selected_protocol } => {
|
ClientConnectorState::BasicSettingsExchangeSendInitial { selected_protocol } => {
|
||||||
|
debug!("Basic Settings Exchange");
|
||||||
let client_gcc_blocks =
|
let client_gcc_blocks =
|
||||||
create_gcc_blocks(&self.config, selected_protocol, self.static_channels.values());
|
create_gcc_blocks(&self.config, selected_protocol, self.static_channels.values());
|
||||||
|
|
||||||
|
@ -559,6 +569,7 @@ impl Sequence for ClientConnector {
|
||||||
io_channel_id,
|
io_channel_id,
|
||||||
mut channel_connection,
|
mut channel_connection,
|
||||||
} => {
|
} => {
|
||||||
|
debug!("Channel Connection");
|
||||||
let written = channel_connection.step(input, output)?;
|
let written = channel_connection.step(input, output)?;
|
||||||
|
|
||||||
let next_state = if let ChannelConnectionState::AllJoined { user_channel_id } = channel_connection.state
|
let next_state = if let ChannelConnectionState::AllJoined { user_channel_id } = channel_connection.state
|
||||||
|
@ -589,6 +600,7 @@ impl Sequence for ClientConnector {
|
||||||
io_channel_id,
|
io_channel_id,
|
||||||
user_channel_id,
|
user_channel_id,
|
||||||
} => {
|
} => {
|
||||||
|
debug!("RDP Security Commencement");
|
||||||
if selected_protocol == nego::SecurityProtocol::RDP {
|
if selected_protocol == nego::SecurityProtocol::RDP {
|
||||||
return Err(general_err!("standard RDP Security (RC4 encryption) is not supported"));
|
return Err(general_err!("standard RDP Security (RC4 encryption) is not supported"));
|
||||||
}
|
}
|
||||||
|
@ -608,6 +620,7 @@ impl Sequence for ClientConnector {
|
||||||
io_channel_id,
|
io_channel_id,
|
||||||
user_channel_id,
|
user_channel_id,
|
||||||
} => {
|
} => {
|
||||||
|
debug!("Secure Settings Exchange");
|
||||||
let routing_addr = self
|
let routing_addr = self
|
||||||
.server_addr
|
.server_addr
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -640,7 +653,7 @@ impl Sequence for ClientConnector {
|
||||||
user_channel_id,
|
user_channel_id,
|
||||||
license_exchange: LicenseExchangeSequence::new(
|
license_exchange: LicenseExchangeSequence::new(
|
||||||
io_channel_id,
|
io_channel_id,
|
||||||
self.config.username.clone(),
|
self.config.credentials.username().into(),
|
||||||
self.config.domain.clone(),
|
self.config.domain.clone(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -654,6 +667,7 @@ impl Sequence for ClientConnector {
|
||||||
user_channel_id,
|
user_channel_id,
|
||||||
mut license_exchange,
|
mut license_exchange,
|
||||||
} => {
|
} => {
|
||||||
|
debug!("Licensing Exchange");
|
||||||
let written = license_exchange.step(input, output)?;
|
let written = license_exchange.step(input, output)?;
|
||||||
|
|
||||||
let next_state = if license_exchange.state.is_terminal() {
|
let next_state = if license_exchange.state.is_terminal() {
|
||||||
|
@ -691,6 +705,7 @@ impl Sequence for ClientConnector {
|
||||||
io_channel_id,
|
io_channel_id,
|
||||||
user_channel_id,
|
user_channel_id,
|
||||||
} => {
|
} => {
|
||||||
|
debug!("Capabilities Exchange");
|
||||||
let send_data_indication_ctx = legacy::decode_send_data_indication(input)?;
|
let send_data_indication_ctx = legacy::decode_send_data_indication(input)?;
|
||||||
let share_control_ctx = legacy::decode_share_control(send_data_indication_ctx)?;
|
let share_control_ctx = legacy::decode_share_control(send_data_indication_ctx)?;
|
||||||
|
|
||||||
|
@ -761,6 +776,7 @@ impl Sequence for ClientConnector {
|
||||||
desktop_size,
|
desktop_size,
|
||||||
mut connection_finalization,
|
mut connection_finalization,
|
||||||
} => {
|
} => {
|
||||||
|
debug!("Connection Finalization");
|
||||||
let written = connection_finalization.step(input, output)?;
|
let written = connection_finalization.step(input, output)?;
|
||||||
|
|
||||||
let next_state = if connection_finalization.state.is_terminal() {
|
let next_state = if connection_finalization.state.is_terminal() {
|
||||||
|
@ -898,19 +914,30 @@ fn create_client_info_pdu(config: &Config, routing_addr: &SocketAddr) -> rdp::Cl
|
||||||
flags: BasicSecurityHeaderFlags::INFO_PKT,
|
flags: BasicSecurityHeaderFlags::INFO_PKT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Default flags for all sessions
|
||||||
|
let mut flags = ClientInfoFlags::UNICODE
|
||||||
|
| ClientInfoFlags::DISABLE_CTRL_ALT_DEL
|
||||||
|
| ClientInfoFlags::LOGON_NOTIFY
|
||||||
|
| ClientInfoFlags::LOGON_ERRORS
|
||||||
|
| ClientInfoFlags::NO_AUDIO_PLAYBACK
|
||||||
|
| ClientInfoFlags::VIDEO_DISABLE;
|
||||||
|
|
||||||
|
if config.autologon {
|
||||||
|
flags |= ClientInfoFlags::AUTOLOGON;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let crate::Credentials::SmartCard { .. } = &config.credentials {
|
||||||
|
flags |= ClientInfoFlags::PASSWORD_IS_SC_PIN;
|
||||||
|
}
|
||||||
|
|
||||||
let client_info = ClientInfo {
|
let client_info = ClientInfo {
|
||||||
credentials: Credentials {
|
credentials: Credentials {
|
||||||
username: config.username.clone(),
|
username: config.credentials.username().into(),
|
||||||
password: config.password.clone(),
|
password: config.credentials.secret().into(),
|
||||||
domain: config.domain.clone(),
|
domain: config.domain.clone(),
|
||||||
},
|
},
|
||||||
code_page: 0, // ignored if the keyboardLayout field of the Client Core Data is set to zero
|
code_page: 0, // ignored if the keyboardLayout field of the Client Core Data is set to zero
|
||||||
flags: ClientInfoFlags::UNICODE
|
flags,
|
||||||
| ClientInfoFlags::DISABLE_CTRL_ALT_DEL
|
|
||||||
| ClientInfoFlags::LOGON_NOTIFY
|
|
||||||
| ClientInfoFlags::LOGON_ERRORS
|
|
||||||
| ClientInfoFlags::NO_AUDIO_PLAYBACK
|
|
||||||
| ClientInfoFlags::VIDEO_DISABLE,
|
|
||||||
compression_type: CompressionType::K8, // ignored if ClientInfoFlags::COMPRESSION is not set
|
compression_type: CompressionType::K8, // ignored if ClientInfoFlags::COMPRESSION is not set
|
||||||
alternate_shell: String::new(),
|
alternate_shell: String::new(),
|
||||||
work_dir: String::new(),
|
work_dir: String::new(),
|
||||||
|
|
|
@ -52,13 +52,34 @@ pub struct BitmapConfig {
|
||||||
pub color_depth: u32,
|
pub color_depth: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Credentials {
|
||||||
|
UsernamePassword { username: String, password: String },
|
||||||
|
SmartCard { pin: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Credentials {
|
||||||
|
fn username(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::UsernamePassword { username, .. } => username,
|
||||||
|
Self::SmartCard { .. } => "", // Username is ultimately provided by the smart card certificate.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn secret(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::UsernamePassword { password, .. } => password,
|
||||||
|
Self::SmartCard { pin, .. } => pin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub desktop_size: DesktopSize,
|
pub desktop_size: DesktopSize,
|
||||||
pub security_protocol: nego::SecurityProtocol,
|
pub security_protocol: nego::SecurityProtocol,
|
||||||
pub username: String,
|
pub credentials: Credentials,
|
||||||
pub password: String,
|
|
||||||
pub domain: Option<String>,
|
pub domain: Option<String>,
|
||||||
/// The build number of the client.
|
/// The build number of the client.
|
||||||
pub client_build: u32,
|
pub client_build: u32,
|
||||||
|
@ -74,6 +95,8 @@ pub struct Config {
|
||||||
pub client_dir: String,
|
pub client_dir: String,
|
||||||
pub platform: capability_sets::MajorPlatformType,
|
pub platform: capability_sets::MajorPlatformType,
|
||||||
pub no_server_pointer: bool,
|
pub no_server_pointer: bool,
|
||||||
|
/// If true, the INFO_AUTOLOGON flag is set in the [`ironrdp_pdu::rdp::ClientInfoPdu`].
|
||||||
|
pub autologon: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
ironrdp_pdu::assert_impl!(Config: Send, Sync);
|
ironrdp_pdu::assert_impl!(Config: Send, Sync);
|
||||||
|
|
|
@ -31,6 +31,9 @@ const RECONNECT_COOKIE_LENGTH_SIZE: usize = 2;
|
||||||
const BIAS_SIZE: usize = 4;
|
const BIAS_SIZE: usize = 4;
|
||||||
const SYSTEM_TIME_SIZE: usize = 16;
|
const SYSTEM_TIME_SIZE: usize = 16;
|
||||||
|
|
||||||
|
/// [2.2.1.11.1.1 Info Packet (TS_INFO_PACKET)]
|
||||||
|
///
|
||||||
|
/// [2.2.1.11.1.1 Info Packet (TS_INFO_PACKET)]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/732394f5-e2b5-4ac5-8a0a-35345386b0d1
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct ClientInfo {
|
pub struct ClientInfo {
|
||||||
pub credentials: Credentials,
|
pub credentials: Credentials,
|
||||||
|
@ -521,26 +524,47 @@ pub enum AddressFamily {
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct ClientInfoFlags: u32 {
|
pub struct ClientInfoFlags: u32 {
|
||||||
|
/// INFO_MOUSE
|
||||||
const MOUSE = 0x0000_0001;
|
const MOUSE = 0x0000_0001;
|
||||||
|
/// INFO_DISABLECTRLALTDEL
|
||||||
const DISABLE_CTRL_ALT_DEL = 0x0000_0002;
|
const DISABLE_CTRL_ALT_DEL = 0x0000_0002;
|
||||||
|
/// INFO_AUTOLOGON
|
||||||
const AUTOLOGON = 0x0000_0008;
|
const AUTOLOGON = 0x0000_0008;
|
||||||
|
/// INFO_UNICODE
|
||||||
const UNICODE = 0x0000_0010;
|
const UNICODE = 0x0000_0010;
|
||||||
|
/// INFO_MAXIMIZESHELL
|
||||||
const MAXIMIZE_SHELL = 0x0000_0020;
|
const MAXIMIZE_SHELL = 0x0000_0020;
|
||||||
|
/// INFO_LOGONNOTIFY
|
||||||
const LOGON_NOTIFY = 0x0000_0040;
|
const LOGON_NOTIFY = 0x0000_0040;
|
||||||
|
/// INFO_COMPRESSION
|
||||||
const COMPRESSION = 0x0000_0080;
|
const COMPRESSION = 0x0000_0080;
|
||||||
|
/// INFO_ENABLEWINDOWSKEY
|
||||||
const ENABLE_WINDOWS_KEY = 0x0000_0100;
|
const ENABLE_WINDOWS_KEY = 0x0000_0100;
|
||||||
|
/// INFO_REMOTECONSOLEAUDIO
|
||||||
const REMOTE_CONSOLE_AUDIO = 0x0000_2000;
|
const REMOTE_CONSOLE_AUDIO = 0x0000_2000;
|
||||||
|
/// INFO_FORCE_ENCRYPTED_CS_PDU
|
||||||
const FORCE_ENCRYPTED_CS_PDU = 0x0000_4000;
|
const FORCE_ENCRYPTED_CS_PDU = 0x0000_4000;
|
||||||
|
/// INFO_RAIL
|
||||||
const RAIL = 0x0000_8000;
|
const RAIL = 0x0000_8000;
|
||||||
|
/// INFO_LOGONERRORS
|
||||||
const LOGON_ERRORS = 0x0001_0000;
|
const LOGON_ERRORS = 0x0001_0000;
|
||||||
|
/// INFO_MOUSE_HAS_WHEEL
|
||||||
const MOUSE_HAS_WHEEL = 0x0002_0000;
|
const MOUSE_HAS_WHEEL = 0x0002_0000;
|
||||||
|
/// INFO_PASSWORD_IS_SC_PIN
|
||||||
const PASSWORD_IS_SC_PIN = 0x0004_0000;
|
const PASSWORD_IS_SC_PIN = 0x0004_0000;
|
||||||
|
/// INFO_NOAUDIOPLAYBACK
|
||||||
const NO_AUDIO_PLAYBACK = 0x0008_0000;
|
const NO_AUDIO_PLAYBACK = 0x0008_0000;
|
||||||
|
/// INFO_USING_SAVED_CREDS
|
||||||
const USING_SAVED_CREDS = 0x0010_0000;
|
const USING_SAVED_CREDS = 0x0010_0000;
|
||||||
|
/// INFO_AUDIOCAPTURE
|
||||||
const AUDIO_CAPTURE = 0x0020_0000;
|
const AUDIO_CAPTURE = 0x0020_0000;
|
||||||
|
/// INFO_VIDEO_DISABLE
|
||||||
const VIDEO_DISABLE = 0x0040_0000;
|
const VIDEO_DISABLE = 0x0040_0000;
|
||||||
|
/// INFO_RESERVED1
|
||||||
const RESERVED1 = 0x0080_0000;
|
const RESERVED1 = 0x0080_0000;
|
||||||
|
/// INFO_RESERVED1
|
||||||
const RESERVED2 = 0x0100_0000;
|
const RESERVED2 = 0x0100_0000;
|
||||||
|
/// INFO_HIDEF_RAIL_SUPPORTED
|
||||||
const HIDEF_RAIL_SUPPORTED = 0x0200_0000;
|
const HIDEF_RAIL_SUPPORTED = 0x0200_0000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,7 +272,7 @@ fn from_buffer_correctly_parses_server_license_request() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_buffer_correctly_parses_server_license_request_no_certificate() {
|
fn from_buffer_correctly_parses_server_license_request_no_certificate() {
|
||||||
let server_certificate_header_buffer = vec![
|
let server_certificate_header_buffer = [
|
||||||
0x03, 0x00, // blob type
|
0x03, 0x00, // blob type
|
||||||
0x00, 0x00, // blob len
|
0x00, 0x00, // blob len
|
||||||
];
|
];
|
||||||
|
|
|
@ -34,6 +34,7 @@ pub enum ScardCall {
|
||||||
GetDeviceTypeIdCall(GetDeviceTypeIdCall),
|
GetDeviceTypeIdCall(GetDeviceTypeIdCall),
|
||||||
ReadCacheCall(ReadCacheCall),
|
ReadCacheCall(ReadCacheCall),
|
||||||
WriteCacheCall(WriteCacheCall),
|
WriteCacheCall(WriteCacheCall),
|
||||||
|
GetReaderIconCall(GetReaderIconCall),
|
||||||
Unsupported,
|
Unsupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +65,7 @@ impl ScardCall {
|
||||||
ScardIoCtlCode::GetDeviceTypeId => Ok(ScardCall::GetDeviceTypeIdCall(GetDeviceTypeIdCall::decode(src)?)),
|
ScardIoCtlCode::GetDeviceTypeId => Ok(ScardCall::GetDeviceTypeIdCall(GetDeviceTypeIdCall::decode(src)?)),
|
||||||
ScardIoCtlCode::ReadCacheW => Ok(ScardCall::ReadCacheCall(ReadCacheCall::decode(src)?)),
|
ScardIoCtlCode::ReadCacheW => Ok(ScardCall::ReadCacheCall(ReadCacheCall::decode(src)?)),
|
||||||
ScardIoCtlCode::WriteCacheW => Ok(ScardCall::WriteCacheCall(WriteCacheCall::decode(src)?)),
|
ScardIoCtlCode::WriteCacheW => Ok(ScardCall::WriteCacheCall(WriteCacheCall::decode(src)?)),
|
||||||
|
ScardIoCtlCode::GetReaderIcon => Ok(ScardCall::GetReaderIconCall(GetReaderIconCall::decode(src)?)),
|
||||||
_ => {
|
_ => {
|
||||||
warn!(?io_ctl_code, "Unsupported ScardIoCtlCode");
|
warn!(?io_ctl_code, "Unsupported ScardIoCtlCode");
|
||||||
// TODO: maybe this should be an error
|
// TODO: maybe this should be an error
|
||||||
|
@ -1740,3 +1742,72 @@ impl ndr::Decode for WriteCacheCommon {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [2.2.2.31 GetReaderIcon_Call]
|
||||||
|
///
|
||||||
|
/// [2.2.2.31 GetReaderIcon_Call]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpesc/e6a68d90-697f-4b98-8ad6-f74853d27ccb
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetReaderIconCall {
|
||||||
|
pub context: ScardContext,
|
||||||
|
pub reader_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetReaderIconCall {
|
||||||
|
pub fn decode(src: &mut ReadCursor<'_>) -> PduResult<Self> {
|
||||||
|
Ok(rpce::Pdu::<Self>::decode(src)?.into_inner())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl rpce::HeaderlessDecode for GetReaderIconCall {
|
||||||
|
fn decode(src: &mut ReadCursor<'_>) -> PduResult<Self> {
|
||||||
|
let mut index = 0;
|
||||||
|
let mut context = ScardContext::decode_ptr(src, &mut index)?;
|
||||||
|
|
||||||
|
let _reader_ptr = ndr::decode_ptr(src, &mut index)?;
|
||||||
|
|
||||||
|
context.decode_value(src)?;
|
||||||
|
let reader_name = ndr::read_string_from_cursor(src)?;
|
||||||
|
Ok(Self { context, reader_name })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [2.2.3.14 GetReaderIcon_Return]
|
||||||
|
///
|
||||||
|
/// [2.2.3.14 GetReaderIcon_Return]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpesc/f011f3d9-e2a4-4c43-a336-4c89ecaa8360
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetReaderIconReturn {
|
||||||
|
pub return_code: ReturnCode,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetReaderIconReturn {
|
||||||
|
const NAME: &'static str = "GetReaderIcon_Return";
|
||||||
|
|
||||||
|
pub fn new(return_code: ReturnCode, data: Vec<u8>) -> rpce::Pdu<Self> {
|
||||||
|
rpce::Pdu(Self { return_code, data })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl rpce::HeaderlessEncode for GetReaderIconReturn {
|
||||||
|
fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> {
|
||||||
|
ensure_size!(in: dst, size: self.size());
|
||||||
|
dst.write_u32(self.return_code.into());
|
||||||
|
let data_len: u32 = cast_length!("GetReaderIconReturn", "data_len", self.data.len())?;
|
||||||
|
let mut index = 0;
|
||||||
|
ndr::encode_ptr(Some(data_len), &mut index, dst)?;
|
||||||
|
dst.write_u32(data_len);
|
||||||
|
dst.write_slice(&self.data);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
Self::NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
size_of::<u32>() // dst.write_u32(self.return_code.into());
|
||||||
|
+ ndr::ptr_size(true) // ndr::encode_ptr(Some(data_len), &mut index, dst)?;
|
||||||
|
+ size_of::<u32>() // dst.write_u32(data_len);
|
||||||
|
+ self.data.len() // dst.write_slice(&self.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ fn client_temp_dir_encode_decode_ms_1() {
|
||||||
|
|
||||||
if let ClipboardPdu::TemporaryDirectory(client_temp_dir) = &decoded_pdu {
|
if let ClipboardPdu::TemporaryDirectory(client_temp_dir) = &decoded_pdu {
|
||||||
let path = client_temp_dir.temporary_directory_path().unwrap();
|
let path = client_temp_dir.temporary_directory_path().unwrap();
|
||||||
expect![[r#"C:\DOCUME~1\ELTONS~1.NTD\LOCALS~1\Temp\cdepotslhrdp_1\_TSABD.tmp"#]].assert_eq(&path);
|
expect![[r"C:\DOCUME~1\ELTONS~1.NTD\LOCALS~1\Temp\cdepotslhrdp_1\_TSABD.tmp"]].assert_eq(&path);
|
||||||
} else {
|
} else {
|
||||||
panic!("Expected ClientTemporaryDirectory");
|
panic!("Expected ClientTemporaryDirectory");
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use futures_util::io::{ReadHalf, WriteHalf};
|
||||||
use futures_util::{select, AsyncReadExt as _, AsyncWriteExt as _, FutureExt as _, StreamExt as _};
|
use futures_util::{select, AsyncReadExt as _, AsyncWriteExt as _, FutureExt as _, StreamExt as _};
|
||||||
use gloo_net::websocket;
|
use gloo_net::websocket;
|
||||||
use gloo_net::websocket::futures::WebSocket;
|
use gloo_net::websocket::futures::WebSocket;
|
||||||
use ironrdp::connector::{self, ClientConnector};
|
use ironrdp::connector::{self, ClientConnector, Credentials};
|
||||||
use ironrdp::graphics::image_processing::PixelFormat;
|
use ironrdp::graphics::image_processing::PixelFormat;
|
||||||
use ironrdp::pdu::input::fast_path::FastPathInputEvent;
|
use ironrdp::pdu::input::fast_path::FastPathInputEvent;
|
||||||
use ironrdp::pdu::write_buf::WriteBuf;
|
use ironrdp::pdu::write_buf::WriteBuf;
|
||||||
|
@ -462,8 +462,7 @@ fn build_config(
|
||||||
desktop_size: DesktopSize,
|
desktop_size: DesktopSize,
|
||||||
) -> connector::Config {
|
) -> connector::Config {
|
||||||
connector::Config {
|
connector::Config {
|
||||||
username,
|
credentials: Credentials::UsernamePassword { username, password },
|
||||||
password,
|
|
||||||
domain,
|
domain,
|
||||||
security_protocol: ironrdp::pdu::nego::SecurityProtocol::HYBRID,
|
security_protocol: ironrdp::pdu::nego::SecurityProtocol::HYBRID,
|
||||||
keyboard_type: ironrdp::pdu::gcc::KeyboardType::IbmEnhanced,
|
keyboard_type: ironrdp::pdu::gcc::KeyboardType::IbmEnhanced,
|
||||||
|
@ -492,6 +491,7 @@ fn build_config(
|
||||||
client_dir: "C:\\Windows\\System32\\mstscax.dll".to_owned(),
|
client_dir: "C:\\Windows\\System32\\mstscax.dll".to_owned(),
|
||||||
platform: ironrdp::pdu::rdp::capability_sets::MajorPlatformType::UNSPECIFIED,
|
platform: ironrdp::pdu::rdp::capability_sets::MajorPlatformType::UNSPECIFIED,
|
||||||
no_server_pointer: false,
|
no_server_pointer: false,
|
||||||
|
autologon: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ use std::path::PathBuf;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
|
use connector::Credentials;
|
||||||
use ironrdp::connector;
|
use ironrdp::connector;
|
||||||
use ironrdp::connector::sspi::network_client::reqwest_network_client::RequestClientFactory;
|
use ironrdp::connector::sspi::network_client::reqwest_network_client::RequestClientFactory;
|
||||||
use ironrdp::connector::ConnectionResult;
|
use ironrdp::connector::ConnectionResult;
|
||||||
|
@ -174,8 +175,7 @@ fn run(
|
||||||
|
|
||||||
fn build_config(username: String, password: String, domain: Option<String>) -> connector::Config {
|
fn build_config(username: String, password: String, domain: Option<String>) -> connector::Config {
|
||||||
connector::Config {
|
connector::Config {
|
||||||
username,
|
credentials: Credentials::UsernamePassword { username, password },
|
||||||
password,
|
|
||||||
domain,
|
domain,
|
||||||
security_protocol: SecurityProtocol::HYBRID,
|
security_protocol: SecurityProtocol::HYBRID,
|
||||||
keyboard_type: KeyboardType::IbmEnhanced,
|
keyboard_type: KeyboardType::IbmEnhanced,
|
||||||
|
@ -214,6 +214,7 @@ fn build_config(username: String, password: String, domain: Option<String>) -> c
|
||||||
|
|
||||||
// Disable custom pointers (there is no user interaction anyway)
|
// Disable custom pointers (there is no user interaction anyway)
|
||||||
no_server_pointer: true,
|
no_server_pointer: true,
|
||||||
|
autologon: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue