[rdg] implementation of http_extauth_sspi_ntlm

This commit is contained in:
akarl10 2022-11-16 15:10:27 +01:00 committed by akallabeth
parent 5b09cd57a7
commit b1583d56c0
6 changed files with 145 additions and 14 deletions

View File

@ -2964,15 +2964,27 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
else
{
char* c = strchr(arg->Value, ',');
if (c)
while (c)
{
char* next = strchr(c + 1, ',');
if (next)
*next = '\0';
*c++ = '\0';
if (!option_equals(c, "no-websockets"))
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets,
FALSE))
if (option_equals(c, "no-websockets"))
{
if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets,
FALSE))
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
}
else if (option_equals(c, "extauth-sspi-ntlm"))
{
if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpExtAuthSspiNtln,
TRUE))
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
}
else
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
c = next;
}
if (option_equals(arg->Value, "http"))

View File

@ -206,8 +206,9 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
{ "grab-keyboard", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL,
"Grab keyboard" },
{ "grab-mouse", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Grab mouse" },
{ "gt", COMMAND_LINE_VALUE_REQUIRED, "[rpc|http[,no-websockets]|auto[,no-websockets]]", NULL,
NULL, -1, NULL, "Gateway transport type" },
{ "gt", COMMAND_LINE_VALUE_REQUIRED,
"[rpc|http[,no-websockets][,extauth-sspi-ntlm]|auto[,no-websockets][,extauth-sspi-ntlm]]",
NULL, NULL, -1, NULL, "Gateway transport type" },
{ "gu", COMMAND_LINE_VALUE_REQUIRED, "[[<domain>\\]<user>|<user>[@<domain>]]", NULL, NULL, -1,
NULL, "Gateway username" },
{ "gat", COMMAND_LINE_VALUE_REQUIRED, "<access token>", NULL, NULL, -1, NULL,

View File

@ -772,6 +772,7 @@ typedef struct
#define FreeRDP_GatewayAcceptedCert (1998)
#define FreeRDP_GatewayAcceptedCertLength (1999)
#define FreeRDP_GatewayHttpUseWebsockets (2000)
#define FreeRDP_GatewayHttpExtAuthSspiNtln (2001)
#define FreeRDP_ProxyType (2015)
#define FreeRDP_ProxyHostname (2016)
#define FreeRDP_ProxyPort (2017)
@ -1337,7 +1338,8 @@ struct rdp_settings
ALIGN64 char* GatewayAcceptedCert; /* 1998 */
ALIGN64 UINT32 GatewayAcceptedCertLength; /* 1999 */
ALIGN64 BOOL GatewayHttpUseWebsockets; /* 2000 */
UINT64 padding2015[2015 - 2001]; /* 2001 */
ALIGN64 BOOL GatewayHttpExtAuthSspiNtln; /* 2001 */
UINT64 padding2015[2015 - 2002]; /* 2002 */
/* Proxy */
ALIGN64 UINT32 ProxyType; /* 2015 */

View File

@ -222,6 +222,9 @@ BOOL freerdp_settings_get_bool(const rdpSettings* settings, size_t id)
case FreeRDP_GatewayHttpUseWebsockets:
return settings->GatewayHttpUseWebsockets;
case FreeRDP_GatewayHttpExtAuthSspiNtln:
return settings->GatewayHttpExtAuthSspiNtln;
case FreeRDP_GatewayRpcTransport:
return settings->GatewayRpcTransport;
@ -829,6 +832,9 @@ BOOL freerdp_settings_set_bool(rdpSettings* settings, size_t id, BOOL val)
case FreeRDP_GatewayHttpUseWebsockets:
settings->GatewayHttpUseWebsockets = cnv.c;
break;
case FreeRDP_GatewayHttpExtAuthSspiNtln:
settings->GatewayHttpExtAuthSspiNtln = cnv.c;
break;
case FreeRDP_GatewayRpcTransport:
settings->GatewayRpcTransport = cnv.c;

View File

@ -1000,6 +1000,38 @@ static BOOL rdg_send_handshake(rdpRdg* rdg)
return status;
}
static BOOL rdg_send_extauth_sspi(rdpRdg* rdg)
{
wStream* s;
BOOL status;
UINT32 packetSize = 8 + 4 + 2;
WINPR_ASSERT(rdg);
const SecBuffer* authToken = credssp_auth_get_output_buffer(rdg->auth);
if (!authToken)
return FALSE;
packetSize += authToken->cbBuffer;
s = Stream_New(NULL, packetSize);
if (!s)
return FALSE;
Stream_Write_UINT16(s, PKT_TYPE_EXTENDED_AUTH_MSG); /* Type (2 bytes) */
Stream_Write_UINT16(s, 0); /* Reserved (2 bytes) */
Stream_Write_UINT32(s, packetSize); /* PacketLength (4 bytes) */
Stream_Write_UINT32(s, ERROR_SUCCESS); /* Error code */
Stream_Write_UINT16(s, (UINT16)authToken->cbBuffer);
Stream_Write(s, authToken->pvBuffer, authToken->cbBuffer);
Stream_SealLength(s);
status = rdg_write_packet(rdg, s);
Stream_Free(s, TRUE);
return status;
}
static BOOL rdg_send_tunnel_request(rdpRdg* rdg)
{
wStream* s;
@ -1308,6 +1340,9 @@ static BOOL rdg_process_handshake_response(rdpRdg* rdg, wStream* s)
return FALSE;
}
if (rdg->extAuth == HTTP_EXTENDED_AUTH_SSPI_NTLM)
return rdg_send_extauth_sspi(rdg);
return rdg_send_tunnel_request(rdg);
}
@ -1443,6 +1478,53 @@ static BOOL rdg_process_tunnel_authorization_response(rdpRdg* rdg, wStream* s)
return rdg_send_channel_create(rdg);
}
static BOOL rdg_process_extauth_sspi(rdpRdg* rdg, wStream* s)
{
UINT32 errorCode;
UINT16 authBlobLen;
SecBuffer authToken = { 0 };
BYTE* authTokenData = NULL;
WINPR_ASSERT(rdg);
Stream_Read_UINT32(s, errorCode);
Stream_Read_UINT16(s, authBlobLen);
if (errorCode != ERROR_SUCCESS)
{
WLog_ERR(TAG, "[%s] EXTAUTH_SSPI_NTLM failed with error %s [0x%08X]", __FUNCTION__,
GetSecurityStatusString(errorCode), errorCode);
return FALSE;
}
if (authBlobLen == 0)
{
if (credssp_auth_is_complete(rdg->auth))
{
credssp_auth_free(rdg->auth);
rdg->auth = NULL;
return rdg_send_tunnel_request(rdg);
}
return FALSE;
}
authTokenData = malloc(authBlobLen);
Stream_Read(s, authTokenData, authBlobLen);
authToken.pvBuffer = authTokenData;
authToken.cbBuffer = authBlobLen;
credssp_auth_take_input_buffer(rdg->auth, &authToken);
if (credssp_auth_authenticate(rdg->auth) < 0)
return FALSE;
if (credssp_auth_have_output_token(rdg->auth))
return rdg_send_extauth_sspi(rdg);
return FALSE;
}
static BOOL rdg_process_channel_response(rdpRdg* rdg, wStream* s)
{
UINT16 fieldsPresent;
@ -1519,6 +1601,14 @@ static BOOL rdg_process_packet(rdpRdg* rdg, wStream* s)
case PKT_TYPE_DATA:
WLog_ERR(TAG, "[%s] Unexpected packet type DATA", __FUNCTION__);
return FALSE;
case PKT_TYPE_EXTENDED_AUTH_MSG:
status = rdg_process_extauth_sspi(rdg, s);
break;
default:
WLog_ERR(TAG, "[%s] PKG TYPE 0x%x not implemented", __FUNCTION__, type);
return FALSE;
}
return status;
@ -1574,7 +1664,7 @@ static BOOL rdg_get_gateway_credentials(rdpContext* context, rdp_auth_reason rea
}
}
static BOOL rdg_auth_init(rdpRdg* rdg, rdpTls* tls)
static BOOL rdg_auth_init(rdpRdg* rdg, rdpTls* tls, TCHAR* authPkg)
{
rdpContext* context = rdg->context;
rdpSettings* settings = context->settings;
@ -1585,7 +1675,7 @@ static BOOL rdg_auth_init(rdpRdg* rdg, rdpTls* tls)
if (!rdg->auth)
return FALSE;
if (!credssp_auth_init(rdg->auth, AUTH_PKG, tls->Bindings))
if (!credssp_auth_init(rdg->auth, authPkg, tls->Bindings))
return FALSE;
if (freerdp_settings_get_bool(settings, FreeRDP_SmartcardLogon))
@ -1765,7 +1855,7 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
WINPR_ASSERT(rpcFallback);
if (rdg->extAuth == HTTP_EXTENDED_AUTH_NONE)
{
if (!rdg_auth_init(rdg, tls))
if (!rdg_auth_init(rdg, tls, AUTH_PKG))
return FALSE;
if (!rdg_send_http_request(rdg, tls, method, TransferEncodingIdentity))
@ -1880,7 +1970,13 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
rdg->transferEncoding.isWebsocketTransport = TRUE;
rdg->transferEncoding.context.websocket.state = WebsocketStateOpcodeAndFin;
rdg->transferEncoding.context.websocket.responseStreamBuffer = NULL;
if (rdg->extAuth == HTTP_EXTENDED_AUTH_SSPI_NTLM)
{
/* create a new auth context for SSPI_NTLM. This must be done after the last
* rdg_send_http_request */
if (!rdg_auth_init(rdg, tls, NTLM_SSP_NAME))
return FALSE;
}
return TRUE;
default:
return FALSE;
@ -1904,6 +2000,14 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
{
if (!rdg_send_http_request(rdg, tls, method, TransferEncodingChunked))
return FALSE;
if (rdg->extAuth == HTTP_EXTENDED_AUTH_SSPI_NTLM)
{
/* create a new auth context for SSPI_NTLM. This must be done after the last
* rdg_send_http_request (RDG_IN_DATA is always after RDG_OUT_DATA) */
if (!rdg_auth_init(rdg, tls, NTLM_SSP_NAME))
return FALSE;
}
}
return TRUE;
@ -2592,7 +2696,8 @@ rdpRdg* rdg_new(rdpContext* context)
rdg->state = RDG_CLIENT_STATE_INITIAL;
rdg->context = context;
rdg->settings = rdg->context->settings;
rdg->extAuth = HTTP_EXTENDED_AUTH_NONE;
rdg->extAuth = (rdg->settings->GatewayHttpExtAuthSspiNtln ? HTTP_EXTENDED_AUTH_SSPI_NTLM
: HTTP_EXTENDED_AUTH_NONE);
if (rdg->settings->GatewayAccessToken)
rdg->extAuth = HTTP_EXTENDED_AUTH_PAA;
@ -2643,6 +2748,10 @@ rdpRdg* rdg_new(rdpContext* context)
if (!http_context_set_rdg_auth_scheme(rdg->http, "PAA"))
goto rdg_alloc_error;
case HTTP_EXTENDED_AUTH_SSPI_NTLM:
if (!http_context_set_rdg_auth_scheme(rdg->http, "SSPI_NTLM"))
goto rdg_alloc_error;
break;
default:

View File

@ -601,6 +601,7 @@ rdpSettings* freerdp_settings_new(DWORD flags)
!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_GatewayUdpTransport, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpExtAuthSspiNtln, FALSE) ||
!freerdp_settings_set_bool(settings, FreeRDP_FastPathInput, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_FastPathOutput, TRUE) ||
!freerdp_settings_set_bool(settings, FreeRDP_LongCredentialsSupported, TRUE) ||