mirror of
https://github.com/FreeRDP/FreeRDP.git
synced 2024-11-27 11:54:44 +08:00
libfreerdp-core: fix parsing of MCS Disconnect Provider Ultimatum, workaround for 2008 R2 lack of error info pdu on user logoff
This commit is contained in:
parent
c4492411e4
commit
fa12414a4b
@ -818,6 +818,54 @@ BOOL mcs_send_channel_join_confirm(rdpMcs* mcs, UINT16 channel_id)
|
||||
return (status < 0) ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive MCS Disconnect Provider Ultimatum PDU.\n
|
||||
* @param mcs mcs module
|
||||
*/
|
||||
|
||||
BOOL mcs_recv_disconnect_provider_ultimatum(rdpMcs* mcs, wStream* s, int* reason)
|
||||
{
|
||||
BYTE b1, b2;
|
||||
|
||||
/*
|
||||
* http://msdn.microsoft.com/en-us/library/cc240872.aspx:
|
||||
*
|
||||
* PER encoded (ALIGNED variant of BASIC-PER) PDU contents:
|
||||
* 21 80
|
||||
*
|
||||
* 0x21:
|
||||
* 0 - --\
|
||||
* 0 - |
|
||||
* 1 - | CHOICE: From DomainMCSPDU select disconnectProviderUltimatum (8)
|
||||
* 0 - | of type DisconnectProviderUltimatum
|
||||
* 0 - |
|
||||
* 0 - --/
|
||||
* 0 - --\
|
||||
* 1 - |
|
||||
* | DisconnectProviderUltimatum::reason = rn-user-requested (3)
|
||||
* 0x80: |
|
||||
* 1 - --/
|
||||
* 0 - padding
|
||||
* 0 - padding
|
||||
* 0 - padding
|
||||
* 0 - padding
|
||||
* 0 - padding
|
||||
* 0 - padding
|
||||
* 0 - padding
|
||||
*/
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 1)
|
||||
return FALSE;
|
||||
|
||||
Stream_Rewind_UINT8(s);
|
||||
Stream_Read_UINT8(s, b1);
|
||||
Stream_Read_UINT8(s, b2);
|
||||
|
||||
*reason = ((b1 & 0x01) << 1) | (b2 >> 7);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send MCS Disconnect Provider Ultimatum PDU.\n
|
||||
* @param mcs mcs module
|
||||
|
@ -20,6 +20,8 @@
|
||||
#ifndef __MCS_H
|
||||
#define __MCS_H
|
||||
|
||||
typedef struct rdp_mcs rdpMcs;
|
||||
|
||||
#include "transport.h"
|
||||
|
||||
#include <freerdp/crypto/ber.h>
|
||||
@ -52,6 +54,15 @@ enum MCS_Result
|
||||
MCS_Result_enum_length = 16
|
||||
};
|
||||
|
||||
enum MCS_Reason
|
||||
{
|
||||
MCS_Reason_domain_disconnected = 0,
|
||||
MCS_Reason_provider_initiated = 1,
|
||||
MCS_Reason_token_purged = 2,
|
||||
MCS_Reason_user_requested = 3,
|
||||
MCS_Reason_channel_purged = 4
|
||||
};
|
||||
|
||||
enum DomainMCSPDU
|
||||
{
|
||||
DomainMCSPDU_PlumbDomainIndication = 0,
|
||||
@ -115,7 +126,7 @@ typedef struct
|
||||
struct rdp_mcs
|
||||
{
|
||||
UINT16 user_id;
|
||||
struct rdp_transport* transport;
|
||||
rdpTransport* transport;
|
||||
DomainParameters domainParameters;
|
||||
DomainParameters targetParameters;
|
||||
DomainParameters minimumParameters;
|
||||
@ -124,7 +135,6 @@ struct rdp_mcs
|
||||
BOOL user_channel_joined;
|
||||
BOOL global_channel_joined;
|
||||
};
|
||||
typedef struct rdp_mcs rdpMcs;
|
||||
|
||||
#define MCS_SEND_DATA_HEADER_MAX_LENGTH 8
|
||||
|
||||
@ -148,6 +158,7 @@ BOOL mcs_recv_channel_join_request(rdpMcs* mcs, wStream* s, UINT16* channel_id);
|
||||
BOOL mcs_send_channel_join_request(rdpMcs* mcs, UINT16 channel_id);
|
||||
BOOL mcs_recv_channel_join_confirm(rdpMcs* mcs, wStream* s, UINT16* channel_id);
|
||||
BOOL mcs_send_channel_join_confirm(rdpMcs* mcs, UINT16 channel_id);
|
||||
BOOL mcs_recv_disconnect_provider_ultimatum(rdpMcs* mcs, wStream* s, int* reason);
|
||||
BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs);
|
||||
BOOL mcs_read_domain_mcspdu_header(wStream* s, enum DomainMCSPDU* domainMCSPDU, UINT16* length);
|
||||
void mcs_write_domain_mcspdu_header(wStream* s, enum DomainMCSPDU domainMCSPDU, UINT16 length, BYTE options);
|
||||
|
@ -229,6 +229,25 @@ wStream* rdp_data_pdu_init(rdpRdp* rdp)
|
||||
return s;
|
||||
}
|
||||
|
||||
BOOL rdp_set_error_info(rdpRdp* rdp, UINT32 errorInfo)
|
||||
{
|
||||
rdp->errorInfo = errorInfo;
|
||||
|
||||
if (rdp->errorInfo != ERRINFO_SUCCESS)
|
||||
{
|
||||
ErrorInfoEventArgs e;
|
||||
rdpContext* context = rdp->instance->context;
|
||||
|
||||
rdp_print_errinfo(rdp->errorInfo);
|
||||
|
||||
EventArgsInit(&e, "freerdp");
|
||||
e.code = rdp->errorInfo;
|
||||
PubSub_OnErrorInfo(context->pubSub, context, &e);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an RDP packet header.\n
|
||||
* @param rdp rdp module
|
||||
@ -256,12 +275,25 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId)
|
||||
|
||||
if (MCSPDU == DomainMCSPDU_DisconnectProviderUltimatum)
|
||||
{
|
||||
BYTE reason;
|
||||
int reason = 0;
|
||||
TerminateEventArgs e;
|
||||
rdpContext* context = rdp->instance->context;
|
||||
|
||||
(void) per_read_enumerated(s, &reason, 0);
|
||||
DEBUG_RDP("DisconnectProviderUltimatum from server, reason code 0x%02x\n", reason);
|
||||
if (!mcs_recv_disconnect_provider_ultimatum(rdp->mcs, s, &reason))
|
||||
return FALSE;
|
||||
|
||||
if (rdp->errorInfo == ERRINFO_SUCCESS)
|
||||
{
|
||||
/**
|
||||
* Some servers like Windows Server 2008 R2 do not send the error info pdu
|
||||
* when the user logs off like they should. Map DisconnectProviderUltimatum
|
||||
* to a ERRINFO_LOGOFF_BY_USER when the errinfo code is ERRINFO_SUCCESS.
|
||||
*/
|
||||
|
||||
rdp_set_error_info(rdp, ERRINFO_LOGOFF_BY_USER);
|
||||
}
|
||||
|
||||
fprintf(stderr, "DisconnectProviderUltimatum: reason: %d\n", reason);
|
||||
|
||||
rdp->disconnect = TRUE;
|
||||
|
||||
@ -503,22 +535,14 @@ BOOL rdp_send_data_pdu(rdpRdp* rdp, wStream* s, BYTE type, UINT16 channel_id)
|
||||
|
||||
BOOL rdp_recv_set_error_info_data_pdu(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
UINT32 errorInfo;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT32(s, rdp->errorInfo); /* errorInfo (4 bytes) */
|
||||
Stream_Read_UINT32(s, errorInfo); /* errorInfo (4 bytes) */
|
||||
|
||||
if (rdp->errorInfo != ERRINFO_SUCCESS)
|
||||
{
|
||||
ErrorInfoEventArgs e;
|
||||
rdpContext* context = rdp->instance->context;
|
||||
|
||||
rdp_print_errinfo(rdp->errorInfo);
|
||||
|
||||
EventArgsInit(&e, "freerdp");
|
||||
e.code = rdp->errorInfo;
|
||||
PubSub_OnErrorInfo(context->pubSub, context, &e);
|
||||
}
|
||||
rdp_set_error_info(rdp, errorInfo);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user