mirror of
https://github.com/Devolutions/IronRDP.git
synced 2025-08-04 15:18:17 +00:00
feat(acceptor): add CredSSP support
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
parent
ac24e15a3d
commit
4c4d93bc6f
3 changed files with 390 additions and 25 deletions
|
@ -27,7 +27,7 @@ const IO_CHANNEL_ID: u16 = 1003;
|
|||
const USER_CHANNEL_ID: u16 = 1002;
|
||||
|
||||
pub struct Acceptor {
|
||||
state: AcceptorState,
|
||||
pub(crate) state: AcceptorState,
|
||||
security: nego::SecurityProtocol,
|
||||
io_channel_id: u16,
|
||||
user_channel_id: u16,
|
||||
|
@ -35,7 +35,7 @@ pub struct Acceptor {
|
|||
server_capabilities: Vec<CapabilitySet>,
|
||||
static_channels: StaticChannelSet,
|
||||
saved_for_reactivation: AcceptorState,
|
||||
creds: Option<Credentials>,
|
||||
pub(crate) creds: Option<Credentials>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -128,6 +128,23 @@ impl Acceptor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn mark_security_upgrade_as_done(&mut self) {
|
||||
assert!(self.reached_security_upgrade().is_some());
|
||||
self.step(&[], &mut WriteBuf::new()).expect("transition to next state");
|
||||
debug_assert!(self.reached_security_upgrade().is_none());
|
||||
}
|
||||
|
||||
pub fn should_perform_credssp(&self) -> bool {
|
||||
matches!(self.state, AcceptorState::Credssp { .. })
|
||||
}
|
||||
|
||||
pub fn mark_credssp_as_done(&mut self) {
|
||||
assert!(self.should_perform_credssp());
|
||||
let res = self.step(&[], &mut WriteBuf::new()).expect("transition to next state");
|
||||
debug_assert!(!self.should_perform_credssp());
|
||||
assert_eq!(res, Written::Nothing);
|
||||
}
|
||||
|
||||
pub fn get_result(&mut self) -> Option<AcceptorResult> {
|
||||
match mem::take(&mut self.state) {
|
||||
AcceptorState::Accepted {
|
||||
|
@ -160,25 +177,35 @@ pub enum AcceptorState {
|
|||
},
|
||||
SecurityUpgrade {
|
||||
requested_protocol: nego::SecurityProtocol,
|
||||
protocol: nego::SecurityProtocol,
|
||||
},
|
||||
Credssp {
|
||||
requested_protocol: nego::SecurityProtocol,
|
||||
protocol: nego::SecurityProtocol,
|
||||
},
|
||||
BasicSettingsWaitInitial {
|
||||
requested_protocol: nego::SecurityProtocol,
|
||||
protocol: nego::SecurityProtocol,
|
||||
},
|
||||
BasicSettingsSendResponse {
|
||||
requested_protocol: nego::SecurityProtocol,
|
||||
protocol: nego::SecurityProtocol,
|
||||
early_capability: Option<gcc::ClientEarlyCapabilityFlags>,
|
||||
channels: Vec<(u16, Option<gcc::ChannelDef>)>,
|
||||
},
|
||||
ChannelConnection {
|
||||
protocol: nego::SecurityProtocol,
|
||||
early_capability: Option<gcc::ClientEarlyCapabilityFlags>,
|
||||
channels: Vec<(u16, gcc::ChannelDef)>,
|
||||
connection: ChannelConnectionSequence,
|
||||
},
|
||||
RdpSecurityCommencement {
|
||||
protocol: nego::SecurityProtocol,
|
||||
early_capability: Option<gcc::ClientEarlyCapabilityFlags>,
|
||||
channels: Vec<(u16, gcc::ChannelDef)>,
|
||||
},
|
||||
SecureSettingsExchange {
|
||||
protocol: nego::SecurityProtocol,
|
||||
early_capability: Option<gcc::ClientEarlyCapabilityFlags>,
|
||||
channels: Vec<(u16, gcc::ChannelDef)>,
|
||||
},
|
||||
|
@ -215,6 +242,7 @@ impl State for AcceptorState {
|
|||
Self::InitiationWaitRequest => "InitiationWaitRequest",
|
||||
Self::InitiationSendConfirm { .. } => "InitiationSendConfirm",
|
||||
Self::SecurityUpgrade { .. } => "SecurityUpgrade",
|
||||
Self::Credssp { .. } => "Credssp",
|
||||
Self::BasicSettingsWaitInitial { .. } => "BasicSettingsWaitInitial",
|
||||
Self::BasicSettingsSendResponse { .. } => "BasicSettingsSendResponse",
|
||||
Self::ChannelConnection { .. } => "ChannelConnection",
|
||||
|
@ -245,6 +273,7 @@ impl Sequence for Acceptor {
|
|||
AcceptorState::InitiationWaitRequest => Some(&pdu::X224_HINT),
|
||||
AcceptorState::InitiationSendConfirm { .. } => None,
|
||||
AcceptorState::SecurityUpgrade { .. } => None,
|
||||
AcceptorState::Credssp { .. } => None,
|
||||
AcceptorState::BasicSettingsWaitInitial { .. } => Some(&pdu::X224_HINT),
|
||||
AcceptorState::BasicSettingsSendResponse { .. } => None,
|
||||
AcceptorState::ChannelConnection { connection, .. } => connection.next_pdu_hint(),
|
||||
|
@ -281,9 +310,10 @@ impl Sequence for Acceptor {
|
|||
}
|
||||
|
||||
AcceptorState::InitiationSendConfirm { requested_protocol } => {
|
||||
let protocol = requested_protocol & self.security;
|
||||
let connection_confirm = nego::ConnectionConfirm::Response {
|
||||
flags: nego::ResponseFlags::empty(),
|
||||
protocol: self.security,
|
||||
protocol,
|
||||
};
|
||||
|
||||
debug!(message = ?connection_confirm, "Send");
|
||||
|
@ -293,16 +323,48 @@ impl Sequence for Acceptor {
|
|||
|
||||
(
|
||||
Written::from_size(written)?,
|
||||
AcceptorState::SecurityUpgrade { requested_protocol },
|
||||
AcceptorState::SecurityUpgrade {
|
||||
requested_protocol,
|
||||
protocol,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
AcceptorState::SecurityUpgrade { requested_protocol } => (
|
||||
AcceptorState::SecurityUpgrade {
|
||||
requested_protocol,
|
||||
protocol,
|
||||
} => {
|
||||
debug!(?requested_protocol);
|
||||
let next_state =
|
||||
if protocol.intersects(nego::SecurityProtocol::HYBRID | nego::SecurityProtocol::HYBRID_EX) {
|
||||
AcceptorState::Credssp {
|
||||
requested_protocol,
|
||||
protocol,
|
||||
}
|
||||
} else {
|
||||
AcceptorState::BasicSettingsWaitInitial {
|
||||
requested_protocol,
|
||||
protocol,
|
||||
}
|
||||
};
|
||||
(Written::Nothing, next_state)
|
||||
}
|
||||
|
||||
AcceptorState::Credssp {
|
||||
requested_protocol,
|
||||
protocol,
|
||||
} => (
|
||||
Written::Nothing,
|
||||
AcceptorState::BasicSettingsWaitInitial { requested_protocol },
|
||||
AcceptorState::BasicSettingsWaitInitial {
|
||||
requested_protocol,
|
||||
protocol,
|
||||
},
|
||||
),
|
||||
|
||||
AcceptorState::BasicSettingsWaitInitial { requested_protocol } => {
|
||||
AcceptorState::BasicSettingsWaitInitial {
|
||||
requested_protocol,
|
||||
protocol,
|
||||
} => {
|
||||
let x224_payload = decode::<X224<pdu::x224::X224Data<'_>>>(input)
|
||||
.map_err(ConnectorError::decode)
|
||||
.map(|p| p.0)?;
|
||||
|
@ -354,6 +416,7 @@ impl Sequence for Acceptor {
|
|||
Written::Nothing,
|
||||
AcceptorState::BasicSettingsSendResponse {
|
||||
requested_protocol,
|
||||
protocol,
|
||||
early_capability,
|
||||
channels,
|
||||
},
|
||||
|
@ -362,6 +425,7 @@ impl Sequence for Acceptor {
|
|||
|
||||
AcceptorState::BasicSettingsSendResponse {
|
||||
requested_protocol,
|
||||
protocol,
|
||||
early_capability,
|
||||
channels,
|
||||
} => {
|
||||
|
@ -394,6 +458,7 @@ impl Sequence for Acceptor {
|
|||
(
|
||||
Written::from_size(written)?,
|
||||
AcceptorState::ChannelConnection {
|
||||
protocol,
|
||||
early_capability,
|
||||
channels,
|
||||
connection: if skip_channel_join {
|
||||
|
@ -406,6 +471,7 @@ impl Sequence for Acceptor {
|
|||
}
|
||||
|
||||
AcceptorState::ChannelConnection {
|
||||
protocol,
|
||||
early_capability,
|
||||
channels,
|
||||
mut connection,
|
||||
|
@ -413,11 +479,13 @@ impl Sequence for Acceptor {
|
|||
let written = connection.step(input, output)?;
|
||||
let state = if connection.is_done() {
|
||||
AcceptorState::RdpSecurityCommencement {
|
||||
protocol,
|
||||
early_capability,
|
||||
channels,
|
||||
}
|
||||
} else {
|
||||
AcceptorState::ChannelConnection {
|
||||
protocol,
|
||||
early_capability,
|
||||
channels,
|
||||
connection,
|
||||
|
@ -428,18 +496,21 @@ impl Sequence for Acceptor {
|
|||
}
|
||||
|
||||
AcceptorState::RdpSecurityCommencement {
|
||||
protocol,
|
||||
early_capability,
|
||||
channels,
|
||||
..
|
||||
} => (
|
||||
Written::Nothing,
|
||||
AcceptorState::SecureSettingsExchange {
|
||||
protocol,
|
||||
early_capability,
|
||||
channels,
|
||||
},
|
||||
),
|
||||
|
||||
AcceptorState::SecureSettingsExchange {
|
||||
protocol,
|
||||
early_capability,
|
||||
channels,
|
||||
} => {
|
||||
|
@ -450,28 +521,29 @@ impl Sequence for Acceptor {
|
|||
|
||||
debug!(message = ?client_info, "Received");
|
||||
|
||||
let creds = client_info.client_info.credentials;
|
||||
if !protocol.intersects(nego::SecurityProtocol::HYBRID | nego::SecurityProtocol::HYBRID_EX) {
|
||||
let creds = client_info.client_info.credentials;
|
||||
|
||||
if self.creds.as_ref().map_or(true, |srv_creds| srv_creds != &creds) {
|
||||
// how authorization should be denied with standard RDP security?
|
||||
let info = ServerSetErrorInfoPdu(ErrorInfo::ProtocolIndependentCode(
|
||||
ProtocolIndependentCode::ServerDeniedConnection,
|
||||
));
|
||||
if self.creds.as_ref().map_or(true, |srv_creds| srv_creds != &creds) {
|
||||
// how authorization should be denied with standard RDP security?
|
||||
let info = ServerSetErrorInfoPdu(ErrorInfo::ProtocolIndependentCode(
|
||||
ProtocolIndependentCode::ServerDeniedConnection,
|
||||
));
|
||||
|
||||
debug!(message = ?info, "Send");
|
||||
debug!(message = ?info, "Send");
|
||||
|
||||
util::encode_send_data_indication(self.user_channel_id, self.io_channel_id, &info, output)?;
|
||||
util::encode_send_data_indication(self.user_channel_id, self.io_channel_id, &info, output)?;
|
||||
|
||||
return Err(ConnectorError::general("invalid credentials"));
|
||||
} else {
|
||||
(
|
||||
Written::Nothing,
|
||||
AcceptorState::LicensingExchange {
|
||||
early_capability,
|
||||
channels,
|
||||
},
|
||||
)
|
||||
return Err(ConnectorError::general("invalid credentials"));
|
||||
}
|
||||
}
|
||||
(
|
||||
Written::Nothing,
|
||||
AcceptorState::LicensingExchange {
|
||||
early_capability,
|
||||
channels,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
AcceptorState::LicensingExchange {
|
||||
|
|
160
crates/ironrdp-acceptor/src/credssp.rs
Normal file
160
crates/ironrdp-acceptor/src/credssp.rs
Normal file
|
@ -0,0 +1,160 @@
|
|||
use ironrdp_connector::{
|
||||
credssp::KerberosConfig,
|
||||
custom_err, general_err,
|
||||
sspi::{
|
||||
self,
|
||||
credssp::{ClientMode, CredSspServer, CredentialsProxy, ServerError, ServerState, TsRequest},
|
||||
negotiate::ProtocolConfig,
|
||||
AuthIdentity, Username,
|
||||
},
|
||||
ConnectorError, ConnectorErrorKind, ConnectorResult, ServerName, Written,
|
||||
};
|
||||
use ironrdp_core::{other_err, WriteBuf};
|
||||
use ironrdp_pdu::PduHint;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum CredsspState {
|
||||
Ongoing,
|
||||
Finished,
|
||||
ServerError(sspi::Error),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct CredsspTsRequestHint;
|
||||
|
||||
const CREDSSP_TS_REQUEST_HINT: CredsspTsRequestHint = CredsspTsRequestHint;
|
||||
|
||||
impl PduHint for CredsspTsRequestHint {
|
||||
fn find_size(&self, bytes: &[u8]) -> ironrdp_core::DecodeResult<Option<(bool, usize)>> {
|
||||
match TsRequest::read_length(bytes) {
|
||||
Ok(length) => Ok(Some((true, length))),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => Ok(None),
|
||||
Err(e) => Err(other_err!("CredsspTsRequestHint", source: e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CredsspSequence<'a> {
|
||||
server: CredSspServer<CredentialsProxyImpl<'a>>,
|
||||
state: CredsspState,
|
||||
// selected_protocol: nego::SecurityProtocol,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CredentialsProxyImpl<'a> {
|
||||
credentials: &'a AuthIdentity,
|
||||
}
|
||||
|
||||
impl<'a> CredentialsProxyImpl<'a> {
|
||||
fn new(credentials: &'a AuthIdentity) -> Self {
|
||||
Self { credentials }
|
||||
}
|
||||
}
|
||||
|
||||
impl CredentialsProxy for CredentialsProxyImpl<'_> {
|
||||
type AuthenticationData = AuthIdentity;
|
||||
|
||||
fn auth_data_by_user(&mut self, username: &Username) -> std::io::Result<Self::AuthenticationData> {
|
||||
if username.account_name() != self.credentials.username.account_name() {
|
||||
return Err(std::io::Error::other("invalid username"));
|
||||
}
|
||||
|
||||
let mut data = self.credentials.clone();
|
||||
// keep the original user/domain
|
||||
data.username = username.clone();
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CredsspSequence<'a> {
|
||||
pub(crate) fn next_pdu_hint(&self) -> ConnectorResult<Option<&dyn PduHint>> {
|
||||
match &self.state {
|
||||
CredsspState::Ongoing => Ok(Some(&CREDSSP_TS_REQUEST_HINT)),
|
||||
CredsspState::Finished => Ok(None),
|
||||
CredsspState::ServerError(err) => Err(custom_err!("Credssp server error", err.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn init(
|
||||
creds: &'a AuthIdentity,
|
||||
client_computer_name: ServerName,
|
||||
public_key: Vec<u8>,
|
||||
kerberos_config: Option<KerberosConfig>,
|
||||
) -> ConnectorResult<Self> {
|
||||
let client_computer_name = client_computer_name.into_inner();
|
||||
let credentials = CredentialsProxyImpl::new(creds);
|
||||
let credssp_config: Box<dyn ProtocolConfig>;
|
||||
if let Some(ref krb_config) = kerberos_config {
|
||||
credssp_config = Box::new(Into::<sspi::KerberosConfig>::into(krb_config.clone()));
|
||||
} else {
|
||||
credssp_config = Box::<sspi::ntlm::NtlmConfig>::default();
|
||||
}
|
||||
|
||||
debug!(?credssp_config);
|
||||
let server = CredSspServer::new(
|
||||
public_key,
|
||||
credentials,
|
||||
ClientMode::Negotiate(sspi::NegotiateConfig {
|
||||
protocol_config: credssp_config,
|
||||
package_list: None,
|
||||
client_computer_name,
|
||||
}),
|
||||
)
|
||||
.map_err(|e| ConnectorError::new("CredSSP", ConnectorErrorKind::Credssp(e)))?;
|
||||
|
||||
let sequence = Self {
|
||||
server,
|
||||
state: CredsspState::Ongoing,
|
||||
};
|
||||
|
||||
Ok(sequence)
|
||||
}
|
||||
|
||||
/// Returns Some(ts_request) when a TS request is received from client,
|
||||
pub(crate) fn decode_client_message(&mut self, input: &[u8]) -> ConnectorResult<Option<TsRequest>> {
|
||||
match self.state {
|
||||
CredsspState::Ongoing => {
|
||||
let message = TsRequest::from_buffer(input).map_err(|e| custom_err!("TsRequest", e))?;
|
||||
debug!(?message, "Received");
|
||||
Ok(Some(message))
|
||||
}
|
||||
_ => Err(general_err!(
|
||||
"attempted to feed client request to CredSSP sequence in an unexpected state"
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn process_ts_request(&mut self, request: TsRequest) -> Result<ServerState, Box<ServerError>> {
|
||||
Ok(self.server.process(request)?)
|
||||
}
|
||||
|
||||
pub(crate) fn handle_process_result(
|
||||
&mut self,
|
||||
result: Result<ServerState, Box<ServerError>>,
|
||||
output: &mut WriteBuf,
|
||||
) -> ConnectorResult<Written> {
|
||||
let (ts_request, next_state) = match result {
|
||||
Ok(ServerState::ReplyNeeded(ts_request)) => (Some(ts_request), CredsspState::Ongoing),
|
||||
Ok(ServerState::Finished(_id)) => (None, CredsspState::Finished),
|
||||
Err(err) => (Some(err.ts_request), CredsspState::ServerError(err.error)),
|
||||
};
|
||||
|
||||
self.state = next_state;
|
||||
if let Some(ts_request) = ts_request {
|
||||
debug!(?ts_request, "Send");
|
||||
let length = usize::from(ts_request.buffer_len());
|
||||
let unfilled_buffer = output.unfilled_to(length);
|
||||
|
||||
ts_request
|
||||
.encode_ts_request(unfilled_buffer)
|
||||
.map_err(|e| custom_err!("TsRequest", e))?;
|
||||
|
||||
output.advance(length);
|
||||
|
||||
Ok(Written::from_size(length)?)
|
||||
} else {
|
||||
Ok(Written::Nothing)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,15 +3,20 @@ extern crate tracing;
|
|||
|
||||
use ironrdp_async::bytes::Bytes;
|
||||
use ironrdp_async::{single_sequence_step, Framed, FramedRead, FramedWrite, StreamWrapper};
|
||||
use ironrdp_connector::ConnectorResult;
|
||||
use ironrdp_connector::credssp::KerberosConfig;
|
||||
use ironrdp_connector::sspi::credssp::EarlyUserAuthResult;
|
||||
use ironrdp_connector::sspi::{AuthIdentity, Username};
|
||||
use ironrdp_connector::{custom_err, ConnectorResult, ServerName};
|
||||
use ironrdp_core::WriteBuf;
|
||||
|
||||
mod channel_connection;
|
||||
mod connection;
|
||||
mod credssp;
|
||||
mod finalization;
|
||||
mod util;
|
||||
|
||||
pub use ironrdp_connector::DesktopSize;
|
||||
use ironrdp_pdu::nego;
|
||||
|
||||
pub use self::channel_connection::{ChannelConnectionSequence, ChannelConnectionState};
|
||||
pub use self::connection::{Acceptor, AcceptorResult, AcceptorState};
|
||||
|
@ -46,6 +51,33 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn accept_credssp<S>(
|
||||
framed: &mut Framed<S>,
|
||||
acceptor: &mut Acceptor,
|
||||
client_computer_name: ServerName,
|
||||
public_key: Vec<u8>,
|
||||
kerberos_config: Option<KerberosConfig>,
|
||||
) -> ConnectorResult<()>
|
||||
where
|
||||
S: FramedRead + FramedWrite,
|
||||
{
|
||||
let mut buf = WriteBuf::new();
|
||||
|
||||
if acceptor.should_perform_credssp() {
|
||||
perform_credssp_step(
|
||||
framed,
|
||||
acceptor,
|
||||
&mut buf,
|
||||
client_computer_name,
|
||||
public_key,
|
||||
kerberos_config,
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn accept_finalize<S>(
|
||||
mut framed: Framed<S>,
|
||||
acceptor: &mut Acceptor,
|
||||
|
@ -63,3 +95,104 @@ where
|
|||
single_sequence_step(&mut framed, acceptor, &mut buf, unmatched.as_deref_mut()).await?;
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all, ret)]
|
||||
async fn perform_credssp_step<S>(
|
||||
framed: &mut Framed<S>,
|
||||
acceptor: &mut Acceptor,
|
||||
buf: &mut WriteBuf,
|
||||
client_computer_name: ServerName,
|
||||
public_key: Vec<u8>,
|
||||
kerberos_config: Option<KerberosConfig>,
|
||||
) -> ConnectorResult<()>
|
||||
where
|
||||
S: FramedRead + FramedWrite,
|
||||
{
|
||||
assert!(acceptor.should_perform_credssp());
|
||||
let AcceptorState::Credssp { protocol, .. } = acceptor.state else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
async fn credssp_loop<S>(
|
||||
framed: &mut Framed<S>,
|
||||
acceptor: &mut Acceptor,
|
||||
buf: &mut WriteBuf,
|
||||
client_computer_name: ServerName,
|
||||
public_key: Vec<u8>,
|
||||
kerberos_config: Option<KerberosConfig>,
|
||||
) -> ConnectorResult<()>
|
||||
where
|
||||
S: FramedRead + FramedWrite,
|
||||
{
|
||||
let creds = acceptor.creds.as_ref().unwrap();
|
||||
let username = Username::new(&creds.username, None).map_err(|e| custom_err!("invalid username", e))?;
|
||||
let identity = AuthIdentity {
|
||||
username,
|
||||
password: creds.password.clone().into(),
|
||||
};
|
||||
|
||||
let mut sequence =
|
||||
credssp::CredsspSequence::init(&identity, client_computer_name, public_key, kerberos_config)?;
|
||||
|
||||
loop {
|
||||
let Some(next_pdu_hint) = sequence.next_pdu_hint()? else {
|
||||
break;
|
||||
};
|
||||
|
||||
debug!(
|
||||
acceptor.state = ?acceptor.state,
|
||||
hint = ?next_pdu_hint,
|
||||
"Wait for PDU"
|
||||
);
|
||||
|
||||
let pdu = framed
|
||||
.read_by_hint(next_pdu_hint, None)
|
||||
.await
|
||||
.map_err(|e| ironrdp_connector::custom_err!("read frame by hint", e))?;
|
||||
|
||||
trace!(length = pdu.len(), "PDU received");
|
||||
|
||||
let Some(ts_request) = sequence.decode_client_message(&pdu)? else {
|
||||
break;
|
||||
};
|
||||
|
||||
let result = sequence.process_ts_request(ts_request);
|
||||
buf.clear();
|
||||
let written = sequence.handle_process_result(result, buf)?;
|
||||
|
||||
if let Some(response_len) = written.size() {
|
||||
let response = &buf[..response_len];
|
||||
trace!(response_len, "Send response");
|
||||
framed
|
||||
.write_all(response)
|
||||
.await
|
||||
.map_err(|e| ironrdp_connector::custom_err!("write all", e))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let result = match credssp_loop(framed, acceptor, buf, client_computer_name, public_key, kerberos_config).await {
|
||||
Ok(_) => EarlyUserAuthResult::Success,
|
||||
Err(err) => {
|
||||
warn!("credssp: {err}");
|
||||
EarlyUserAuthResult::AccessDenied
|
||||
}
|
||||
};
|
||||
|
||||
if protocol.intersects(nego::SecurityProtocol::HYBRID_EX) {
|
||||
trace!(?result, "HYBRID_EX");
|
||||
buf.clear();
|
||||
result
|
||||
.to_buffer(&mut *buf)
|
||||
.map_err(|e| ironrdp_connector::custom_err!("to_buffer", e))?;
|
||||
let response = &buf[..result.buffer_len()];
|
||||
framed
|
||||
.write_all(response)
|
||||
.await
|
||||
.map_err(|e| ironrdp_connector::custom_err!("write all", e))?;
|
||||
}
|
||||
acceptor.mark_credssp_as_done();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue