Skip to content

Commit ac29142

Browse files
refactor(web): add NegotiationFailure to IronErrorKind (#905)
Adds a general NegotiationFailure to IronErrorKind so that web embedders can handle failures that occur during protocol negotiation, before authentication. Changes: - RDP errors during the negotiation phase become IronErrorKind.NegotiationError - User-friendly RDP negotiation error messages to ironrdp-connector - Update TypeScript definitions
1 parent 5fc9fef commit ac29142

6 files changed

Lines changed: 63 additions & 3 deletions

File tree

crates/iron-remote-desktop/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ pub enum IronErrorKind {
2121
RDCleanPath,
2222
/// Couldn’t connect to proxy
2323
ProxyConnect,
24+
/// Protocol negotiation failed
25+
NegotiationFailure,
2426
}

crates/ironrdp-connector/src/connection.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use crate::channel_connection::{ChannelConnectionSequence, ChannelConnectionStat
1313
use crate::connection_activation::{ConnectionActivationSequence, ConnectionActivationState};
1414
use crate::license_exchange::{LicenseExchangeSequence, NoopLicenseCache};
1515
use crate::{
16-
encode_x224_packet, Config, ConnectorError, ConnectorErrorExt as _, ConnectorResult, DesktopSize, Sequence, State,
17-
Written,
16+
encode_x224_packet, Config, ConnectorError, ConnectorErrorExt as _, ConnectorErrorKind, ConnectorResult,
17+
DesktopSize, NegotiationFailure, Sequence, State, Written,
1818
};
1919

2020
#[derive(Debug)]
@@ -274,7 +274,10 @@ impl Sequence for ClientConnector {
274274
nego::ConnectionConfirm::Response { flags, protocol } => (flags, protocol),
275275
nego::ConnectionConfirm::Failure { code } => {
276276
error!(?code, "Received connection failure code");
277-
return Err(reason_err!("Initiation", "{code}"));
277+
return Err(ConnectorError::new(
278+
"negotiation failure",
279+
ConnectorErrorKind::Negotiation(NegotiationFailure::from(code)),
280+
));
278281
}
279282
};
280283

crates/ironrdp-connector/src/lib.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,55 @@ pub use self::license_exchange::{LicenseExchangeSequence, LicenseExchangeState};
3636
pub use self::server_name::ServerName;
3737
pub use crate::license_exchange::LicenseCache;
3838

39+
/// Provides user-friendly error messages for RDP negotiation failures
40+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41+
pub struct NegotiationFailure(ironrdp_pdu::nego::FailureCode);
42+
43+
impl NegotiationFailure {
44+
pub fn code(self) -> ironrdp_pdu::nego::FailureCode {
45+
self.0
46+
}
47+
}
48+
49+
impl core::error::Error for NegotiationFailure {}
50+
51+
impl From<ironrdp_pdu::nego::FailureCode> for NegotiationFailure {
52+
fn from(code: ironrdp_pdu::nego::FailureCode) -> Self {
53+
Self(code)
54+
}
55+
}
56+
57+
impl fmt::Display for NegotiationFailure {
58+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59+
use ironrdp_pdu::nego::FailureCode;
60+
61+
match self.0 {
62+
FailureCode::SSL_REQUIRED_BY_SERVER => {
63+
write!(f, "server requires Enhanced RDP Security with TLS or CredSSP")
64+
}
65+
FailureCode::SSL_NOT_ALLOWED_BY_SERVER => {
66+
write!(f, "server only supports Standard RDP Security")
67+
}
68+
FailureCode::SSL_CERT_NOT_ON_SERVER => {
69+
write!(f, "server lacks valid authentication certificate")
70+
}
71+
FailureCode::INCONSISTENT_FLAGS => {
72+
write!(f, "inconsistent security protocol flags")
73+
}
74+
FailureCode::HYBRID_REQUIRED_BY_SERVER => {
75+
write!(f, "server requires Enhanced RDP Security with CredSSP")
76+
}
77+
FailureCode::SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER => {
78+
write!(
79+
f,
80+
"server requires Enhanced RDP Security with TLS and client certificate"
81+
)
82+
}
83+
_ => write!(f, "unknown negotiation failure (code: 0x{:08x})", u32::from(self.0)),
84+
}
85+
}
86+
}
87+
3988
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4089
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
4190
pub struct DesktopSize {
@@ -276,6 +325,7 @@ pub enum ConnectorErrorKind {
276325
AccessDenied,
277326
General,
278327
Custom,
328+
Negotiation(NegotiationFailure),
279329
}
280330

281331
impl fmt::Display for ConnectorErrorKind {
@@ -288,6 +338,7 @@ impl fmt::Display for ConnectorErrorKind {
288338
ConnectorErrorKind::AccessDenied => write!(f, "access denied"),
289339
ConnectorErrorKind::General => write!(f, "general error"),
290340
ConnectorErrorKind::Custom => write!(f, "custom error"),
341+
ConnectorErrorKind::Negotiation(failure) => write!(f, "negotiation failure: {failure}"),
291342
}
292343
}
293344
}
@@ -302,6 +353,7 @@ impl core::error::Error for ConnectorErrorKind {
302353
ConnectorErrorKind::AccessDenied => None,
303354
ConnectorErrorKind::Custom => None,
304355
ConnectorErrorKind::General => None,
356+
ConnectorErrorKind::Negotiation(failure) => Some(failure),
305357
}
306358
}
307359
}

crates/ironrdp-web/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ ironrdp = { path = "../ironrdp", features = [
3434
"cliprdr",
3535
"svc",
3636
"displaycontrol",
37+
"pdu",
3738
] }
3839
ironrdp-core.path = "../ironrdp-core"
3940
ironrdp-cliprdr-format.path = "../ironrdp-cliprdr-format"

crates/ironrdp-web/src/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ impl From<connector::ConnectorError> for IronError {
3737
..
3838
}) => IronErrorKind::LogonFailure,
3939
ConnectorErrorKind::AccessDenied => IronErrorKind::AccessDenied,
40+
ConnectorErrorKind::Negotiation(_) => IronErrorKind::NegotiationFailure,
4041
_ => IronErrorKind::General,
4142
};
4243

web-client/iron-remote-desktop/src/interfaces/session-event.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export enum IronErrorKind {
77
AccessDenied = 3,
88
RDCleanPath = 4,
99
ProxyConnect = 5,
10+
NegotiationFailure = 6,
1011
}
1112

1213
export interface IronError {

0 commit comments

Comments
 (0)