Merge pull request #4441 from akallabeth/paa

[cleanup] Support for gatewayaccesstoken / PAA
This commit is contained in:
Martin Fleisz 2018-02-19 17:28:32 +01:00 committed by GitHub
commit 3cfa837b0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 213 additions and 66 deletions

View File

@ -1898,6 +1898,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
settings->GatewayHttpTransport = TRUE;
}
}
CommandLineSwitchCase(arg, "gat")
{
free(settings->GatewayAccessToken);
if (!(settings->GatewayAccessToken = _strdup(arg->Value)))
return COMMAND_LINE_ERROR_MEMORY;
}
CommandLineSwitchCase(arg, "gateway-usage-method")
{
long type;

View File

@ -92,6 +92,7 @@ static COMMAND_LINE_ARGUMENT_A args[] =
{ "grab-keyboard", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Grab keyboard" },
{ "gt", COMMAND_LINE_VALUE_REQUIRED, "rpc|http|auto", NULL, NULL, -1, NULL, "Gateway transport type" },
{ "gu", COMMAND_LINE_VALUE_REQUIRED, "[<domain>\\]<user> or <user>[@<domain>]", NULL, NULL, -1, NULL, "Gateway username" },
{ "gat", COMMAND_LINE_VALUE_REQUIRED, "<access token>", NULL, NULL, -1, NULL, "Gateway Access Token" },
{ "h", COMMAND_LINE_VALUE_REQUIRED, "<height>", "768", NULL, -1, NULL, "Height" },
{ "heartbeat", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support heartbeat PDUs" },
{ "help", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, NULL, NULL, NULL, -1, "?", "Print help" },
@ -171,7 +172,7 @@ static COMMAND_LINE_ARGUMENT_A args[] =
{ "v", COMMAND_LINE_VALUE_REQUIRED, "<server>[:port]", NULL, NULL, -1, NULL, "Server hostname" },
{ "vc", COMMAND_LINE_VALUE_REQUIRED, "<channel>[,<options>]", NULL, NULL, -1, NULL, "Static virtual channel" },
{ "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, NULL, NULL, NULL, -1, NULL, "Print version" },
{ "video", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Video optimized remoting channel" },
{ "video", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Video optimized remoting channel" },
{ "vmconnect", COMMAND_LINE_VALUE_OPTIONAL, "<vmid>", NULL, NULL, -1, NULL, "Hyper-V console (use port 2179, disable negotiation)" },
{ "w", COMMAND_LINE_VALUE_REQUIRED, "<width>", "1024", NULL, -1, NULL, "Width" },
{ "wallpaper", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Enable wallpaper" },

View File

@ -288,6 +288,8 @@ static int freerdp_client_rdp_file_set_string(rdpFile* file, const char* name, c
tmp = &file->ShellWorkingDirectory;
else if (_stricmp(name, "gatewayhostname") == 0)
tmp = &file->GatewayHostname;
else if (_stricmp(name, "gatewayaccesstoken") == 0)
tmp = &file->GatewayAccessToken;
else if (_stricmp(name, "kdcproxyname") == 0)
tmp = &file->KdcProxyName;
else if (_stricmp(name, "drivestoredirect") == 0)
@ -598,6 +600,7 @@ BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, const rdpSett
}
SETTING_MODIFIED_SET_STRING(file->GatewayHostname, settings, GatewayHostname);
SETTING_MODIFIED_SET_STRING(file->GatewayAccessToken, settings, GatewayAccessToken);
SETTING_MODIFIED_SET(file->GatewayUsageMethod, settings, GatewayUsageMethod);
SETTING_MODIFIED_SET(file->PromptCredentialOnce, settings, GatewayUseSameCredentials);
SETTING_MODIFIED_SET(file->RemoteApplicationMode, settings, RemoteApplicationMode);
@ -893,6 +896,12 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
free(host);
}
if (~((size_t) file->GatewayAccessToken))
{
if (freerdp_set_param_string(settings, FreeRDP_GatewayAccessToken, file->GatewayAccessToken) != 0)
return FALSE;
}
if (~file->GatewayUsageMethod)
freerdp_set_gateway_usage_method(settings, file->GatewayUsageMethod);
@ -1314,6 +1323,7 @@ void freerdp_client_rdp_file_free(rdpFile* file)
freerdp_client_file_string_check_free(file->AlternateShell);
freerdp_client_file_string_check_free(file->ShellWorkingDirectory);
freerdp_client_file_string_check_free(file->GatewayHostname);
freerdp_client_file_string_check_free(file->GatewayAccessToken);
freerdp_client_file_string_check_free(file->KdcProxyName);
freerdp_client_file_string_check_free(file->DrivesToRedirect);
freerdp_client_file_string_check_free(file->DevicesToRedirect);

View File

@ -140,6 +140,7 @@ struct rdp_file
DWORD GatewayUsageMethod; /* gatewayusagemethod */
DWORD GatewayProfileUsageMethod; /* gatewayprofileusagemethod */
DWORD GatewayCredentialsSource; /* gatewaycredentialssource */
LPSTR GatewayAccessToken; /* gatewayaccesstoken */
DWORD UseRedirectionServerName; /* use redirection server name */

View File

@ -691,6 +691,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_GatewayRpcTransport 1994
#define FreeRDP_GatewayHttpTransport 1995
#define FreeRDP_GatewayUdpTransport 1996
#define FreeRDP_GatewayAccessToken 1997
#define FreeRDP_ProxyType 2015
#define FreeRDP_ProxyHostname 2016
#define FreeRDP_ProxyPort 2017
@ -1156,7 +1157,8 @@ struct rdp_settings
ALIGN64 BOOL GatewayRpcTransport; /* 1994 */
ALIGN64 BOOL GatewayHttpTransport; /* 1995 */
ALIGN64 BOOL GatewayUdpTransport; /* 1996 */
UINT64 padding2048[2015 - 1997]; /* 1997 */
ALIGN64 char* GatewayAccessToken; /* 1997 */
UINT64 padding2015[2015 - 1998]; /* 1998 */
/* Proxy */
ALIGN64 UINT32 ProxyType; /* 2015 */
@ -1449,6 +1451,7 @@ struct rdp_settings
ALIGN64 BYTE*
SettingsModified; /* byte array marking fields that have been modified from their default value */
ALIGN64 char* ActionScript;
};
typedef struct rdp_settings rdpSettings;

View File

@ -2503,6 +2503,9 @@ char* freerdp_get_param_string(rdpSettings* settings, int id)
case FreeRDP_GatewayDomain:
return settings->GatewayDomain;
case FreeRDP_GatewayAccessToken:
return settings->GatewayAccessToken;
case FreeRDP_ProxyHostname:
return settings->ProxyHostname;
@ -2713,6 +2716,10 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param)
tmp = &settings->GatewayDomain;
break;
case FreeRDP_GatewayAccessToken:
tmp = &settings->GatewayAccessToken;
break;
case FreeRDP_ProxyHostname:
tmp = &settings->ProxyHostname;
break;

View File

@ -181,6 +181,13 @@ BOOL http_context_set_rdg_connection_id(HttpContext* context, const char* RdgCon
return TRUE;
}
BOOL http_context_set_rdg_auth_scheme(HttpContext* context, const char* RdgAuthScheme)
{
free(context->RdgAuthScheme);
context->RdgAuthScheme = _strdup(RdgAuthScheme);
return context->RdgAuthScheme != NULL;
}
void http_context_free(HttpContext* context)
{
if (context)
@ -194,6 +201,7 @@ void http_context_free(HttpContext* context)
free(context->Connection);
free(context->Pragma);
free(context->RdgConnectionId);
free(context->RdgAuthScheme);
free(context);
}
}
@ -332,9 +340,29 @@ wStream* http_request_write(HttpContext* context, HttpRequest* request)
lines[count++] = http_encode_body_line("Pragma", context->Pragma);
lines[count++] = http_encode_body_line("Accept", context->Accept);
lines[count++] = http_encode_body_line("User-Agent", context->UserAgent);
lines[count++] = http_encode_content_length_line(request->ContentLength);
lines[count++] = http_encode_body_line("Host", context->Host);
if (!context->RdgAuthScheme)
lines[count++] = http_encode_content_length_line(request->ContentLength);
if (context->RdgConnectionId)
lines[count++] = http_encode_body_line("RDG-Connection-Id", context->RdgConnectionId);
if (context->RdgAuthScheme)
lines[count++] = http_encode_body_line("RDG-Auth-Scheme", context->RdgAuthScheme);
if (request->TransferEncoding)
lines[count++] = http_encode_body_line("Transfer-Encoding", request->TransferEncoding);
if (request->Authorization)
{
lines[count++] = http_encode_body_line("Authorization", request->Authorization);
}
else if (request->AuthScheme && request->AuthParam)
{
lines[count++] = http_encode_authorization_line(request->AuthScheme, request->AuthParam);
}
/* check that everything went well */
for (i = 0; i < count; i++)
{
@ -342,45 +370,6 @@ wStream* http_request_write(HttpContext* context, HttpRequest* request)
goto out_free;
}
if (context->RdgConnectionId)
{
lines[count] = http_encode_body_line("RDG-Connection-Id", context->RdgConnectionId);
if (!lines[count])
goto out_free;
count++;
}
if (request->TransferEncoding)
{
lines[count] = http_encode_body_line("Transfer-Encoding", request->TransferEncoding);
if (!lines[count])
goto out_free;
count++;
}
if (request->Authorization)
{
lines[count] = http_encode_body_line("Authorization", request->Authorization);
if (!lines[count])
goto out_free;
count++;
}
else if (request->AuthScheme && request->AuthParam)
{
lines[count] = http_encode_authorization_line(request->AuthScheme, request->AuthParam);
if (!lines[count])
goto out_free;
count++;
}
for (i = 0; i < count; i++)
{
length += (strlen(lines[i]) + 2); /* add +2 for each '\r\n' character */

View File

@ -42,6 +42,7 @@ struct _http_context
char* Connection;
char* Pragma;
char* RdgConnectionId;
char* RdgAuthScheme;
};
FREERDP_LOCAL BOOL http_context_set_method(HttpContext* context,
@ -61,6 +62,8 @@ FREERDP_LOCAL BOOL http_context_set_pragma(HttpContext* context,
const char* Pragma);
FREERDP_LOCAL BOOL http_context_set_rdg_connection_id(HttpContext* context,
const char* RdgConnectionId);
FREERDP_LOCAL BOOL http_context_set_rdg_auth_scheme(HttpContext* context,
const char* RdgAuthScheme);
HttpContext* http_context_new(void);
void http_context_free(HttpContext* context);

View File

@ -144,7 +144,7 @@ static BOOL rdg_send_handshake(rdpRdg* rdg)
Stream_Write_UINT8(s, 1); /* VersionMajor (1 byte) */
Stream_Write_UINT8(s, 0); /* VersionMinor (1 byte) */
Stream_Write_UINT16(s, 0); /* ClientVersion (2 bytes), must be 0 */
Stream_Write_UINT16(s, 0); /* ExtendedAuthentication (2 bytes) */
Stream_Write_UINT16(s, rdg->extAuth); /* ExtendedAuthentication (2 bytes) */
Stream_SealLength(s);
status = rdg_write_packet(rdg, s);
Stream_Free(s, TRUE);
@ -161,20 +161,54 @@ static BOOL rdg_send_tunnel_request(rdpRdg* rdg)
{
wStream* s;
BOOL status;
s = Stream_New(NULL, 16);
WCHAR* PAACookie = NULL;
UINT16 PAACookieLen = 0;
if (!s)
return FALSE;
if (rdg->extAuth == HTTP_EXTENDED_AUTH_PAA)
{
PAACookieLen = ConvertToUnicode(CP_UTF8, 0, rdg->settings->GatewayAccessToken, -1, &PAACookie, 0);
if (!PAACookie)
return FALSE;
s = Stream_New(NULL, 16 + 2 + 2 * PAACookieLen);
if (!s)
{
free(PAACookie);
return FALSE;
}
}
else
{
s = Stream_New(NULL, 16);
if (!s)
return FALSE;
}
Stream_Write_UINT16(s, PKT_TYPE_TUNNEL_CREATE); /* Type (2 bytes) */
Stream_Write_UINT16(s, 0); /* Reserved (2 bytes) */
Stream_Write_UINT32(s, 16); /* PacketLength (4 bytes) */
Stream_Write_UINT32(s, HTTP_CAPABILITY_TYPE_QUAR_SOH); /* CapabilityFlags (4 bytes) */
Stream_Write_UINT16(s, 0); /* FieldsPresent (2 bytes) */
Stream_Write_UINT16(s, 0); /* Reserved (2 bytes), must be 0 */
if (rdg->extAuth == HTTP_EXTENDED_AUTH_PAA)
{
Stream_Write_UINT16(s, 1); /* FieldsPresent (2 bytes) */
Stream_Write_UINT16(s, 0); /* Reserved (2 bytes), must be 0 */
Stream_Write_UINT16(s, PAACookieLen * 2); /* PAA cookie string length */
Stream_Write_UTF16_String(s, PAACookie, PAACookieLen);
}
else
{
Stream_Write_UINT16(s, 0); /* FieldsPresent (2 bytes) */
Stream_Write_UINT16(s, 0); /* Reserved (2 bytes), must be 0 */
}
Stream_SealLength(s);
status = rdg_write_packet(rdg, s);
Stream_Free(s, TRUE);
free(PAACookie);
if (status)
{
@ -326,6 +360,36 @@ static BOOL rdg_process_out_channel_response(rdpRdg* rdg, HttpResponse* response
BYTE* ntlmTokenData = NULL;
rdpNtlm* ntlm = rdg->ntlm;
if (rdg->extAuth == HTTP_EXTENDED_AUTH_PAA)
{
if (response->StatusCode == HTTP_STATUS_OK)
{
rdg->state = RDG_CLIENT_STATE_OUT_CHANNEL_AUTHORIZED;
/*
packet trace shows additional 10 bytes with value 0xabcdabcdabcdabcdabcd
which is not a normal header + data format
can't find any documentation on how to handle, chose to just read an extra 10 bytes
*/
s = Stream_New(NULL, 10);
if (!s)
return FALSE;
status = BIO_read(rdg->tlsOut->bio, Stream_Pointer(s), 10);
Stream_Free(s, TRUE);
if (status <= 0)
return FALSE;
return TRUE;
}
else
{
/* fallback to regular authentication scheme */
rdg->extAuth = HTTP_EXTENDED_AUTH_NONE;
}
}
if (response->StatusCode != HTTP_STATUS_DENIED)
{
WLog_DBG(TAG, "RDG not supported");
@ -392,6 +456,32 @@ static BOOL rdg_process_in_channel_response(rdpRdg* rdg, HttpResponse* response)
int ntlmTokenLength = 0;
BYTE* ntlmTokenData = NULL;
rdpNtlm* ntlm = rdg->ntlm;
if (rdg->extAuth == HTTP_EXTENDED_AUTH_PAA)
{
if (response->StatusCode == HTTP_STATUS_OK)
{
rdg->state = RDG_CLIENT_STATE_IN_CHANNEL_AUTHORIZED;
/* send http headers again */
s = rdg_build_http_request(rdg, "RDG_IN_DATA");
if (!s)
return FALSE;
status = tls_write_all(rdg->tlsIn, Stream_Buffer(s), Stream_Length(s));
Stream_Free(s, TRUE);
if (status < 0)
return FALSE;
return TRUE;
}
else
{
rdg->extAuth = HTTP_EXTENDED_AUTH_NONE;
}
}
WLog_DBG(TAG, "In Channel authorization required");
if (ListDictionary_Contains(response->Authenticates, "NTLM"))
@ -791,20 +881,25 @@ static BOOL rdg_send_out_channel_request(rdpRdg* rdg)
{
wStream* s = NULL;
int status;
rdg->ntlm = ntlm_new();
rdg->ntlm = NULL;
if (!rdg->ntlm)
return FALSE;
if (rdg->extAuth == HTTP_EXTENDED_AUTH_NONE)
{
rdg->ntlm = ntlm_new();
status = rdg_ncacn_http_ntlm_init(rdg, rdg->tlsOut);
if (!rdg->ntlm)
return FALSE;
if (!status)
return FALSE;
status = rdg_ncacn_http_ntlm_init(rdg, rdg->tlsOut);
status = ntlm_authenticate(rdg->ntlm);
if (!status)
return FALSE;
if (!status)
return FALSE;
status = ntlm_authenticate(rdg->ntlm);
if (!status)
return FALSE;
}
s = rdg_build_http_request(rdg, "RDG_OUT_DATA");
@ -825,20 +920,25 @@ static BOOL rdg_send_in_channel_request(rdpRdg* rdg)
{
int status;
wStream* s = NULL;
rdg->ntlm = ntlm_new();
rdg->ntlm = NULL;
if (!rdg->ntlm)
return FALSE;
if (rdg->extAuth == HTTP_EXTENDED_AUTH_NONE)
{
rdg->ntlm = ntlm_new();
status = rdg_ncacn_http_ntlm_init(rdg, rdg->tlsIn);
if (!rdg->ntlm)
return FALSE;
if (!status)
return FALSE;
status = rdg_ncacn_http_ntlm_init(rdg, rdg->tlsIn);
status = ntlm_authenticate(rdg->ntlm);
if (!status)
return FALSE;
if (!status)
return FALSE;
status = ntlm_authenticate(rdg->ntlm);
if (!status)
return FALSE;
}
s = rdg_build_http_request(rdg, "RDG_IN_DATA");
@ -1501,6 +1601,11 @@ rdpRdg* rdg_new(rdpTransport* transport)
rdg->state = RDG_CLIENT_STATE_INITIAL;
rdg->context = transport->context;
rdg->settings = rdg->context->settings;
rdg->extAuth = HTTP_EXTENDED_AUTH_NONE;
if (rdg->settings->GatewayAccessToken)
rdg->extAuth = HTTP_EXTENDED_AUTH_PAA;
UuidCreate(&rdg->guid);
rpcStatus = UuidToStringA(&rdg->guid, &stringUuid);
@ -1540,6 +1645,23 @@ rdpRdg* rdg_new(rdpTransport* transport)
goto rdg_alloc_error;
}
if (rdg->extAuth != HTTP_EXTENDED_AUTH_NONE)
{
switch (rdg->extAuth)
{
case HTTP_EXTENDED_AUTH_PAA:
http_context_set_rdg_auth_scheme(rdg->http, "PAA");
if (!rdg->http->RdgAuthScheme)
goto rdg_alloc_error;
break;
default:
WLog_DBG(TAG, "RDG extended authentication method %d not supported", rdg->extAuth);
}
}
rdg->frontBio = BIO_new(BIO_s_rdg());
if (!rdg->frontBio)

View File

@ -50,6 +50,7 @@ typedef struct rdp_rdg rdpRdg;
#define HTTP_EXTENDED_AUTH_NONE 0x0
#define HTTP_EXTENDED_AUTH_SC 0x1 /* Smart card authentication. */
#define HTTP_EXTENDED_AUTH_PAA 0x02 /* Pluggable authentication. */
#define HTTP_EXTENDED_AUTH_SSPI_NTLM 0x04 /* NTLM extended authentication. */
/* HTTP packet types. */
#define PKT_TYPE_HANDSHAKE_REQUEST 0x1
@ -140,6 +141,7 @@ struct rdp_rdg
int state;
UINT16 packetRemainingCount;
int timeout;
UINT16 extAuth;
};

View File

@ -692,6 +692,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
CHECKED_STRDUP(GatewayUsername); /* 1987 */
CHECKED_STRDUP(GatewayPassword); /* 1988 */
CHECKED_STRDUP(GatewayDomain); /* 1989 */
CHECKED_STRDUP(GatewayAccessToken); /* 1997 */
CHECKED_STRDUP(ProxyHostname); /* 2016 */
CHECKED_STRDUP(RemoteApplicationName); /* 2113 */
CHECKED_STRDUP(RemoteApplicationIcon); /* 2114 */
@ -1085,6 +1086,7 @@ void freerdp_settings_free(rdpSettings* settings)
free(settings->GatewayUsername);
free(settings->GatewayPassword);
free(settings->GatewayDomain);
free(settings->GatewayAccessToken);
free(settings->CertificateName);
free(settings->DynamicDSTTimeZoneKeyName);
free(settings->PreconnectionBlob);