mirror of https://github.com/FreeRDP/FreeRDP
Merge remote-tracking branch 'origin/master' into tsmf-gstreamer-1.0
Conflicts: client/X11/xf_client.c
This commit is contained in:
commit
4325741583
|
@ -77,9 +77,11 @@ static void audin_server_select_format(audin_server_context* context, int client
|
|||
|
||||
static void audin_server_send_version(audin_server* audin, wStream* s)
|
||||
{
|
||||
ULONG written;
|
||||
|
||||
Stream_Write_UINT8(s, MSG_SNDIN_VERSION);
|
||||
Stream_Write_UINT32(s, 1); /* Version (4 bytes) */
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_version(audin_server* audin, wStream* s, UINT32 length)
|
||||
|
@ -101,6 +103,7 @@ static void audin_server_send_formats(audin_server* audin, wStream* s)
|
|||
{
|
||||
int i;
|
||||
UINT32 nAvgBytesPerSec;
|
||||
ULONG written;
|
||||
|
||||
Stream_SetPosition(s, 0);
|
||||
Stream_Write_UINT8(s, MSG_SNDIN_FORMATS);
|
||||
|
@ -131,7 +134,7 @@ static void audin_server_send_formats(audin_server* audin, wStream* s)
|
|||
}
|
||||
}
|
||||
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length)
|
||||
|
@ -181,6 +184,8 @@ static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 le
|
|||
|
||||
static void audin_server_send_open(audin_server* audin, wStream* s)
|
||||
{
|
||||
ULONG written;
|
||||
|
||||
if (audin->context.selected_client_format < 0)
|
||||
return;
|
||||
|
||||
|
@ -203,7 +208,7 @@ static void audin_server_send_open(audin_server* audin, wStream* s)
|
|||
Stream_Write_UINT16(s, 16); /* wBitsPerSample */
|
||||
Stream_Write_UINT16(s, 0); /* cbSize */
|
||||
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_open_reply(audin_server* audin, wStream* s, UINT32 length)
|
||||
|
|
|
@ -68,6 +68,7 @@ static int cliprdr_server_send_capabilities(CliprdrServerContext* context)
|
|||
BOOL status;
|
||||
UINT32 generalFlags;
|
||||
CLIPRDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("CliprdrServerSendCapabilities\n");
|
||||
|
||||
|
@ -96,7 +97,7 @@ static int cliprdr_server_send_capabilities(CliprdrServerContext* context)
|
|||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
|
@ -108,6 +109,7 @@ static int cliprdr_server_send_monitor_ready(CliprdrServerContext* context)
|
|||
wStream* s;
|
||||
BOOL status;
|
||||
CLIPRDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("CliprdrServerSendMonitorReady\n");
|
||||
|
||||
|
@ -123,7 +125,7 @@ static int cliprdr_server_send_monitor_ready(CliprdrServerContext* context)
|
|||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
|
@ -135,6 +137,7 @@ static int cliprdr_server_send_format_list_response(CliprdrServerContext* contex
|
|||
wStream* s;
|
||||
BOOL status;
|
||||
CLIPRDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("CliprdrServerSendFormatListResponse\n");
|
||||
|
||||
|
@ -150,7 +153,7 @@ static int cliprdr_server_send_format_list_response(CliprdrServerContext* contex
|
|||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ static int rdpdr_server_send_announce_request(RdpdrServerContext* context)
|
|||
wStream* s;
|
||||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("RdpdrServerSendAnnounceRequest\n");
|
||||
|
||||
|
@ -51,7 +52,7 @@ static int rdpdr_server_send_announce_request(RdpdrServerContext* context)
|
|||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
|
@ -295,6 +296,7 @@ static int rdpdr_server_send_core_capability_request(RdpdrServerContext* context
|
|||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
UINT16 numCapabilities;
|
||||
ULONG written;
|
||||
|
||||
printf("RdpdrServerSendCoreCapabilityRequest\n");
|
||||
|
||||
|
@ -319,7 +321,7 @@ static int rdpdr_server_send_core_capability_request(RdpdrServerContext* context
|
|||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
|
@ -376,6 +378,7 @@ static int rdpdr_server_send_client_id_confirm(RdpdrServerContext* context)
|
|||
wStream* s;
|
||||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("RdpdrServerSendClientIdConfirm\n");
|
||||
|
||||
|
@ -393,7 +396,7 @@ static int rdpdr_server_send_client_id_confirm(RdpdrServerContext* context)
|
|||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
|
@ -457,6 +460,7 @@ static int rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
|
|||
wStream* s;
|
||||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("%s\n", __FUNCTION__);
|
||||
|
||||
|
@ -470,7 +474,7 @@ static int rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
|
|||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ static BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s)
|
|||
int pos;
|
||||
UINT16 i;
|
||||
BOOL status;
|
||||
ULONG written;
|
||||
|
||||
Stream_Write_UINT8(s, SNDC_FORMATS);
|
||||
Stream_Write_UINT8(s, 0);
|
||||
|
@ -74,7 +75,7 @@ static BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s)
|
|||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
|
@ -199,13 +200,13 @@ static void* rdpsnd_server_thread(void* arg)
|
|||
|
||||
buffer = NULL;
|
||||
BytesReturned = 0;
|
||||
ChannelEvent = context->priv->ChannelHandle;
|
||||
ChannelEvent = NULL;
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
if (WTSVirtualChannelQuery(ChannelEvent, WTSVirtualEventHandle, &buffer, &BytesReturned))
|
||||
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned))
|
||||
{
|
||||
if (BytesReturned == sizeof(HANDLE))
|
||||
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
|
||||
|
@ -214,7 +215,8 @@ static void* rdpsnd_server_thread(void* arg)
|
|||
}
|
||||
|
||||
nCount = 0;
|
||||
events[nCount++] = ChannelEvent;
|
||||
if (ChannelEvent)
|
||||
events[nCount++] = ChannelEvent;
|
||||
events[nCount++] = context->priv->StopEvent;
|
||||
|
||||
if (!rdpsnd_server_send_formats(context, s))
|
||||
|
@ -230,7 +232,7 @@ static void* rdpsnd_server_thread(void* arg)
|
|||
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
if (!WTSVirtualChannelRead(ChannelEvent, 0, (PCHAR)Stream_Buffer(s),
|
||||
if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s),
|
||||
Stream_Capacity(s), &BytesReturned))
|
||||
{
|
||||
if (!BytesReturned)
|
||||
|
@ -238,7 +240,7 @@ static void* rdpsnd_server_thread(void* arg)
|
|||
|
||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
||||
|
||||
if (!WTSVirtualChannelRead(ChannelEvent, 0, (PCHAR)Stream_Buffer(s),
|
||||
if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s),
|
||||
Stream_Capacity(s), &BytesReturned))
|
||||
break;
|
||||
}
|
||||
|
@ -360,6 +362,7 @@ static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context)
|
|||
BOOL status;
|
||||
AUDIO_FORMAT* format;
|
||||
int tbytes_per_frame;
|
||||
ULONG written;
|
||||
wStream* s = context->priv->rdpsnd_pdu;
|
||||
|
||||
format = &context->client_formats[context->selected_client_format];
|
||||
|
@ -421,7 +424,7 @@ static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context)
|
|||
Stream_Seek(s, 3); /* bPad */
|
||||
Stream_Write(s, src, 4);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
if (!status)
|
||||
goto out;
|
||||
Stream_SetPosition(s, 0);
|
||||
|
@ -434,7 +437,7 @@ static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context)
|
|||
if (fill_size > 0)
|
||||
Stream_Zero(s, fill_size);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
|
||||
out:
|
||||
Stream_SetPosition(s, 0);
|
||||
|
@ -475,6 +478,7 @@ static BOOL rdpsnd_server_set_volume(RdpsndServerContext* context, int left, int
|
|||
{
|
||||
int pos;
|
||||
BOOL status;
|
||||
ULONG written;
|
||||
wStream* s = context->priv->rdpsnd_pdu;
|
||||
|
||||
Stream_Write_UINT8(s, SNDC_SETVOLUME);
|
||||
|
@ -488,7 +492,7 @@ static BOOL rdpsnd_server_set_volume(RdpsndServerContext* context, int left, int
|
|||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
|
@ -498,6 +502,7 @@ static BOOL rdpsnd_server_close(RdpsndServerContext* context)
|
|||
{
|
||||
int pos;
|
||||
BOOL status;
|
||||
ULONG written;
|
||||
wStream* s = context->priv->rdpsnd_pdu;
|
||||
|
||||
if (context->selected_client_format < 0)
|
||||
|
@ -519,7 +524,7 @@ static BOOL rdpsnd_server_close(RdpsndServerContext* context)
|
|||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
|
|
|
@ -509,7 +509,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
|||
|
||||
smartcard->log = WLog_Get("com.freerdp.channel.smartcard.client");
|
||||
|
||||
WLog_SetLogLevel(smartcard->log, WLOG_DEBUG);
|
||||
//WLog_SetLogLevel(smartcard->log, WLOG_DEBUG);
|
||||
|
||||
smartcard->IrpQueue = MessageQueue_New(NULL);
|
||||
smartcard->rgSCardContextList = ListDictionary_New(TRUE);
|
||||
|
|
|
@ -553,14 +553,14 @@ static UINT32 smartcard_ConnectA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE
|
|||
status = ret.ReturnCode = SCardConnectA(operation->hContext, (char*) call->szReader, call->Common.dwShareMode,
|
||||
call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), operation->hContext);
|
||||
smartcard_scard_handle_native_to_redir(smartcard, &(ret.hCard), hCard);
|
||||
|
||||
smartcard_trace_connect_return(smartcard, &ret);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = smartcard_pack_connect_return(smartcard, irp->output, &ret);
|
||||
|
||||
if (status)
|
||||
|
@ -605,14 +605,14 @@ static UINT32 smartcard_ConnectW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE
|
|||
status = ret.ReturnCode = SCardConnectW(operation->hContext, (WCHAR*) call->szReader, call->Common.dwShareMode,
|
||||
call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), operation->hContext);
|
||||
smartcard_scard_handle_native_to_redir(smartcard, &(ret.hCard), hCard);
|
||||
|
||||
smartcard_trace_connect_return(smartcard, &ret);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = smartcard_pack_connect_return(smartcard, irp->output, &ret);
|
||||
|
||||
if (status)
|
||||
|
|
|
@ -1890,6 +1890,12 @@ void smartcard_trace_get_attrib_return(SMARTCARD_DEVICE* smartcard, GetAttrib_Re
|
|||
{
|
||||
WLog_Print(smartcard->log, WLOG_DEBUG, "pbAttr: %.*s", ret->cbAttrLen, (char*) ret->pbAttr);
|
||||
}
|
||||
else if (dwAttrId == SCARD_ATTR_CURRENT_PROTOCOL_TYPE)
|
||||
{
|
||||
UINT32 dwProtocolType = *((UINT32*) ret->pbAttr);
|
||||
WLog_Print(smartcard->log, WLOG_DEBUG, "dwProtocolType: %s (0x%04X)",
|
||||
SCardGetProtocolString(dwProtocolType), dwProtocolType);
|
||||
}
|
||||
|
||||
WLog_Print(smartcard->log, WLOG_DEBUG, "}");
|
||||
}
|
||||
|
|
|
@ -914,7 +914,7 @@ static void xf_cliprdr_process_unicodetext(clipboardContext* cb, BYTE* data, int
|
|||
crlf2lf(cb->data, &cb->data_length);
|
||||
}
|
||||
|
||||
static void xf_cliprdr_process_dib(clipboardContext* cb, BYTE* data, int size)
|
||||
static BOOL xf_cliprdr_process_dib(clipboardContext* cb, BYTE* data, int size)
|
||||
{
|
||||
wStream* s;
|
||||
UINT16 bpp;
|
||||
|
@ -926,12 +926,18 @@ static void xf_cliprdr_process_dib(clipboardContext* cb, BYTE* data, int size)
|
|||
if (size < 40)
|
||||
{
|
||||
DEBUG_X11_CLIPRDR("dib size %d too short", size);
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
s = Stream_New(data, size);
|
||||
Stream_Seek(s, 14);
|
||||
Stream_Read_UINT16(s, bpp);
|
||||
if ((bpp < 1) || (bpp > 32))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, bpp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT32(s, ncolors);
|
||||
offset = 14 + 40 + (bpp <= 8 ? (ncolors == 0 ? (1 << bpp) : ncolors) * 4 : 0);
|
||||
Stream_Free(s, FALSE);
|
||||
|
@ -949,6 +955,7 @@ static void xf_cliprdr_process_dib(clipboardContext* cb, BYTE* data, int size)
|
|||
cb->data = Stream_Buffer(s);
|
||||
cb->data_length = Stream_GetPosition(s);
|
||||
Stream_Free(s, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void xf_cliprdr_process_html(clipboardContext* cb, BYTE* data, int size)
|
||||
|
|
|
@ -73,6 +73,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
|
|||
{ "gu", COMMAND_LINE_VALUE_REQUIRED, "[<domain>\\]<user> or <user>[@<domain>]", NULL, NULL, -1, NULL, "Gateway username" },
|
||||
{ "gp", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL, "Gateway password" },
|
||||
{ "gd", COMMAND_LINE_VALUE_REQUIRED, "<domain>", NULL, NULL, -1, NULL, "Gateway domain" },
|
||||
{ "gateway-usage-method", COMMAND_LINE_VALUE_REQUIRED, "<direct|detect>", NULL, NULL, -1, NULL, "Gateway usage method" },
|
||||
{ "load-balance-info", COMMAND_LINE_VALUE_REQUIRED, "<info string>", NULL, NULL, -1, NULL, "Load balance info" },
|
||||
{ "app", COMMAND_LINE_VALUE_REQUIRED, "<executable path> or <||alias>", NULL, NULL, -1, NULL, "Remote application program" },
|
||||
{ "app-name", COMMAND_LINE_VALUE_REQUIRED, "<app name>", NULL, NULL, -1, NULL, "Remote application name for user interface" },
|
||||
|
@ -1384,11 +1385,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
|
|||
settings->GatewayHostname = _strdup(settings->ServerHostname);
|
||||
}
|
||||
|
||||
settings->GatewayEnabled = TRUE;
|
||||
settings->GatewayUseSameCredentials = TRUE;
|
||||
|
||||
settings->GatewayUsageMethod = TSC_PROXY_MODE_DETECT;
|
||||
settings->GatewayEnabled = TRUE;
|
||||
settings->GatewayBypassLocal = TRUE;
|
||||
freerdp_set_gateway_usage_method(settings, TSC_PROXY_MODE_DETECT);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "gu")
|
||||
{
|
||||
|
@ -1412,6 +1412,27 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
|
|||
settings->GatewayPassword = _strdup(arg->Value);
|
||||
settings->GatewayUseSameCredentials = FALSE;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "gateway-usage-method")
|
||||
{
|
||||
int type;
|
||||
char* pEnd;
|
||||
|
||||
type = strtol(arg->Value, &pEnd, 10);
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
if (_stricmp(arg->Value, "none") == 0)
|
||||
type = TSC_PROXY_MODE_NONE_DIRECT;
|
||||
else if (_stricmp(arg->Value, "direct") == 0)
|
||||
type = TSC_PROXY_MODE_DIRECT;
|
||||
else if (_stricmp(arg->Value, "detect") == 0)
|
||||
type = TSC_PROXY_MODE_DETECT;
|
||||
else if (_stricmp(arg->Value, "default") == 0)
|
||||
type = TSC_PROXY_MODE_DEFAULT;
|
||||
}
|
||||
|
||||
freerdp_set_gateway_usage_method(settings, (UINT32) type);
|
||||
}
|
||||
CommandLineSwitchCase(arg, "app")
|
||||
{
|
||||
settings->RemoteApplicationProgram = _strdup(arg->Value);
|
||||
|
|
|
@ -802,12 +802,12 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
|
|||
*
|
||||
* Values:
|
||||
*
|
||||
* 0: The remote session will appear in a window.
|
||||
* 1: The remote session will appear full screen.
|
||||
* 1: The remote session will appear in a window.
|
||||
* 2: The remote session will appear full screen.
|
||||
*/
|
||||
|
||||
freerdp_set_param_bool(settings, FreeRDP_Fullscreen,
|
||||
(file->ScreenModeId == 1) ? TRUE : FALSE);
|
||||
(file->ScreenModeId == 2) ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
if (~((size_t) file->SmartSizing))
|
||||
|
|
|
@ -73,11 +73,18 @@ macro(add_complex_library)
|
|||
"MODULE;TYPE;MONOLITHIC"
|
||||
"SOURCES"
|
||||
${ARGN})
|
||||
|
||||
|
||||
string(TOUPPER "${${PREFIX}_MODULE}_TYPE" ${PREFIX}_TYPE_OPTION)
|
||||
string(REGEX REPLACE "-" "_" ${PREFIX}_TYPE_OPTION ${${PREFIX}_TYPE_OPTION})
|
||||
|
||||
if(${${PREFIX}_MONOLITHIC})
|
||||
add_library(${${PREFIX}_MODULE} ${${PREFIX}_TYPE} ${${PREFIX}_SOURCES})
|
||||
else()
|
||||
add_library(${${PREFIX}_MODULE} ${${PREFIX}_SOURCES})
|
||||
if (NOT DEFINED ${${PREFIX}_TYPE_OPTION})
|
||||
add_library(${${PREFIX}_MODULE} ${${PREFIX}_SOURCES})
|
||||
else()
|
||||
add_library(${${PREFIX}_MODULE} ${${${PREFIX}_TYPE_OPTION}} ${${PREFIX}_SOURCES})
|
||||
endif()
|
||||
endif()
|
||||
if (${PREFIX}_EXPORT)
|
||||
export_complex_library(LIBNAME ${${PREFIX}_MODULE})
|
||||
|
|
|
@ -54,6 +54,8 @@ if(MSVC)
|
|||
option(WITH_WIN8 "Use Windows 8 libraries" OFF)
|
||||
endif()
|
||||
|
||||
option(WITH_SMARTCARD_INSPECT "Enable SmartCard API Inspector" OFF)
|
||||
|
||||
option(BUILD_TESTING "Build unit tests" OFF)
|
||||
option(WITH_SAMPLE "Build sample code" OFF)
|
||||
|
||||
|
|
|
@ -48,7 +48,8 @@ FREERDP_API int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize
|
|||
FREERDP_API int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
|
||||
|
||||
FREERDP_API void mppc_set_compression_level(MPPC_CONTEXT* mppc, DWORD CompressionLevel);
|
||||
FREERDP_API void mppc_context_reset(MPPC_CONTEXT* mppc);
|
||||
|
||||
FREERDP_API void mppc_context_reset(MPPC_CONTEXT* mppc, BOOL flush);
|
||||
|
||||
FREERDP_API MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor);
|
||||
FREERDP_API void mppc_context_free(MPPC_CONTEXT* mppc);
|
||||
|
|
|
@ -51,7 +51,7 @@ extern "C" {
|
|||
FREERDP_API int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags);
|
||||
FREERDP_API int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
|
||||
|
||||
FREERDP_API void ncrush_context_reset(NCRUSH_CONTEXT* ncrush);
|
||||
FREERDP_API void ncrush_context_reset(NCRUSH_CONTEXT* ncrush, BOOL flush);
|
||||
|
||||
FREERDP_API NCRUSH_CONTEXT* ncrush_context_new(BOOL Compressor);
|
||||
FREERDP_API void ncrush_context_free(NCRUSH_CONTEXT* ncrush);
|
||||
|
|
|
@ -25,6 +25,30 @@
|
|||
|
||||
#include <freerdp/codec/mppc.h>
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
struct _XCRUSH_MATCH_INFO
|
||||
{
|
||||
UINT32 MatchOffset;
|
||||
UINT32 ChunkOffset;
|
||||
UINT32 MatchLength;
|
||||
};
|
||||
typedef struct _XCRUSH_MATCH_INFO XCRUSH_MATCH_INFO;
|
||||
|
||||
struct _XCRUSH_CHUNK
|
||||
{
|
||||
UINT32 offset;
|
||||
UINT32 next;
|
||||
};
|
||||
typedef struct _XCRUSH_CHUNK XCRUSH_CHUNK;
|
||||
|
||||
struct _XCRUSH_SIGNATURE
|
||||
{
|
||||
UINT16 seed;
|
||||
UINT16 size;
|
||||
};
|
||||
typedef struct _XCRUSH_SIGNATURE XCRUSH_SIGNATURE;
|
||||
|
||||
struct _RDP61_MATCH_DETAILS
|
||||
{
|
||||
UINT16 MatchLength;
|
||||
|
@ -43,6 +67,8 @@ struct _RDP61_COMPRESSED_DATA
|
|||
};
|
||||
typedef struct _RDP61_COMPRESSED_DATA RDP61_COMPRESSED_DATA;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
struct _XCRUSH_CONTEXT
|
||||
{
|
||||
BOOL Compressor;
|
||||
|
@ -52,6 +78,21 @@ struct _XCRUSH_CONTEXT
|
|||
UINT32 HistoryBufferSize;
|
||||
BYTE HistoryBuffer[2000000];
|
||||
BYTE BlockBuffer[16384];
|
||||
UINT32 CompressionFlags;
|
||||
|
||||
UINT32 SignatureIndex;
|
||||
UINT32 SignatureCount;
|
||||
XCRUSH_SIGNATURE Signatures[1000];
|
||||
|
||||
UINT32 ChunkHead;
|
||||
UINT32 ChunkTail;
|
||||
XCRUSH_CHUNK Chunks[65534];
|
||||
UINT16 NextChunks[65536];
|
||||
|
||||
UINT32 OriginalMatchCount;
|
||||
UINT32 OptimizedMatchCount;
|
||||
XCRUSH_MATCH_INFO OriginalMatches[1000];
|
||||
XCRUSH_MATCH_INFO OptimizedMatches[1000];
|
||||
};
|
||||
typedef struct _XCRUSH_CONTEXT XCRUSH_CONTEXT;
|
||||
|
||||
|
@ -62,7 +103,7 @@ extern "C" {
|
|||
FREERDP_API int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags);
|
||||
FREERDP_API int xcrush_decompress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
|
||||
|
||||
FREERDP_API void xcrush_context_reset(XCRUSH_CONTEXT* xcrush);
|
||||
FREERDP_API void xcrush_context_reset(XCRUSH_CONTEXT* xcrush, BOOL flush);
|
||||
|
||||
FREERDP_API XCRUSH_CONTEXT* xcrush_context_new(BOOL Compressor);
|
||||
FREERDP_API void xcrush_context_free(XCRUSH_CONTEXT* xcrush);
|
||||
|
|
|
@ -72,7 +72,6 @@ struct rdp_tls
|
|||
void* tsg;
|
||||
SSL_CTX* ctx;
|
||||
BYTE* PublicKey;
|
||||
BIO_METHOD* methods;
|
||||
DWORD PublicKeyLength;
|
||||
rdpSettings* settings;
|
||||
SecPkgContext_Bindings* Bindings;
|
||||
|
@ -81,6 +80,7 @@ struct rdp_tls
|
|||
int port;
|
||||
int alertLevel;
|
||||
int alertDescription;
|
||||
BOOL isGatewayTransport;
|
||||
};
|
||||
|
||||
FREERDP_API int tls_connect(rdpTls* tls, BIO *underlying);
|
||||
|
|
|
@ -26,6 +26,7 @@ typedef struct rdp_rail rdpRail;
|
|||
typedef struct rdp_cache rdpCache;
|
||||
typedef struct rdp_channels rdpChannels;
|
||||
typedef struct rdp_graphics rdpGraphics;
|
||||
typedef struct rdp_metrics rdpMetrics;
|
||||
|
||||
typedef struct rdp_freerdp freerdp;
|
||||
typedef struct rdp_context rdpContext;
|
||||
|
@ -39,6 +40,7 @@ typedef RDP_CLIENT_ENTRY_POINTS_V1 RDP_CLIENT_ENTRY_POINTS;
|
|||
#include <freerdp/types.h>
|
||||
#include <freerdp/error.h>
|
||||
#include <freerdp/event.h>
|
||||
#include <freerdp/metrics.h>
|
||||
#include <freerdp/settings.h>
|
||||
#include <freerdp/extension.h>
|
||||
|
||||
|
@ -117,7 +119,8 @@ struct rdp_context
|
|||
ALIGN64 rdpInput* input; /* 38 */
|
||||
ALIGN64 rdpUpdate* update; /* 39 */
|
||||
ALIGN64 rdpSettings* settings; /* 40 */
|
||||
UINT64 paddingC[64 - 41]; /* 41 */
|
||||
ALIGN64 rdpMetrics* metrics; /* 41 */
|
||||
UINT64 paddingC[64 - 42]; /* 42 */
|
||||
|
||||
UINT64 paddingD[96 - 64]; /* 64 */
|
||||
UINT64 paddingE[128 - 96]; /* 96 */
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Protocol Metrics
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_METRICS_H
|
||||
#define FREERDP_METRICS_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
|
||||
struct rdp_metrics
|
||||
{
|
||||
rdpContext* context;
|
||||
|
||||
UINT64 TotalCompressedBytes;
|
||||
UINT64 TotalUncompressedBytes;
|
||||
double TotalCompressionRatio;
|
||||
};
|
||||
|
||||
FREERDP_API double metrics_write_bytes(rdpMetrics* metrics, UINT32 UncompressedBytes, UINT32 CompressedBytes);
|
||||
|
||||
FREERDP_API rdpMetrics* metrics_new(rdpContext* context);
|
||||
FREERDP_API void metrics_free(rdpMetrics* metrics);
|
||||
|
||||
#endif /* FREERDP_METRICS_H */
|
||||
|
|
@ -1382,6 +1382,7 @@ FREERDP_API void freerdp_performance_flags_make(rdpSettings* settings);
|
|||
FREERDP_API void freerdp_performance_flags_split(rdpSettings* settings);
|
||||
|
||||
FREERDP_API void freerdp_set_gateway_usage_method(rdpSettings* settings, UINT32 GatewayUsageMethod);
|
||||
FREERDP_API void freerdp_update_gateway_usage_method(rdpSettings* settings, UINT32 GatewayEnabled, UINT32 GatewayBypassLocal);
|
||||
|
||||
FREERDP_API BOOL freerdp_get_param_bool(rdpSettings* settings, int id);
|
||||
FREERDP_API int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param);
|
||||
|
|
|
@ -207,7 +207,7 @@ int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** p
|
|||
else
|
||||
{
|
||||
/* Invalid CopyOffset Encoding */
|
||||
return -1;
|
||||
return -1001;
|
||||
}
|
||||
}
|
||||
else /* RDP4 */
|
||||
|
@ -245,7 +245,7 @@ int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** p
|
|||
else
|
||||
{
|
||||
/* Invalid CopyOffset Encoding */
|
||||
return -1;
|
||||
return -1002;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -409,7 +409,7 @@ int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** p
|
|||
else
|
||||
{
|
||||
/* Invalid LengthOfMatch Encoding */
|
||||
return -1;
|
||||
return -1003;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MPPC
|
||||
|
@ -510,12 +510,10 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD
|
|||
if (!pDstData)
|
||||
return -1;
|
||||
|
||||
DstSize = *pDstSize;
|
||||
|
||||
if (DstSize < SrcSize)
|
||||
return -1;
|
||||
|
||||
DstSize = SrcSize;
|
||||
if (*pDstSize > SrcSize)
|
||||
DstSize = SrcSize;
|
||||
else
|
||||
DstSize = *pDstSize;
|
||||
|
||||
BitStream_Attach(bs, pDstData, DstSize);
|
||||
|
||||
|
@ -546,9 +544,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD
|
|||
{
|
||||
if (((bs->position / 8) + 2) > (DstSize - 1))
|
||||
{
|
||||
ZeroMemory(HistoryBuffer, HistoryBufferSize);
|
||||
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
|
||||
mppc->HistoryOffset = HistoryBufferSize + 1;
|
||||
mppc_context_reset(mppc, TRUE);
|
||||
*pFlags |= PACKET_FLUSHED;
|
||||
*pFlags |= CompressionLevel;
|
||||
*ppDstData = pSrcData;
|
||||
|
@ -600,9 +596,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD
|
|||
|
||||
if (((bs->position / 8) + 7) > (DstSize - 1))
|
||||
{
|
||||
ZeroMemory(HistoryBuffer, HistoryBufferSize);
|
||||
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
|
||||
mppc->HistoryOffset = HistoryBufferSize + 1;
|
||||
mppc_context_reset(mppc, TRUE);
|
||||
*pFlags |= PACKET_FLUSHED;
|
||||
*pFlags |= CompressionLevel;
|
||||
*ppDstData = pSrcData;
|
||||
|
@ -759,9 +753,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD
|
|||
{
|
||||
if (((bs->position / 8) + 2) > (DstSize - 1))
|
||||
{
|
||||
ZeroMemory(HistoryBuffer, HistoryBufferSize);
|
||||
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
|
||||
mppc->HistoryOffset = HistoryBufferSize + 1;
|
||||
mppc_context_reset(mppc, TRUE);
|
||||
*pFlags |= PACKET_FLUSHED;
|
||||
*pFlags |= CompressionLevel;
|
||||
*ppDstData = pSrcData;
|
||||
|
@ -827,12 +819,16 @@ void mppc_set_compression_level(MPPC_CONTEXT* mppc, DWORD CompressionLevel)
|
|||
}
|
||||
}
|
||||
|
||||
void mppc_context_reset(MPPC_CONTEXT* mppc)
|
||||
void mppc_context_reset(MPPC_CONTEXT* mppc, BOOL flush)
|
||||
{
|
||||
ZeroMemory(&(mppc->HistoryBuffer), sizeof(mppc->HistoryBuffer));
|
||||
ZeroMemory(&(mppc->MatchBuffer), sizeof(mppc->MatchBuffer));
|
||||
|
||||
mppc->HistoryOffset = 0;
|
||||
if (flush)
|
||||
mppc->HistoryOffset = mppc->HistoryBufferSize + 1;
|
||||
else
|
||||
mppc->HistoryOffset = 0;
|
||||
|
||||
mppc->HistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryOffset]);
|
||||
}
|
||||
|
||||
|
@ -859,11 +855,7 @@ MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor)
|
|||
|
||||
mppc->bs = BitStream_New();
|
||||
|
||||
ZeroMemory(&(mppc->HistoryBuffer), sizeof(mppc->HistoryBuffer));
|
||||
ZeroMemory(&(mppc->MatchBuffer), sizeof(mppc->MatchBuffer));
|
||||
|
||||
mppc->HistoryOffset = 0;
|
||||
mppc->HistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryOffset]);
|
||||
mppc_context_reset(mppc, FALSE);
|
||||
}
|
||||
|
||||
return mppc;
|
||||
|
|
|
@ -2357,8 +2357,7 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
|||
|
||||
if ((DstPtr + 2) > DstEndPtr) /* PACKET_FLUSH #1 */
|
||||
{
|
||||
ncrush_context_reset(ncrush);
|
||||
ncrush->HistoryOffset = ncrush->HistoryBufferSize + 1;
|
||||
ncrush_context_reset(ncrush, TRUE);
|
||||
*pFlags = PACKET_FLUSHED;
|
||||
*pFlags |= CompressionLevel;
|
||||
*ppDstData = pSrcData;
|
||||
|
@ -2385,8 +2384,7 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
|||
|
||||
if ((DstPtr + 8) > DstEndPtr) /* PACKET_FLUSH #2 */
|
||||
{
|
||||
ncrush_context_reset(ncrush);
|
||||
ncrush->HistoryOffset = ncrush->HistoryBufferSize + 1;
|
||||
ncrush_context_reset(ncrush, TRUE);
|
||||
*pFlags = PACKET_FLUSHED;
|
||||
*pFlags |= CompressionLevel;
|
||||
*ppDstData = pSrcData;
|
||||
|
@ -2530,8 +2528,7 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
|||
{
|
||||
if ((DstPtr + 2) > DstEndPtr) /* PACKET_FLUSH #3 */
|
||||
{
|
||||
ncrush_context_reset(ncrush);
|
||||
ncrush->HistoryOffset = ncrush->HistoryBufferSize + 1;
|
||||
ncrush_context_reset(ncrush, TRUE);
|
||||
*pFlags = PACKET_FLUSHED;
|
||||
*pFlags |= CompressionLevel;
|
||||
*ppDstData = pSrcData;
|
||||
|
@ -2554,8 +2551,7 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
|||
|
||||
if ((DstPtr + 4) >= DstEndPtr) /* PACKET_FLUSH #4 */
|
||||
{
|
||||
ncrush_context_reset(ncrush);
|
||||
ncrush->HistoryOffset = ncrush->HistoryBufferSize + 1;
|
||||
ncrush_context_reset(ncrush, TRUE);
|
||||
*pFlags = PACKET_FLUSHED;
|
||||
*pFlags |= CompressionLevel;
|
||||
*ppDstData = pSrcData;
|
||||
|
@ -2648,7 +2644,7 @@ int ncrush_generate_tables(NCRUSH_CONTEXT *context)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void ncrush_context_reset(NCRUSH_CONTEXT* ncrush)
|
||||
void ncrush_context_reset(NCRUSH_CONTEXT* ncrush, BOOL flush)
|
||||
{
|
||||
ZeroMemory(&(ncrush->HistoryBuffer), sizeof(ncrush->HistoryBuffer));
|
||||
ZeroMemory(&(ncrush->OffsetCache), sizeof(ncrush->OffsetCache));
|
||||
|
@ -2656,7 +2652,11 @@ void ncrush_context_reset(NCRUSH_CONTEXT* ncrush)
|
|||
ZeroMemory(&(ncrush->MatchTable), sizeof(ncrush->MatchTable));
|
||||
ZeroMemory(&(ncrush->HashTable), sizeof(ncrush->HashTable));
|
||||
|
||||
ncrush->HistoryOffset = 0;
|
||||
if (flush)
|
||||
ncrush->HistoryOffset = ncrush->HistoryBufferSize + 1;
|
||||
else
|
||||
ncrush->HistoryOffset = 0;
|
||||
|
||||
ncrush->HistoryPtr = &(ncrush->HistoryBuffer[ncrush->HistoryOffset]);
|
||||
}
|
||||
|
||||
|
@ -2672,9 +2672,9 @@ NCRUSH_CONTEXT* ncrush_context_new(BOOL Compressor)
|
|||
|
||||
ZeroMemory(&(ncrush->OffsetCache), sizeof(ncrush->OffsetCache));
|
||||
|
||||
ncrush->HistoryEndOffset = 65535;
|
||||
|
||||
ncrush->HistoryBufferSize = 65536;
|
||||
ncrush->HistoryEndOffset = ncrush->HistoryBufferSize - 1;
|
||||
|
||||
ZeroMemory(&(ncrush->HistoryBuffer), sizeof(ncrush->HistoryBuffer));
|
||||
ncrush->HistoryBufferFence = 0xABABABAB;
|
||||
|
||||
|
@ -2684,7 +2684,7 @@ NCRUSH_CONTEXT* ncrush_context_new(BOOL Compressor)
|
|||
if (ncrush_generate_tables(ncrush) < 0)
|
||||
printf("ncrush_context_new: failed to initialize tables\n");
|
||||
|
||||
ncrush_context_reset(ncrush);
|
||||
ncrush_context_reset(ncrush, FALSE);
|
||||
}
|
||||
|
||||
return ncrush;
|
||||
|
|
|
@ -704,6 +704,38 @@ static const BYTE TEST_MPPC_BELLS_RDP5[] =
|
|||
"\x6c\x2e\x74\x6f\x6c\x6c\x73\x2c\xfa\x1b\x97\x33\x7e\x87\xe3\x32"
|
||||
"\x90\x80";
|
||||
|
||||
static const BYTE TEST_ISLAND_DATA[] =
|
||||
"No man is an island entire of itself; every man "
|
||||
"is a piece of the continent, a part of the main; "
|
||||
"if a clod be washed away by the sea, Europe "
|
||||
"is the less, as well as if a promontory were, as"
|
||||
"well as any manner of thy friends or of thine "
|
||||
"own were; any man's death diminishes me, "
|
||||
"because I am involved in mankind. "
|
||||
"And therefore never send to know for whom "
|
||||
"the bell tolls; it tolls for thee.";
|
||||
|
||||
static const BYTE TEST_ISLAND_DATA_RDP5[] =
|
||||
"\x4e\x6f\x20\x6d\x61\x6e\x20\x69\x73\x20\xf8\xd2\xd8\xc2\xdc\xc8"
|
||||
"\x40\xca\xdc\xe8\xd2\xe4\xca\x40\xde\xcc\x40\xd2\xe8\xe6\xca\xd8"
|
||||
"\xcc\x76\x40\xca\xec\xca\xe4\xf3\xfa\x71\x20\x70\x69\x65\x63\xfc"
|
||||
"\x12\xe8\xd0\xca\x40\xc6\xdf\xfb\xcd\xdf\xd0\x58\x40\xc2\x40\xe0"
|
||||
"\xc2\xe4\xe9\xfe\x63\xec\xc3\x6b\x0b\x4b\x71\xd9\x03\x4b\x37\xd7"
|
||||
"\x31\xb6\x37\xb2\x10\x31\x32\x90\x3b\xb0\xb9\xb4\x32\xb2\x10\x30"
|
||||
"\xbb\xb0\xbc\x90\x31\x3c\x90\x7e\x68\x73\x65\x61\x2c\x20\x45\x75"
|
||||
"\x72\x6f\x70\x65\xf2\x34\x7d\x38\x6c\x65\x73\x73\xf0\x69\xcc\x81"
|
||||
"\xdd\x95\xb1\xb0\x81\x85\xcf\xc0\x94\xe0\xe4\xde\xdb\xe2\xb3\x7f"
|
||||
"\x92\x4e\xec\xae\x4c\xbf\x86\x3f\x06\x0c\x2d\xde\x5d\x96\xe6\x57"
|
||||
"\x2f\x1e\x53\xc9\x03\x33\x93\x4b\x2b\x73\x23\x99\x03\x7f\xd2\xb6"
|
||||
"\x96\xef\x38\x1d\xdb\xbc\x24\x72\x65\x3b\xf5\x5b\xf8\x49\x3b\x99"
|
||||
"\x03\x23\x2b\x0b\xa3\x41\x03\x23\x4b\x6b\x4b\x73\x4f\x96\xce\x64"
|
||||
"\x0d\xbe\x19\x31\x32\xb1\xb0\xba\xb9\xb2\x90\x24\x90\x30\xb6\x90"
|
||||
"\x34\xb7\x3b\x37\xb6\x3b\x79\xd4\xd2\xdd\xec\x18\x6b\x69\x6e\x64"
|
||||
"\x2e\x20\x41\xf7\x33\xcd\x47\x26\x56\x66\xff\x74\x9b\xbd\xbf\x04"
|
||||
"\x0e\x7e\x31\x10\x3a\x37\x90\x35\xb7\x37\xbb\x90\x7d\x81\x03\xbb"
|
||||
"\x43\x7b\x6f\xa8\xe5\x8b\xd0\xf0\xe8\xde\xd8\xd8\xe7\xec\xf3\xa7"
|
||||
"\xe4\x7c\xa7\xe2\x9f\x01\x99\x4b\x80";
|
||||
|
||||
int test_MppcCompressBellsRdp5()
|
||||
{
|
||||
int status;
|
||||
|
@ -878,6 +910,55 @@ int test_MppcDecompressBellsRdp4()
|
|||
return 0;
|
||||
}
|
||||
|
||||
int test_MppcCompressIslandRdp5()
|
||||
{
|
||||
int status;
|
||||
UINT32 Flags;
|
||||
UINT32 SrcSize;
|
||||
BYTE* pSrcData;
|
||||
UINT32 DstSize;
|
||||
BYTE* pDstData;
|
||||
MPPC_CONTEXT* mppc;
|
||||
UINT32 expectedSize;
|
||||
BYTE OutputBuffer[65536];
|
||||
|
||||
mppc = mppc_context_new(1, TRUE);
|
||||
|
||||
SrcSize = sizeof(TEST_ISLAND_DATA) - 1;
|
||||
pSrcData = (BYTE*) TEST_ISLAND_DATA;
|
||||
expectedSize = sizeof(TEST_ISLAND_DATA_RDP5) - 1;
|
||||
|
||||
DstSize = sizeof(OutputBuffer);
|
||||
pDstData = OutputBuffer;
|
||||
|
||||
status = mppc_compress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
|
||||
|
||||
printf("Flags: 0x%04X DstSize: %d\n", Flags, DstSize);
|
||||
|
||||
if (DstSize != expectedSize)
|
||||
{
|
||||
printf("MppcCompressIslandRdp5: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(pDstData, TEST_ISLAND_DATA_RDP5, DstSize) != 0)
|
||||
{
|
||||
printf("MppcCompressIslandRdp5: output mismatch\n");
|
||||
|
||||
printf("Actual\n");
|
||||
BitDump(pDstData, DstSize * 8, 0);
|
||||
|
||||
printf("Expected\n");
|
||||
BitDump(TEST_ISLAND_DATA_RDP5, DstSize * 8, 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
mppc_context_free(mppc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_MppcCompressBufferRdp5()
|
||||
{
|
||||
int status;
|
||||
|
@ -960,6 +1041,9 @@ int test_MppcDecompressBufferRdp5()
|
|||
|
||||
int TestFreeRDPCodecMppc(int argc, char* argv[])
|
||||
{
|
||||
if (test_MppcCompressIslandRdp5() < 0)
|
||||
return -1;
|
||||
|
||||
if (test_MppcCompressBellsRdp5() < 0)
|
||||
return -1;
|
||||
|
||||
|
|
|
@ -3,8 +3,168 @@
|
|||
|
||||
#include <freerdp/codec/xcrush.h>
|
||||
|
||||
static const BYTE TEST_BELLS_DATA[] = "for.whom.the.bell.tolls,.the.bell.tolls.for.thee!";
|
||||
|
||||
static const BYTE TEST_BELLS_DATA_XCRUSH[] =
|
||||
"\x12\x00\x66\x6f\x72\x2e\x77\x68\x6f\x6d\x2e\x74\x68\x65\x2e\x62"
|
||||
"\x65\x6c\x6c\x2e\x74\x6f\x6c\x6c\x73\x2c\x2e\x74\x68\x65\x2e\x62"
|
||||
"\x65\x6c\x6c\x2e\x74\x6f\x6c\x6c\x73\x2e\x66\x6f\x72\x2e\x74\x68"
|
||||
"\x65";
|
||||
|
||||
static const BYTE TEST_ISLAND_DATA[] =
|
||||
"No man is an island entire of itself; every man "
|
||||
"is a piece of the continent, a part of the main; "
|
||||
"if a clod be washed away by the sea, Europe "
|
||||
"is the less, as well as if a promontory were, as"
|
||||
"well as any manner of thy friends or of thine "
|
||||
"own were; any man's death diminishes me, "
|
||||
"because I am involved in mankind. "
|
||||
"And therefore never send to know for whom "
|
||||
"the bell tolls; it tolls for thee.";
|
||||
|
||||
static const BYTE TEST_ISLAND_DATA_XCRUSH[] =
|
||||
"\x12\x61\x4e\x6f\x20\x6d\x61\x6e\x20\x69\x73\x20\xf8\xd2\xd8\xc2"
|
||||
"\xdc\xc8\x40\xca\xdc\xe8\xd2\xe4\xca\x40\xde\xcc\x40\xd2\xe8\xe6"
|
||||
"\xca\xd8\xcc\x76\x40\xca\xec\xca\xe4\xf3\xfa\x71\x20\x70\x69\x65"
|
||||
"\x63\xfc\x12\xe8\xd0\xca\x40\xc6\xdf\xfb\xcd\xdf\xd0\x58\x40\xc2"
|
||||
"\x40\xe0\xc2\xe4\xe9\xfe\x63\xec\xc3\x6b\x0b\x4b\x71\xd9\x03\x4b"
|
||||
"\x37\xd7\x31\xb6\x37\xb2\x10\x31\x32\x90\x3b\xb0\xb9\xb4\x32\xb2"
|
||||
"\x10\x30\xbb\xb0\xbc\x90\x31\x3c\x90\x7e\x68\x73\x65\x61\x2c\x20"
|
||||
"\x45\x75\x72\x6f\x70\x65\xf2\x34\x7d\x38\x6c\x65\x73\x73\xf0\x69"
|
||||
"\xcc\x81\xdd\x95\xb1\xb0\x81\x85\xcf\xc0\x94\xe0\xe4\xde\xdb\xe2"
|
||||
"\xb3\x7f\x92\x4e\xec\xae\x4c\xbf\x86\x3f\x06\x0c\x2d\xde\x5d\x96"
|
||||
"\xe6\x57\x2f\x1e\x53\xc9\x03\x33\x93\x4b\x2b\x73\x23\x99\x03\x7f"
|
||||
"\xd2\xb6\x96\xef\x38\x1d\xdb\xbc\x24\x72\x65\x3b\xf5\x5b\xf8\x49"
|
||||
"\x3b\x99\x03\x23\x2b\x0b\xa3\x41\x03\x23\x4b\x6b\x4b\x73\x4f\x96"
|
||||
"\xce\x64\x0d\xbe\x19\x31\x32\xb1\xb0\xba\xb9\xb2\x90\x24\x90\x30"
|
||||
"\xb6\x90\x34\xb7\x3b\x37\xb6\x3b\x79\xd4\xd2\xdd\xec\x18\x6b\x69"
|
||||
"\x6e\x64\x2e\x20\x41\xf7\x33\xcd\x47\x26\x56\x66\xff\x74\x9b\xbd"
|
||||
"\xbf\x04\x0e\x7e\x31\x10\x3a\x37\x90\x35\xb7\x37\xbb\x90\x7d\x81"
|
||||
"\x03\xbb\x43\x7b\x6f\xa8\xe5\x8b\xd0\xf0\xe8\xde\xd8\xd8\xe7\xec"
|
||||
"\xf3\xa7\xe4\x7c\xa7\xe2\x9f\x01\x99\x4b\x80";
|
||||
|
||||
int test_XCrushCompressBells()
|
||||
{
|
||||
int status;
|
||||
UINT32 Flags;
|
||||
UINT32 SrcSize;
|
||||
BYTE* pSrcData;
|
||||
UINT32 DstSize;
|
||||
BYTE* pDstData;
|
||||
UINT32 expectedSize;
|
||||
BYTE OutputBuffer[65536];
|
||||
XCRUSH_CONTEXT* xcrush;
|
||||
|
||||
xcrush = xcrush_context_new(TRUE);
|
||||
|
||||
SrcSize = sizeof(TEST_BELLS_DATA) - 1;
|
||||
pSrcData = (BYTE*) TEST_BELLS_DATA;
|
||||
expectedSize = sizeof(TEST_BELLS_DATA_XCRUSH) - 1;
|
||||
|
||||
pDstData = OutputBuffer;
|
||||
DstSize = sizeof(OutputBuffer);
|
||||
ZeroMemory(OutputBuffer, sizeof(OutputBuffer));
|
||||
|
||||
status = xcrush_compress(xcrush, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
|
||||
|
||||
printf("status: %d Flags: 0x%04X DstSize: %d\n", status, Flags, DstSize);
|
||||
|
||||
if (DstSize != expectedSize)
|
||||
{
|
||||
printf("XCrushCompressBells: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize);
|
||||
|
||||
printf("Actual\n");
|
||||
BitDump(pDstData, DstSize * 8, 0);
|
||||
|
||||
printf("Expected\n");
|
||||
BitDump(TEST_BELLS_DATA_XCRUSH, expectedSize * 8, 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(pDstData, TEST_BELLS_DATA_XCRUSH, DstSize) != 0)
|
||||
{
|
||||
printf("XCrushCompressBells: output mismatch\n");
|
||||
|
||||
printf("Actual\n");
|
||||
BitDump(pDstData, DstSize * 8, 0);
|
||||
|
||||
printf("Expected\n");
|
||||
BitDump(TEST_BELLS_DATA_XCRUSH, expectedSize * 8, 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
xcrush_context_free(xcrush);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_XCrushCompressIsland()
|
||||
{
|
||||
int status;
|
||||
UINT32 Flags;
|
||||
UINT32 SrcSize;
|
||||
BYTE* pSrcData;
|
||||
UINT32 DstSize;
|
||||
BYTE* pDstData;
|
||||
UINT32 expectedSize;
|
||||
BYTE OutputBuffer[65536];
|
||||
XCRUSH_CONTEXT* xcrush;
|
||||
|
||||
xcrush = xcrush_context_new(TRUE);
|
||||
|
||||
SrcSize = sizeof(TEST_ISLAND_DATA) - 1;
|
||||
pSrcData = (BYTE*) TEST_ISLAND_DATA;
|
||||
expectedSize = sizeof(TEST_ISLAND_DATA_XCRUSH) - 1;
|
||||
|
||||
pDstData = OutputBuffer;
|
||||
DstSize = sizeof(OutputBuffer);
|
||||
ZeroMemory(OutputBuffer, sizeof(OutputBuffer));
|
||||
|
||||
status = xcrush_compress(xcrush, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
|
||||
|
||||
printf("status: %d Flags: 0x%04X DstSize: %d\n", status, Flags, DstSize);
|
||||
|
||||
if (DstSize != expectedSize)
|
||||
{
|
||||
printf("XCrushCompressIsland: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize);
|
||||
|
||||
printf("Actual\n");
|
||||
BitDump(pDstData, DstSize * 8, 0);
|
||||
|
||||
printf("Expected\n");
|
||||
BitDump(TEST_ISLAND_DATA_XCRUSH, expectedSize * 8, 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(pDstData, TEST_ISLAND_DATA_XCRUSH, DstSize) != 0)
|
||||
{
|
||||
printf("XCrushCompressIsland: output mismatch\n");
|
||||
|
||||
printf("Actual\n");
|
||||
BitDump(pDstData, DstSize * 8, 0);
|
||||
|
||||
printf("Expected\n");
|
||||
BitDump(TEST_ISLAND_DATA_XCRUSH, expectedSize * 8, 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
xcrush_context_free(xcrush);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int TestFreeRDPCodecXCrush(int argc, char* argv[])
|
||||
{
|
||||
if (test_XCrushCompressBells() < 0)
|
||||
return -1;
|
||||
|
||||
if (test_XCrushCompressIsland() < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,647 @@
|
|||
|
||||
#include <freerdp/codec/xcrush.h>
|
||||
|
||||
const char* xcrush_get_level_2_compression_flags_string(UINT32 flags)
|
||||
{
|
||||
flags &= 0xE0;
|
||||
|
||||
if (flags == 0)
|
||||
return "PACKET_UNCOMPRESSED";
|
||||
else if (flags == PACKET_COMPRESSED)
|
||||
return "PACKET_COMPRESSED";
|
||||
else if (flags == PACKET_AT_FRONT)
|
||||
return "PACKET_AT_FRONT";
|
||||
else if (flags == PACKET_FLUSHED)
|
||||
return "PACKET_FLUSHED";
|
||||
else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT))
|
||||
return "PACKET_COMPRESSED | PACKET_AT_FRONT";
|
||||
else if (flags == (PACKET_COMPRESSED | PACKET_FLUSHED))
|
||||
return "PACKET_COMPRESSED | PACKET_FLUSHED";
|
||||
else if (flags == (PACKET_AT_FRONT | PACKET_FLUSHED))
|
||||
return "PACKET_AT_FRONT | PACKET_FLUSHED";
|
||||
else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED))
|
||||
return "PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED";
|
||||
|
||||
return "PACKET_UNKNOWN";
|
||||
}
|
||||
|
||||
const char* xcrush_get_level_1_compression_flags_string(UINT32 flags)
|
||||
{
|
||||
flags &= 0x17;
|
||||
|
||||
if (flags == 0)
|
||||
return "L1_UNKNOWN";
|
||||
else if (flags == L1_PACKET_AT_FRONT)
|
||||
return "L1_PACKET_AT_FRONT";
|
||||
else if (flags == L1_NO_COMPRESSION)
|
||||
return "L1_NO_COMPRESSION";
|
||||
else if (flags == L1_COMPRESSED)
|
||||
return "L1_COMPRESSED";
|
||||
else if (flags == L1_INNER_COMPRESSION)
|
||||
return "L1_INNER_COMPRESSION";
|
||||
else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION))
|
||||
return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION";
|
||||
else if (flags == (L1_PACKET_AT_FRONT | L1_COMPRESSED))
|
||||
return "L1_PACKET_AT_FRONT | L1_COMPRESSED";
|
||||
else if (flags == (L1_PACKET_AT_FRONT | L1_INNER_COMPRESSION))
|
||||
return "L1_PACKET_AT_FRONT | L1_INNER_COMPRESSION";
|
||||
else if (flags == (L1_NO_COMPRESSION | L1_COMPRESSED))
|
||||
return "L1_NO_COMPRESSION | L1_COMPRESSED";
|
||||
else if (flags == (L1_NO_COMPRESSION | L1_INNER_COMPRESSION))
|
||||
return "L1_NO_COMPRESSION | L1_INNER_COMPRESSION";
|
||||
else if (flags == (L1_COMPRESSED | L1_INNER_COMPRESSION))
|
||||
return "L1_COMPRESSED | L1_INNER_COMPRESSION";
|
||||
else if (flags == (L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION))
|
||||
return "L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION";
|
||||
else if (flags == (L1_PACKET_AT_FRONT | L1_COMPRESSED | L1_INNER_COMPRESSION))
|
||||
return "L1_PACKET_AT_FRONT | L1_COMPRESSED | L1_INNER_COMPRESSION";
|
||||
else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_INNER_COMPRESSION))
|
||||
return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_INNER_COMPRESSION";
|
||||
else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED))
|
||||
return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED";
|
||||
else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION))
|
||||
return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION";
|
||||
|
||||
return "L1_UNKNOWN";
|
||||
}
|
||||
|
||||
UINT32 xcrush_update_hash(BYTE* data, UINT32 size)
|
||||
{
|
||||
BYTE* end;
|
||||
UINT32 seed = 5381; /* same value as in djb2 */
|
||||
|
||||
if (size > 32)
|
||||
{
|
||||
size = 32;
|
||||
seed = 5413;
|
||||
}
|
||||
|
||||
end = &data[size - 4];
|
||||
|
||||
while (data < end)
|
||||
{
|
||||
seed += (data[3] ^ data[0]) + (data[1] << 8);
|
||||
data += 4;
|
||||
}
|
||||
|
||||
return (UINT16) seed;
|
||||
}
|
||||
|
||||
int xcrush_append_chunk(XCRUSH_CONTEXT* xcrush, BYTE* data, UINT32* beg, UINT32 end)
|
||||
{
|
||||
UINT16 seed;
|
||||
UINT32 size;
|
||||
|
||||
if (xcrush->SignatureIndex >= xcrush->SignatureCount)
|
||||
return 0;
|
||||
|
||||
size = end - *beg;
|
||||
|
||||
if (size > 65535)
|
||||
return 0;
|
||||
|
||||
if (size >= 15)
|
||||
{
|
||||
seed = xcrush_update_hash(&data[*beg], (UINT16) size);
|
||||
xcrush->Signatures[xcrush->SignatureIndex].size = size;
|
||||
xcrush->Signatures[xcrush->SignatureIndex].seed = seed;
|
||||
xcrush->SignatureIndex++;
|
||||
*beg = end;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xcrush_compute_chunks(XCRUSH_CONTEXT* xcrush, BYTE* data, UINT32 size, UINT32* pIndex)
|
||||
{
|
||||
UINT32 i = 0;
|
||||
UINT32 offset = 0;
|
||||
UINT32 rotation = 0;
|
||||
UINT32 accumulator = 0;
|
||||
|
||||
*pIndex = 0;
|
||||
xcrush->SignatureIndex = 0;
|
||||
|
||||
if (size < 128)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
rotation = _rotl(accumulator, 1);
|
||||
accumulator = data[i] ^ rotation;
|
||||
}
|
||||
|
||||
for (i = 0; i < size - 64; i++)
|
||||
{
|
||||
rotation = _rotl(accumulator, 1);
|
||||
accumulator = data[i + 32] ^ data[i] ^ rotation;
|
||||
|
||||
if (!(accumulator & 0x7F))
|
||||
{
|
||||
if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
|
||||
rotation = _rotl(accumulator, 1);
|
||||
accumulator = data[i + 32] ^ data[i] ^ rotation;
|
||||
|
||||
if (!(accumulator & 0x7F))
|
||||
{
|
||||
if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
|
||||
rotation = _rotl(accumulator, 1);
|
||||
accumulator = data[i + 32] ^ data[i] ^ rotation;
|
||||
|
||||
if (!(accumulator & 0x7F))
|
||||
{
|
||||
if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
|
||||
rotation = _rotl(accumulator, 1);
|
||||
accumulator = data[i + 32] ^ data[i] ^ rotation;
|
||||
|
||||
if (!(accumulator & 0x7F))
|
||||
{
|
||||
if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((size == offset) || xcrush_append_chunk(xcrush, data, &offset, size))
|
||||
{
|
||||
*pIndex = xcrush->SignatureIndex;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT32 xcrush_compute_signatures(XCRUSH_CONTEXT* xcrush, BYTE* data, UINT32 size)
|
||||
{
|
||||
UINT32 index = 0;
|
||||
|
||||
if (xcrush_compute_chunks(xcrush, data, size, &index))
|
||||
return index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xcrush_clear_hash_table_range(XCRUSH_CONTEXT* xcrush, UINT32 beg, UINT32 end)
|
||||
{
|
||||
UINT32 index;
|
||||
|
||||
for (index = 0; index < 65536; index++)
|
||||
{
|
||||
if (xcrush->NextChunks[index] >= beg)
|
||||
{
|
||||
if (xcrush->NextChunks[index] <= end)
|
||||
{
|
||||
xcrush->NextChunks[index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (index = 0; index < 65534; index++)
|
||||
{
|
||||
if (xcrush->Chunks[index].next >= beg )
|
||||
{
|
||||
if (xcrush->Chunks[index].next <= end)
|
||||
{
|
||||
xcrush->Chunks[index].next = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int xcrush_find_next_matching_chunk(XCRUSH_CONTEXT* xcrush, XCRUSH_CHUNK* chunk, XCRUSH_CHUNK** pNextChunk)
|
||||
{
|
||||
UINT32 index;
|
||||
XCRUSH_CHUNK* next = NULL;
|
||||
|
||||
if (!chunk)
|
||||
return -4001; /* error */
|
||||
|
||||
if (chunk->next)
|
||||
{
|
||||
index = (chunk - xcrush->Chunks) / sizeof(XCRUSH_CHUNK);
|
||||
|
||||
if (index >= 65534)
|
||||
return -4002; /* error */
|
||||
|
||||
if ((index < xcrush->ChunkHead) || (chunk->next >= xcrush->ChunkHead))
|
||||
{
|
||||
if (chunk->next >= 65534)
|
||||
return -4003; /* error */
|
||||
|
||||
next = &xcrush->Chunks[chunk->next];
|
||||
}
|
||||
}
|
||||
|
||||
*pNextChunk = next;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xcrush_insert_chunk(XCRUSH_CONTEXT* xcrush, XCRUSH_SIGNATURE* signature, UINT32 offset, XCRUSH_CHUNK** pPrevChunk)
|
||||
{
|
||||
UINT32 seed;
|
||||
UINT32 index;
|
||||
|
||||
if (xcrush->ChunkHead >= 65530)
|
||||
{
|
||||
xcrush->ChunkHead = 1;
|
||||
xcrush->ChunkTail = 1;
|
||||
}
|
||||
|
||||
if (xcrush->ChunkHead >= xcrush->ChunkTail)
|
||||
{
|
||||
xcrush_clear_hash_table_range(xcrush, xcrush->ChunkTail, xcrush->ChunkTail + 10000);
|
||||
xcrush->ChunkTail += 10000;
|
||||
}
|
||||
|
||||
index = xcrush->ChunkHead++;
|
||||
|
||||
if (xcrush->ChunkHead >= 65534)
|
||||
return -3001; /* error */
|
||||
|
||||
xcrush->Chunks[index].offset = offset;
|
||||
|
||||
seed = signature->seed;
|
||||
|
||||
if (seed >= 65536)
|
||||
return -3002; /* error */
|
||||
|
||||
if (xcrush->NextChunks[seed])
|
||||
{
|
||||
if (xcrush->NextChunks[seed] >= 65534)
|
||||
return -3003; /* error */
|
||||
|
||||
*pPrevChunk = &xcrush->Chunks[xcrush->NextChunks[seed]];
|
||||
}
|
||||
|
||||
xcrush->Chunks[index].next = xcrush->NextChunks[seed] & 0xFFFF;
|
||||
xcrush->NextChunks[seed] = index;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xcrush_find_match_length(XCRUSH_CONTEXT* xcrush, UINT32 MatchOffset, UINT32 ChunkOffset, UINT32 HistoryOffset, UINT32 SrcSize, UINT32 MaxMatchLength, XCRUSH_MATCH_INFO* MatchInfo)
|
||||
{
|
||||
UINT32 MatchSymbol;
|
||||
UINT32 ChunkSymbol;
|
||||
BYTE* ChunkBuffer;
|
||||
BYTE* MatchBuffer;
|
||||
BYTE* MatchStartPtr;
|
||||
BYTE* ForwardChunkPtr;
|
||||
BYTE* ReverseChunkPtr;
|
||||
BYTE* ForwardMatchPtr;
|
||||
BYTE* ReverseMatchPtr;
|
||||
BYTE* HistoryBufferEnd;
|
||||
UINT32 ReverseMatchLength;
|
||||
UINT32 ForwardMatchLength;
|
||||
UINT32 TotalMatchLength;
|
||||
BYTE* HistoryBuffer;
|
||||
UINT32 HistoryBufferSize;
|
||||
|
||||
ForwardMatchLength = 0;
|
||||
ReverseMatchLength = 0;
|
||||
|
||||
HistoryBuffer = xcrush->HistoryBuffer;
|
||||
HistoryBufferSize = xcrush->HistoryBufferSize;
|
||||
HistoryBufferEnd = &HistoryBuffer[HistoryOffset + SrcSize];
|
||||
|
||||
if (MatchOffset > HistoryBufferSize)
|
||||
return -2001; /* error */
|
||||
|
||||
MatchBuffer = &HistoryBuffer[MatchOffset];
|
||||
|
||||
if (ChunkOffset > HistoryBufferSize)
|
||||
return -2002; /* error */
|
||||
|
||||
ChunkBuffer = &HistoryBuffer[ChunkOffset];
|
||||
|
||||
if (MatchOffset == ChunkOffset)
|
||||
return -2003; /* error */
|
||||
|
||||
if (MatchBuffer < HistoryBuffer)
|
||||
return -2004; /* error */
|
||||
|
||||
if (ChunkBuffer < HistoryBuffer)
|
||||
return -2005; /* error */
|
||||
|
||||
ForwardMatchPtr = &HistoryBuffer[MatchOffset];
|
||||
ForwardChunkPtr = &HistoryBuffer[ChunkOffset];
|
||||
|
||||
if ((&MatchBuffer[MaxMatchLength + 1] < HistoryBufferEnd)
|
||||
&& (MatchBuffer[MaxMatchLength + 1] != ChunkBuffer[MaxMatchLength + 1]))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
MatchSymbol = *ForwardMatchPtr++;
|
||||
ChunkSymbol = *ForwardChunkPtr++;
|
||||
|
||||
if (MatchSymbol != ChunkSymbol)
|
||||
break;
|
||||
|
||||
if (ForwardMatchPtr > HistoryBufferEnd)
|
||||
break;
|
||||
|
||||
ForwardMatchLength++;
|
||||
}
|
||||
|
||||
ReverseMatchPtr = MatchBuffer - 1;
|
||||
ReverseChunkPtr = ChunkBuffer - 1;
|
||||
|
||||
while((ReverseMatchPtr > &HistoryBuffer[HistoryOffset])
|
||||
&& (ReverseChunkPtr > HistoryBuffer)
|
||||
&& (*ReverseMatchPtr == *ReverseChunkPtr))
|
||||
{
|
||||
ReverseMatchLength++;
|
||||
ReverseMatchPtr--;
|
||||
ReverseChunkPtr--;
|
||||
}
|
||||
|
||||
MatchStartPtr = MatchBuffer - ReverseMatchLength;
|
||||
TotalMatchLength = ReverseMatchLength + ForwardMatchLength;
|
||||
|
||||
if (TotalMatchLength < 11)
|
||||
return 0;
|
||||
|
||||
if (MatchStartPtr < HistoryBuffer)
|
||||
return -2006; /* error */
|
||||
|
||||
MatchInfo->MatchOffset = MatchStartPtr - HistoryBuffer;
|
||||
MatchInfo->ChunkOffset = ChunkBuffer - ReverseMatchLength - HistoryBuffer;
|
||||
MatchInfo->MatchLength = TotalMatchLength;
|
||||
|
||||
return (int) TotalMatchLength;
|
||||
}
|
||||
|
||||
int xcrush_find_all_matches(XCRUSH_CONTEXT* xcrush, UINT32 SignatureIndex, UINT32 HistoryOffset, UINT32 SrcOffset, UINT32 SrcSize)
|
||||
{
|
||||
UINT32 i = 0;
|
||||
UINT32 j = 0;
|
||||
int status = 0;
|
||||
UINT32 offset = 0;
|
||||
UINT32 ChunkIndex = 0;
|
||||
UINT32 ChunkCount = 0;
|
||||
XCRUSH_CHUNK* chunk = NULL;
|
||||
UINT32 MatchLength = 0;
|
||||
UINT32 MaxMatchLength = 0;
|
||||
UINT32 PrevMatchEnd = 0;
|
||||
XCRUSH_MATCH_INFO MatchInfo = { 0 };
|
||||
XCRUSH_MATCH_INFO MaxMatchInfo = { 0 };
|
||||
XCRUSH_SIGNATURE* Signatures = NULL;
|
||||
|
||||
Signatures = xcrush->Signatures;
|
||||
|
||||
for (i = 0; i < SignatureIndex; i++)
|
||||
{
|
||||
offset = SrcOffset + HistoryOffset;
|
||||
|
||||
if (!Signatures[i].size)
|
||||
return -1001; /* error */
|
||||
|
||||
status = xcrush_insert_chunk(xcrush, &Signatures[i], offset, &chunk);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (chunk && (SrcOffset + HistoryOffset + Signatures[i].size >= PrevMatchEnd))
|
||||
{
|
||||
ChunkCount = 0;
|
||||
MaxMatchLength = 0;
|
||||
ZeroMemory(&MaxMatchInfo, sizeof(XCRUSH_MATCH_INFO));
|
||||
|
||||
while (chunk)
|
||||
{
|
||||
if ((chunk->offset < HistoryOffset) || (chunk->offset < offset)
|
||||
|| (chunk->offset > SrcSize + HistoryOffset))
|
||||
{
|
||||
status = xcrush_find_match_length(xcrush, offset, chunk->offset,
|
||||
HistoryOffset, SrcSize, MaxMatchLength, &MatchInfo);
|
||||
|
||||
if (status < 0)
|
||||
return status; /* error */
|
||||
|
||||
MatchLength = (UINT32) status;
|
||||
|
||||
if (MatchLength > MaxMatchLength)
|
||||
{
|
||||
MaxMatchLength = MatchLength;
|
||||
MaxMatchInfo.MatchOffset = MatchInfo.MatchOffset;
|
||||
MaxMatchInfo.ChunkOffset = MatchInfo.ChunkOffset;
|
||||
MaxMatchInfo.MatchLength = MatchInfo.MatchLength;
|
||||
|
||||
if (MatchLength > 256)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ChunkIndex = ChunkCount++;
|
||||
|
||||
if (ChunkIndex > 4)
|
||||
break;
|
||||
|
||||
status = xcrush_find_next_matching_chunk(xcrush, chunk, &chunk);
|
||||
|
||||
if (status < 0)
|
||||
return status; /* error */
|
||||
}
|
||||
|
||||
if (MaxMatchLength)
|
||||
{
|
||||
xcrush->OriginalMatches[j].MatchOffset = MaxMatchInfo.MatchOffset;
|
||||
xcrush->OriginalMatches[j].ChunkOffset = MaxMatchInfo.ChunkOffset;
|
||||
xcrush->OriginalMatches[j].MatchLength = MaxMatchInfo.MatchLength;
|
||||
|
||||
if (xcrush->OriginalMatches[j].MatchOffset < HistoryOffset)
|
||||
return -1002; /* error */
|
||||
|
||||
PrevMatchEnd = xcrush->OriginalMatches[j].MatchLength + xcrush->OriginalMatches[j].MatchOffset;
|
||||
|
||||
j++;
|
||||
|
||||
if (j >= 1000)
|
||||
return -1003; /* error */
|
||||
}
|
||||
}
|
||||
|
||||
SrcOffset += Signatures[i].size;
|
||||
|
||||
if (SrcOffset > SrcSize)
|
||||
return -1004; /* error */
|
||||
}
|
||||
|
||||
if (SrcOffset > SrcSize)
|
||||
return -1005; /* error */
|
||||
|
||||
return (int) j;
|
||||
}
|
||||
|
||||
int xcrush_optimize_matches(XCRUSH_CONTEXT* xcrush)
|
||||
{
|
||||
UINT32 i, j;
|
||||
UINT32 MatchDiff;
|
||||
UINT32 PrevMatchEnd;
|
||||
UINT32 TotalMatchLength;
|
||||
UINT32 OriginalMatchCount;
|
||||
UINT32 OptimizedMatchCount;
|
||||
XCRUSH_MATCH_INFO* OriginalMatch;
|
||||
XCRUSH_MATCH_INFO* OptimizedMatch;
|
||||
XCRUSH_MATCH_INFO* OriginalMatches;
|
||||
XCRUSH_MATCH_INFO* OptimizedMatches;
|
||||
|
||||
i = j = 0;
|
||||
PrevMatchEnd = 0;
|
||||
TotalMatchLength = 0;
|
||||
|
||||
OriginalMatches = xcrush->OriginalMatches;
|
||||
OriginalMatchCount = xcrush->OriginalMatchCount;
|
||||
|
||||
OptimizedMatches = xcrush->OptimizedMatches;
|
||||
OptimizedMatchCount = xcrush->OptimizedMatchCount;
|
||||
|
||||
for (i = 0; i < OriginalMatchCount; i++)
|
||||
{
|
||||
if (OriginalMatches[i].MatchOffset <= PrevMatchEnd)
|
||||
{
|
||||
if ((OriginalMatches[i].MatchOffset < PrevMatchEnd)
|
||||
&& (OriginalMatches[i].MatchLength + OriginalMatches[i].MatchOffset > PrevMatchEnd + 6))
|
||||
{
|
||||
MatchDiff = PrevMatchEnd - OriginalMatches[i].MatchOffset;
|
||||
|
||||
OriginalMatch = &OriginalMatches[i];
|
||||
OptimizedMatch = &OptimizedMatches[j];
|
||||
|
||||
OptimizedMatch->MatchOffset = OriginalMatch->MatchOffset;
|
||||
OptimizedMatch->ChunkOffset = OriginalMatch->ChunkOffset;
|
||||
OptimizedMatch->MatchLength = OriginalMatch->MatchLength;
|
||||
|
||||
if (OptimizedMatches[j].MatchLength <= MatchDiff)
|
||||
return -5001; /* error */
|
||||
|
||||
if (MatchDiff >= 20000)
|
||||
return -5002; /* error */
|
||||
|
||||
OptimizedMatches[j].MatchLength -= MatchDiff;
|
||||
OptimizedMatches[j].MatchOffset += MatchDiff;
|
||||
OptimizedMatches[j].ChunkOffset += MatchDiff;
|
||||
|
||||
PrevMatchEnd = OptimizedMatches[j].MatchLength + OptimizedMatches[j].MatchOffset;
|
||||
TotalMatchLength += OptimizedMatches[j].MatchLength;
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OriginalMatch = &OriginalMatches[i];
|
||||
OptimizedMatch = &OptimizedMatches[j];
|
||||
|
||||
OptimizedMatch->MatchOffset = OriginalMatch->MatchOffset;
|
||||
OptimizedMatch->ChunkOffset = OriginalMatch->ChunkOffset;
|
||||
OptimizedMatch->MatchLength = OriginalMatch->MatchLength;
|
||||
|
||||
PrevMatchEnd = OptimizedMatches[j].MatchLength + OptimizedMatches[j].MatchOffset;
|
||||
TotalMatchLength += OptimizedMatches[j].MatchLength;
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
OptimizedMatchCount = j;
|
||||
xcrush->OptimizedMatchCount = OptimizedMatchCount;
|
||||
|
||||
return (int) TotalMatchLength;
|
||||
}
|
||||
|
||||
int xcrush_generate_output(XCRUSH_CONTEXT* xcrush, BYTE* OutputBuffer, UINT32 OutputSize, UINT32 HistoryOffset, UINT32* pDstSize)
|
||||
{
|
||||
BYTE* Literals;
|
||||
BYTE* OutputEnd;
|
||||
UINT32 MatchIndex;
|
||||
UINT32 MatchOffset;
|
||||
UINT16 MatchLength;
|
||||
UINT32 MatchCount;
|
||||
UINT32 CurrentOffset;
|
||||
UINT32 MatchOffsetDiff;
|
||||
UINT32 HistoryOffsetDiff;
|
||||
RDP61_MATCH_DETAILS* MatchDetails;
|
||||
|
||||
MatchCount = xcrush->OptimizedMatchCount;
|
||||
|
||||
OutputEnd = &OutputBuffer[OutputSize];
|
||||
|
||||
if (&OutputBuffer[2] >= &OutputBuffer[OutputSize])
|
||||
return -6001; /* error */
|
||||
|
||||
*((UINT16*) OutputBuffer) = MatchCount;
|
||||
|
||||
MatchDetails = (RDP61_MATCH_DETAILS*) &OutputBuffer[2];
|
||||
Literals = (BYTE*) &MatchDetails[MatchCount];
|
||||
|
||||
if (Literals > OutputEnd)
|
||||
return -6002; /* error */
|
||||
|
||||
for (MatchIndex = 0; MatchIndex < MatchCount; MatchIndex++)
|
||||
{
|
||||
MatchDetails[MatchIndex].MatchLength = (UINT16) (xcrush->OptimizedMatches[MatchIndex].MatchLength);
|
||||
MatchDetails[MatchIndex].MatchOutputOffset = (UINT16) (xcrush->OptimizedMatches[MatchIndex].MatchOffset - HistoryOffset);
|
||||
MatchDetails[MatchIndex].MatchHistoryOffset = xcrush->OptimizedMatches[MatchIndex].ChunkOffset;
|
||||
}
|
||||
|
||||
CurrentOffset = HistoryOffset;
|
||||
|
||||
for (MatchIndex = 0; MatchIndex < MatchCount; MatchIndex++)
|
||||
{
|
||||
MatchLength = (UINT16) (xcrush->OptimizedMatches[MatchIndex].MatchLength);
|
||||
MatchOffset = xcrush->OptimizedMatches[MatchIndex].MatchOffset;
|
||||
|
||||
if (MatchOffset <= CurrentOffset)
|
||||
{
|
||||
if (MatchOffset != CurrentOffset)
|
||||
return -6003; /* error */
|
||||
|
||||
CurrentOffset = MatchOffset + MatchLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
MatchOffsetDiff = MatchOffset - CurrentOffset;
|
||||
|
||||
if (Literals + MatchOffset - CurrentOffset >= OutputEnd)
|
||||
return -6004; /* error */
|
||||
|
||||
CopyMemory(Literals, &xcrush->HistoryBuffer[CurrentOffset], MatchOffsetDiff);
|
||||
|
||||
if (Literals >= OutputEnd)
|
||||
return -6005; /* error */
|
||||
|
||||
Literals += MatchOffsetDiff;
|
||||
CurrentOffset = MatchOffset + MatchLength;
|
||||
}
|
||||
}
|
||||
|
||||
HistoryOffsetDiff = xcrush->HistoryOffset - CurrentOffset;
|
||||
|
||||
if (Literals + HistoryOffsetDiff >= OutputEnd)
|
||||
return -6006; /* error */
|
||||
|
||||
CopyMemory(Literals, &xcrush->HistoryBuffer[CurrentOffset], HistoryOffsetDiff);
|
||||
*pDstSize = Literals + HistoryOffsetDiff - OutputBuffer;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xcrush_copy_bytes(BYTE* dst, BYTE* src, int num)
|
||||
{
|
||||
int index;
|
||||
|
@ -192,25 +833,67 @@ int xcrush_decompress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BY
|
|||
|
||||
int xcrush_compress_l1(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
|
||||
{
|
||||
int status = 0;
|
||||
UINT32 Flags = 0;
|
||||
UINT32 HistoryOffset = 0;
|
||||
BYTE* HistoryPtr = NULL;
|
||||
BYTE* HistoryBuffer = NULL;
|
||||
UINT32 SignatureIndex = 0;
|
||||
|
||||
if (xcrush->HistoryOffset + SrcSize + 8 > xcrush->HistoryBufferSize)
|
||||
{
|
||||
xcrush->HistoryOffset = 0;
|
||||
Flags |= L1_PACKET_AT_FRONT;
|
||||
}
|
||||
|
||||
HistoryOffset = xcrush->HistoryOffset;
|
||||
HistoryBuffer = xcrush->HistoryBuffer;
|
||||
HistoryPtr = &HistoryBuffer[HistoryOffset];
|
||||
|
||||
CopyMemory(HistoryPtr, pSrcData, SrcSize);
|
||||
MoveMemory(HistoryPtr, pSrcData, SrcSize);
|
||||
xcrush->HistoryOffset += SrcSize;
|
||||
|
||||
if (SrcSize <= 50)
|
||||
if (SrcSize > 50)
|
||||
{
|
||||
SignatureIndex = xcrush_compute_signatures(xcrush, pSrcData, SrcSize);
|
||||
|
||||
if (SignatureIndex)
|
||||
{
|
||||
status = xcrush_find_all_matches(xcrush,
|
||||
SignatureIndex, HistoryOffset, 0, SrcSize);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
xcrush->OriginalMatchCount = (UINT32) status;
|
||||
|
||||
xcrush->OptimizedMatchCount = 0;
|
||||
|
||||
if (xcrush->OriginalMatchCount)
|
||||
{
|
||||
status = xcrush_optimize_matches(xcrush);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (xcrush->OptimizedMatchCount)
|
||||
{
|
||||
status = xcrush_generate_output(xcrush, *ppDstData, SrcSize, HistoryOffset, pDstSize);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (status > 0)
|
||||
Flags |= L1_COMPRESSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(Flags & L1_COMPRESSED))
|
||||
{
|
||||
Flags |= L1_NO_COMPRESSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
*pDstSize = SrcSize;
|
||||
}
|
||||
|
||||
*pFlags = Flags;
|
||||
|
@ -232,18 +915,18 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
|||
UINT32 CompressionLevel = 3;
|
||||
|
||||
if (SrcSize > 16384)
|
||||
return -1;
|
||||
return -1001;
|
||||
|
||||
if ((SrcSize + 2) > *pDstSize)
|
||||
return -1;
|
||||
return -1002;
|
||||
|
||||
OriginalData = pDstData;
|
||||
OriginalDataSize = *pDstSize;
|
||||
OriginalData = *ppDstData;
|
||||
OriginalDataSize = SrcSize;
|
||||
|
||||
pDstData = xcrush->BlockBuffer;
|
||||
DstSize = sizeof(xcrush->BlockBuffer);
|
||||
CompressedDataSize = SrcSize;
|
||||
|
||||
status = xcrush_compress_l1(xcrush, pSrcData, SrcSize, &pDstData, &DstSize, &Level1ComprFlags);
|
||||
status = xcrush_compress_l1(xcrush, pSrcData, SrcSize, &pDstData, &CompressedDataSize, &Level1ComprFlags);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
@ -251,26 +934,24 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
|||
if (Level1ComprFlags & L1_COMPRESSED)
|
||||
{
|
||||
CompressedData = pDstData;
|
||||
CompressedDataSize = DstSize;
|
||||
|
||||
if (CompressedDataSize > SrcSize)
|
||||
return -1;
|
||||
return -1003;
|
||||
}
|
||||
else
|
||||
{
|
||||
CompressedData = pSrcData;
|
||||
CompressedDataSize = DstSize;
|
||||
|
||||
if (CompressedDataSize != SrcSize)
|
||||
return -1;
|
||||
return -1004;
|
||||
}
|
||||
|
||||
status = 1;
|
||||
status = 0;
|
||||
|
||||
pDstData = OriginalData + 2;
|
||||
pDstData = &OriginalData[2];
|
||||
DstSize = OriginalDataSize - 2;
|
||||
|
||||
if (DstSize > 50)
|
||||
if (CompressedDataSize > 50)
|
||||
{
|
||||
status = mppc_compress(xcrush->mppc, CompressedData, CompressedDataSize, &pDstData, &DstSize, &Level2ComprFlags);
|
||||
}
|
||||
|
@ -278,29 +959,29 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
|||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (!(Level2ComprFlags & PACKET_COMPRESSED) || (Level2ComprFlags & PACKET_FLUSHED))
|
||||
if (!status || (Level2ComprFlags & PACKET_FLUSHED))
|
||||
{
|
||||
if (CompressedDataSize > DstSize)
|
||||
return -1;
|
||||
{
|
||||
xcrush_context_reset(xcrush, TRUE);
|
||||
*ppDstData = pSrcData;
|
||||
*pDstSize = SrcSize;
|
||||
*pFlags = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
DstSize = CompressedDataSize;
|
||||
CopyMemory(pDstData, CompressedData, CompressedDataSize);
|
||||
CopyMemory(&OriginalData[2], CompressedData, CompressedDataSize);
|
||||
}
|
||||
|
||||
if (Level2ComprFlags & PACKET_COMPRESSED)
|
||||
{
|
||||
|
||||
Level2ComprFlags |= xcrush->CompressionFlags;
|
||||
xcrush->CompressionFlags = 0;
|
||||
}
|
||||
else
|
||||
else if (Level2ComprFlags & PACKET_FLUSHED)
|
||||
{
|
||||
if (Level2ComprFlags & PACKET_FLUSHED)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
xcrush->CompressionFlags = PACKET_FLUSHED;
|
||||
}
|
||||
|
||||
Level1ComprFlags |= L1_INNER_COMPRESSION;
|
||||
|
@ -308,8 +989,14 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
|||
OriginalData[0] = (BYTE) Level1ComprFlags;
|
||||
OriginalData[1] = (BYTE) Level2ComprFlags;
|
||||
|
||||
#if 0
|
||||
printf("XCrushCompress: Level1ComprFlags: %s Level2ComprFlags: %s\n",
|
||||
xcrush_get_level_1_compression_flags_string(Level1ComprFlags),
|
||||
xcrush_get_level_2_compression_flags_string(Level2ComprFlags));
|
||||
#endif
|
||||
|
||||
if (*pDstSize < (DstSize + 2))
|
||||
return -1;
|
||||
return -1006;
|
||||
|
||||
*pDstSize = DstSize + 2;
|
||||
*pFlags = PACKET_COMPRESSED | CompressionLevel;
|
||||
|
@ -317,9 +1004,27 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
|||
return 1;
|
||||
}
|
||||
|
||||
void xcrush_context_reset(XCRUSH_CONTEXT* xcrush)
|
||||
void xcrush_context_reset(XCRUSH_CONTEXT* xcrush, BOOL flush)
|
||||
{
|
||||
xcrush->SignatureIndex = 0;
|
||||
xcrush->SignatureCount = 1000;
|
||||
ZeroMemory(&(xcrush->Signatures), sizeof(XCRUSH_SIGNATURE) * xcrush->SignatureCount);
|
||||
|
||||
xcrush->CompressionFlags = 0;
|
||||
|
||||
xcrush->ChunkHead = xcrush->ChunkTail = 1;
|
||||
ZeroMemory(&(xcrush->Chunks), sizeof(xcrush->Chunks));
|
||||
ZeroMemory(&(xcrush->NextChunks), sizeof(xcrush->NextChunks));
|
||||
|
||||
ZeroMemory(&(xcrush->OriginalMatches), sizeof(xcrush->OriginalMatches));
|
||||
ZeroMemory(&(xcrush->OptimizedMatches), sizeof(xcrush->OptimizedMatches));
|
||||
|
||||
if (flush)
|
||||
xcrush->HistoryOffset = xcrush->HistoryBufferSize + 1;
|
||||
else
|
||||
xcrush->HistoryOffset = 0;
|
||||
|
||||
mppc_context_reset(xcrush->mppc, flush);
|
||||
}
|
||||
|
||||
XCRUSH_CONTEXT* xcrush_context_new(BOOL Compressor)
|
||||
|
@ -336,7 +1041,7 @@ XCRUSH_CONTEXT* xcrush_context_new(BOOL Compressor)
|
|||
xcrush->HistoryOffset = 0;
|
||||
xcrush->HistoryBufferSize = 2000000;
|
||||
|
||||
xcrush_context_reset(xcrush);
|
||||
xcrush_context_reset(xcrush, FALSE);
|
||||
}
|
||||
|
||||
return xcrush;
|
||||
|
|
|
@ -618,6 +618,20 @@ void freerdp_set_gateway_usage_method(rdpSettings* settings, UINT32 GatewayUsage
|
|||
}
|
||||
}
|
||||
|
||||
void freerdp_update_gateway_usage_method(rdpSettings* settings, UINT32 GatewayEnabled, UINT32 GatewayBypassLocal)
|
||||
{
|
||||
UINT32 GatewayUsageMethod = 0;
|
||||
|
||||
if (!GatewayEnabled && !GatewayBypassLocal)
|
||||
GatewayUsageMethod = TSC_PROXY_MODE_NONE_DIRECT;
|
||||
else if (GatewayEnabled && !GatewayBypassLocal)
|
||||
GatewayUsageMethod = TSC_PROXY_MODE_DIRECT;
|
||||
else if (GatewayEnabled && GatewayBypassLocal)
|
||||
GatewayUsageMethod = TSC_PROXY_MODE_DETECT;
|
||||
|
||||
freerdp_set_gateway_usage_method(settings, GatewayUsageMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Partially Generated Code
|
||||
*/
|
||||
|
|
|
@ -79,6 +79,7 @@ set(${MODULE_PREFIX}_SRCS
|
|||
client.h
|
||||
server.c
|
||||
server.h
|
||||
metrics.c
|
||||
capabilities.c
|
||||
capabilities.h
|
||||
certificate.c
|
||||
|
@ -147,7 +148,7 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE winpr
|
||||
MODULES winpr-registry winpr-utils winpr-interlocked winpr-dsparse winpr-sspi winpr-rpc winpr-wtsapi winpr-handle winpr-crt)
|
||||
MODULES winpr-registry winpr-utils winpr-interlocked winpr-dsparse winpr-sspi winpr-rpc winpr-wtsapi winpr-handle winpr-winsock winpr-crt)
|
||||
|
||||
if(MONOLITHIC_BUILD)
|
||||
set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
|
||||
|
|
|
@ -52,14 +52,19 @@ const char* bulk_get_compression_flags_string(UINT32 flags)
|
|||
UINT32 bulk_compression_level(rdpBulk* bulk)
|
||||
{
|
||||
rdpSettings* settings = bulk->context->settings;
|
||||
bulk->CompressionLevel = (settings->CompressionLevel >= 2) ? 2 : settings->CompressionLevel;
|
||||
|
||||
bulk->CompressionLevel = (settings->CompressionLevel >= PACKET_COMPR_TYPE_RDP61) ?
|
||||
PACKET_COMPR_TYPE_RDP61 : settings->CompressionLevel;
|
||||
|
||||
return bulk->CompressionLevel;
|
||||
}
|
||||
|
||||
UINT32 bulk_compression_max_size(rdpBulk* bulk)
|
||||
{
|
||||
bulk_compression_level(bulk);
|
||||
bulk->CompressionMaxSize = (bulk->CompressionLevel < 1) ? 8192 : 65536;
|
||||
|
||||
bulk->CompressionMaxSize = (bulk->CompressionLevel < PACKET_COMPR_TYPE_64K) ? 8192 : 65536;
|
||||
|
||||
return bulk->CompressionMaxSize;
|
||||
}
|
||||
|
||||
|
@ -112,8 +117,12 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD
|
|||
{
|
||||
UINT32 type;
|
||||
int status = -1;
|
||||
rdpMetrics* metrics;
|
||||
UINT32 CompressedBytes;
|
||||
UINT32 UncompressedBytes;
|
||||
double CompressionRatio;
|
||||
|
||||
metrics = bulk->context->metrics;
|
||||
|
||||
bulk_compression_max_size(bulk);
|
||||
type = flags & BULK_COMPRESSION_TYPE_MASK;
|
||||
|
@ -157,21 +166,15 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD
|
|||
CompressedBytes = SrcSize;
|
||||
UncompressedBytes = *pDstSize;
|
||||
|
||||
bulk->TotalUncompressedBytes += UncompressedBytes;
|
||||
bulk->TotalCompressedBytes += CompressedBytes;
|
||||
CompressionRatio = metrics_write_bytes(metrics, UncompressedBytes, CompressedBytes);
|
||||
|
||||
#ifdef WITH_BULK_DEBUG
|
||||
{
|
||||
double CompressionRatio;
|
||||
double TotalCompressionRatio;
|
||||
|
||||
CompressionRatio = ((double) CompressedBytes) / ((double) UncompressedBytes);
|
||||
TotalCompressionRatio = ((double) bulk->TotalCompressedBytes) / ((double) bulk->TotalUncompressedBytes);
|
||||
|
||||
printf("Decompress Type: %d Flags: %s (0x%04X) Compression Ratio: %f (%d / %d), Total: %f (%d / %d)\n",
|
||||
printf("Decompress Type: %d Flags: %s (0x%04X) Compression Ratio: %f (%d / %d), Total: %f (%u / %u)\n",
|
||||
type, bulk_get_compression_flags_string(flags), flags,
|
||||
CompressionRatio, CompressedBytes, UncompressedBytes,
|
||||
TotalCompressionRatio, bulk->TotalCompressedBytes, bulk->TotalUncompressedBytes);
|
||||
metrics->TotalCompressionRatio, (UINT32) metrics->TotalCompressedBytes,
|
||||
(UINT32) metrics->TotalUncompressedBytes);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -186,8 +189,12 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD
|
|||
int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
|
||||
{
|
||||
int status = -1;
|
||||
rdpMetrics* metrics;
|
||||
UINT32 CompressedBytes;
|
||||
UINT32 UncompressedBytes;
|
||||
double CompressionRatio;
|
||||
|
||||
metrics = bulk->context->metrics;
|
||||
|
||||
if ((SrcSize <= 50) || (SrcSize >= 16384))
|
||||
{
|
||||
|
@ -202,39 +209,39 @@ int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstDat
|
|||
bulk_compression_level(bulk);
|
||||
bulk_compression_max_size(bulk);
|
||||
|
||||
if (bulk->CompressionLevel < PACKET_COMPR_TYPE_RDP6)
|
||||
if ((bulk->CompressionLevel == PACKET_COMPR_TYPE_8K) ||
|
||||
(bulk->CompressionLevel == PACKET_COMPR_TYPE_64K))
|
||||
{
|
||||
mppc_set_compression_level(bulk->mppcSend, bulk->CompressionLevel);
|
||||
status = mppc_compress(bulk->mppcSend, pSrcData, SrcSize, ppDstData, pDstSize, pFlags);
|
||||
}
|
||||
else
|
||||
else if (bulk->CompressionLevel == PACKET_COMPR_TYPE_RDP6)
|
||||
{
|
||||
status = ncrush_compress(bulk->ncrushSend, pSrcData, SrcSize, ppDstData, pDstSize, pFlags);
|
||||
}
|
||||
|
||||
else if (bulk->CompressionLevel == PACKET_COMPR_TYPE_RDP61)
|
||||
{
|
||||
status = xcrush_compress(bulk->xcrushSend, pSrcData, SrcSize, ppDstData, pDstSize, pFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = -1;
|
||||
}
|
||||
|
||||
if (status >= 0)
|
||||
{
|
||||
CompressedBytes = *pDstSize;
|
||||
UncompressedBytes = SrcSize;
|
||||
|
||||
bulk->TotalUncompressedBytes += UncompressedBytes;
|
||||
bulk->TotalCompressedBytes += CompressedBytes;
|
||||
CompressionRatio = metrics_write_bytes(metrics, UncompressedBytes, CompressedBytes);
|
||||
|
||||
#ifdef WITH_BULK_DEBUG
|
||||
{
|
||||
UINT32 type;
|
||||
double CompressionRatio;
|
||||
double TotalCompressionRatio;
|
||||
|
||||
type = bulk->CompressionLevel;
|
||||
|
||||
CompressionRatio = ((double) CompressedBytes) / ((double) UncompressedBytes);
|
||||
TotalCompressionRatio = ((double) bulk->TotalCompressedBytes) / ((double) bulk->TotalUncompressedBytes);
|
||||
|
||||
printf("Compress Type: %d Flags: %s (0x%04X) Compression Ratio: %f (%d / %d), Total: %f (%d / %d)\n",
|
||||
type, bulk_get_compression_flags_string(*pFlags), *pFlags,
|
||||
printf("Compress Type: %d Flags: %s (0x%04X) Compression Ratio: %f (%d / %d), Total: %f (%u / %u)\n",
|
||||
bulk->CompressionLevel, bulk_get_compression_flags_string(*pFlags), *pFlags,
|
||||
CompressionRatio, CompressedBytes, UncompressedBytes,
|
||||
TotalCompressionRatio, bulk->TotalCompressedBytes, bulk->TotalUncompressedBytes);
|
||||
metrics->TotalCompressionRatio, (UINT32) metrics->TotalCompressedBytes,
|
||||
(UINT32) metrics->TotalUncompressedBytes);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -249,14 +256,14 @@ int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstDat
|
|||
|
||||
void bulk_reset(rdpBulk* bulk)
|
||||
{
|
||||
mppc_context_reset(bulk->mppcSend);
|
||||
mppc_context_reset(bulk->mppcRecv);
|
||||
mppc_context_reset(bulk->mppcSend, FALSE);
|
||||
mppc_context_reset(bulk->mppcRecv, FALSE);
|
||||
|
||||
ncrush_context_reset(bulk->ncrushRecv);
|
||||
ncrush_context_reset(bulk->ncrushSend);
|
||||
ncrush_context_reset(bulk->ncrushRecv, FALSE);
|
||||
ncrush_context_reset(bulk->ncrushSend, FALSE);
|
||||
|
||||
xcrush_context_reset(bulk->xcrushRecv);
|
||||
xcrush_context_reset(bulk->xcrushSend);
|
||||
xcrush_context_reset(bulk->xcrushRecv, FALSE);
|
||||
xcrush_context_reset(bulk->xcrushSend, FALSE);
|
||||
}
|
||||
|
||||
rdpBulk* bulk_new(rdpContext* context)
|
||||
|
@ -279,9 +286,6 @@ rdpBulk* bulk_new(rdpContext* context)
|
|||
bulk->xcrushSend = xcrush_context_new(TRUE);
|
||||
|
||||
bulk->CompressionLevel = context->settings->CompressionLevel;
|
||||
|
||||
bulk->TotalCompressedBytes = 0;
|
||||
bulk->TotalUncompressedBytes = 0;
|
||||
}
|
||||
|
||||
return bulk;
|
||||
|
|
|
@ -40,8 +40,6 @@ struct rdp_bulk
|
|||
XCRUSH_CONTEXT* xcrushRecv;
|
||||
XCRUSH_CONTEXT* xcrushSend;
|
||||
BYTE OutputBuffer[65536];
|
||||
UINT64 TotalCompressedBytes;
|
||||
UINT64 TotalUncompressedBytes;
|
||||
};
|
||||
|
||||
#define BULK_COMPRESSION_FLAGS_MASK 0xE0
|
||||
|
|
|
@ -299,7 +299,7 @@ static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, UINT32 s
|
|||
break;
|
||||
|
||||
case FASTPATH_UPDATETYPE_COLOR:
|
||||
if (!update_read_pointer_color(s, &pointer->pointer_color))
|
||||
if (!update_read_pointer_color(s, &pointer->pointer_color, 24))
|
||||
return -1;
|
||||
IFCALL(pointer->PointerColor, context, &pointer->pointer_color);
|
||||
break;
|
||||
|
|
|
@ -212,9 +212,14 @@ BOOL freerdp_check_fds(freerdp* instance)
|
|||
int status;
|
||||
rdpRdp* rdp;
|
||||
|
||||
assert(instance);
|
||||
assert(instance->context);
|
||||
assert(instance->context->rdp);
|
||||
if (!instance)
|
||||
return FALSE;
|
||||
|
||||
if (!instance->context)
|
||||
return FALSE;
|
||||
|
||||
if (!instance->context->rdp)
|
||||
return FALSE;
|
||||
|
||||
rdp = instance->context->rdp;
|
||||
|
||||
|
@ -405,6 +410,8 @@ int freerdp_context_new(freerdp* instance)
|
|||
context->pubSub = PubSub_New(TRUE);
|
||||
PubSub_AddEventTypes(context->pubSub, FreeRDP_Events, sizeof(FreeRDP_Events) / sizeof(wEventType));
|
||||
|
||||
context->metrics = metrics_new(context);
|
||||
|
||||
rdp = rdp_new(context);
|
||||
instance->input = rdp->input;
|
||||
instance->update = rdp->update;
|
||||
|
@ -458,6 +465,8 @@ void freerdp_context_free(freerdp* instance)
|
|||
|
||||
PubSub_Free(instance->context->pubSub);
|
||||
|
||||
metrics_free(instance->context->metrics);
|
||||
|
||||
free(instance->context);
|
||||
instance->context = NULL;
|
||||
}
|
||||
|
|
|
@ -319,8 +319,7 @@ int rpc_out_read(rdpRpc* rpc, BYTE* data, int length)
|
|||
int status;
|
||||
|
||||
status = BIO_read(rpc->TlsOut->bio, data, length);
|
||||
/* fprintf(stderr, "%s: length=%d => status=%d shouldRetry=%d\n", __FUNCTION__, length,
|
||||
* status, BIO_should_retry(rpc->TlsOut->bio)); */
|
||||
|
||||
if (status > 0) {
|
||||
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||
VALGRIND_MAKE_MEM_DEFINED(data, status);
|
||||
|
|
|
@ -1601,14 +1601,17 @@ rdpTsg* tsg_new(rdpTransport* transport)
|
|||
rdpTsg* tsg;
|
||||
|
||||
tsg = (rdpTsg*) calloc(1, sizeof(rdpTsg));
|
||||
|
||||
if (!tsg)
|
||||
return NULL;
|
||||
|
||||
tsg->transport = transport;
|
||||
tsg->settings = transport->settings;
|
||||
tsg->rpc = rpc_new(tsg->transport);
|
||||
|
||||
if (!tsg->rpc)
|
||||
goto out_free;
|
||||
|
||||
tsg->PendingPdu = FALSE;
|
||||
return tsg;
|
||||
|
||||
|
@ -1619,7 +1622,7 @@ out_free:
|
|||
|
||||
void tsg_free(rdpTsg* tsg)
|
||||
{
|
||||
if (tsg != NULL)
|
||||
if (tsg)
|
||||
{
|
||||
free(tsg->MachineName);
|
||||
rpc_free(tsg->rpc);
|
||||
|
|
|
@ -31,6 +31,7 @@ typedef struct rdp_tsg rdpTsg;
|
|||
#include <winpr/rpc.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/error.h>
|
||||
|
||||
#include <time.h>
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Protocol Metrics
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "rdp.h"
|
||||
|
||||
double metrics_write_bytes(rdpMetrics* metrics, UINT32 UncompressedBytes, UINT32 CompressedBytes)
|
||||
{
|
||||
double CompressionRatio;
|
||||
|
||||
metrics->TotalUncompressedBytes += UncompressedBytes;
|
||||
metrics->TotalCompressedBytes += CompressedBytes;
|
||||
|
||||
CompressionRatio = ((double) CompressedBytes) / ((double) UncompressedBytes);
|
||||
metrics->TotalCompressionRatio = ((double) metrics->TotalCompressedBytes) / ((double) metrics->TotalUncompressedBytes);
|
||||
|
||||
return CompressionRatio;
|
||||
}
|
||||
|
||||
rdpMetrics* metrics_new(rdpContext* context)
|
||||
{
|
||||
rdpMetrics* metrics;
|
||||
|
||||
metrics = (rdpMetrics*) calloc(1, sizeof(rdpMetrics));
|
||||
|
||||
if (metrics)
|
||||
{
|
||||
metrics->context = context;
|
||||
}
|
||||
|
||||
return metrics;
|
||||
}
|
||||
|
||||
void metrics_free(rdpMetrics* metrics)
|
||||
{
|
||||
if (!metrics)
|
||||
return;
|
||||
|
||||
free(metrics);
|
||||
}
|
|
@ -220,18 +220,18 @@ BOOL nego_tcp_connect(rdpNego* nego)
|
|||
{
|
||||
/* Attempt a direct connection first, and then fallback to using the gateway */
|
||||
transport_set_gateway_enabled(nego->transport, FALSE);
|
||||
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
|
||||
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port, 1);
|
||||
}
|
||||
|
||||
if (!nego->tcp_connected)
|
||||
{
|
||||
transport_set_gateway_enabled(nego->transport, TRUE);
|
||||
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
|
||||
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port, 15);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
|
||||
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port, 15);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,11 +85,7 @@
|
|||
#define WITH_DEBUG_CREDSSP
|
||||
#endif
|
||||
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
#define NLA_PKG_NAME NTLMSP_NAME
|
||||
#else
|
||||
#define NLA_PKG_NAME NTLMSP_NAME
|
||||
#endif
|
||||
#define NLA_PKG_NAME NEGOSSP_NAME
|
||||
|
||||
#define TERMSRV_SPN_PREFIX "TERMSRV/"
|
||||
|
||||
|
@ -267,24 +263,7 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
|||
if (credssp_ntlm_client_init(credssp) == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
{
|
||||
HMODULE hSSPI;
|
||||
INIT_SECURITY_INTERFACE InitSecurityInterface;
|
||||
PSecurityFunctionTable pSecurityInterface = NULL;
|
||||
|
||||
hSSPI = LoadLibrary(_T("secur32.dll"));
|
||||
|
||||
#ifdef UNICODE
|
||||
InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceW");
|
||||
#else
|
||||
InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
|
||||
#endif
|
||||
credssp->table = (*InitSecurityInterface)();
|
||||
}
|
||||
#else
|
||||
credssp->table = InitSecurityInterface();
|
||||
#endif
|
||||
credssp->table = InitSecurityInterfaceEx(0);
|
||||
|
||||
status = credssp->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &pPackageInfo);
|
||||
|
||||
|
@ -337,17 +316,25 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
|||
SECURITY_NATIVE_DREP, (have_input_buffer) ? &input_buffer_desc : NULL,
|
||||
0, &credssp->context, &output_buffer_desc, &pfContextAttr, &expiration);
|
||||
|
||||
if (have_input_buffer && (input_buffer.pvBuffer != NULL))
|
||||
if (have_input_buffer && (input_buffer.pvBuffer))
|
||||
{
|
||||
free(input_buffer.pvBuffer);
|
||||
input_buffer.pvBuffer = NULL;
|
||||
}
|
||||
|
||||
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED) || (status == SEC_E_OK))
|
||||
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
|
||||
{
|
||||
if (credssp->table->CompleteAuthToken != NULL)
|
||||
if (credssp->table->CompleteAuthToken)
|
||||
credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
status = SEC_E_OK;
|
||||
else if (status == SEC_I_COMPLETE_AND_CONTINUE)
|
||||
status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
if (status == SEC_E_OK)
|
||||
{
|
||||
have_pub_key_auth = TRUE;
|
||||
|
||||
if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
|
||||
|
@ -357,11 +344,6 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
|||
}
|
||||
|
||||
credssp_encrypt_public_key_echo(credssp);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
status = SEC_E_OK;
|
||||
else if (status == SEC_I_COMPLETE_AND_CONTINUE)
|
||||
status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
/* send authentication token to server */
|
||||
|
@ -469,11 +451,6 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
|||
if (credssp_ntlm_server_init(credssp) == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
if (!credssp->SspiModule)
|
||||
credssp->SspiModule = _tcsdup(_T("secur32.dll"));
|
||||
#endif
|
||||
|
||||
if (credssp->SspiModule)
|
||||
{
|
||||
HMODULE hSSPI;
|
||||
|
@ -493,14 +470,12 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
|||
pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
|
||||
#endif
|
||||
|
||||
credssp->table = (*pInitSecurityInterface)();
|
||||
credssp->table = pInitSecurityInterface();
|
||||
}
|
||||
#ifndef WITH_NATIVE_SSPI
|
||||
else
|
||||
{
|
||||
credssp->table = InitSecurityInterface();
|
||||
credssp->table = InitSecurityInterfaceEx(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
status = credssp->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &pPackageInfo);
|
||||
|
||||
|
@ -597,7 +572,7 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
|||
|
||||
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
|
||||
{
|
||||
if (credssp->table->CompleteAuthToken != NULL)
|
||||
if (credssp->table->CompleteAuthToken)
|
||||
credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
|
@ -1385,7 +1360,7 @@ rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings*
|
|||
{
|
||||
rdpCredssp* credssp;
|
||||
|
||||
credssp = (rdpCredssp*) malloc(sizeof(rdpCredssp));
|
||||
credssp = (rdpCredssp*) calloc(1, sizeof(rdpCredssp));
|
||||
|
||||
if (credssp)
|
||||
{
|
||||
|
@ -1394,8 +1369,6 @@ rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings*
|
|||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
|
||||
ZeroMemory(credssp, sizeof(rdpCredssp));
|
||||
|
||||
credssp->instance = instance;
|
||||
credssp->settings = settings;
|
||||
credssp->server = settings->ServerMode;
|
||||
|
|
|
@ -1840,6 +1840,11 @@ BOOL update_read_cache_bitmap_order(wStream* s, CACHE_BITMAP_ORDER* cache_bitmap
|
|||
Stream_Read_UINT8(s, cache_bitmap->bitmapWidth); /* bitmapWidth (1 byte) */
|
||||
Stream_Read_UINT8(s, cache_bitmap->bitmapHeight); /* bitmapHeight (1 byte) */
|
||||
Stream_Read_UINT8(s, cache_bitmap->bitmapBpp); /* bitmapBpp (1 byte) */
|
||||
if ((cache_bitmap->bitmapBpp < 1) || (cache_bitmap->bitmapBpp > 32))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid bitmap bpp %d\n", __FUNCTION__, cache_bitmap->bitmapBpp);
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Read_UINT16(s, cache_bitmap->bitmapLength); /* bitmapLength (2 bytes) */
|
||||
Stream_Read_UINT16(s, cache_bitmap->cacheIndex); /* cacheIndex (2 bytes) */
|
||||
|
||||
|
@ -2078,6 +2083,11 @@ BOOL update_read_cache_bitmap_v3_order(wStream* s, CACHE_BITMAP_V3_ORDER* cache_
|
|||
bitmapData = &cache_bitmap_v3->bitmapData;
|
||||
|
||||
Stream_Read_UINT8(s, bitmapData->bpp);
|
||||
if ((bitmapData->bpp < 1) || (bitmapData->bpp > 32))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, bitmapData->bpp);
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Seek_UINT8(s); /* reserved1 (1 byte) */
|
||||
Stream_Seek_UINT8(s); /* reserved2 (1 byte) */
|
||||
Stream_Read_UINT8(s, bitmapData->codecID); /* codecID (1 byte) */
|
||||
|
@ -2682,6 +2692,11 @@ BOOL update_read_create_nine_grid_bitmap_order(wStream* s, CREATE_NINE_GRID_BITM
|
|||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, create_nine_grid_bitmap->bitmapBpp); /* bitmapBpp (1 byte) */
|
||||
if ((create_nine_grid_bitmap->bitmapBpp < 1) || (create_nine_grid_bitmap->bitmapBpp > 32))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, create_nine_grid_bitmap->bitmapBpp);
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Read_UINT16(s, create_nine_grid_bitmap->bitmapId); /* bitmapId (2 bytes) */
|
||||
|
||||
nineGridInfo = &(create_nine_grid_bitmap->nineGridInfo);
|
||||
|
@ -2717,6 +2732,12 @@ BOOL update_read_stream_bitmap_first_order(wStream* s, STREAM_BITMAP_FIRST_ORDER
|
|||
|
||||
Stream_Read_UINT8(s, stream_bitmap_first->bitmapFlags); /* bitmapFlags (1 byte) */
|
||||
Stream_Read_UINT8(s, stream_bitmap_first->bitmapBpp); /* bitmapBpp (1 byte) */
|
||||
if ((stream_bitmap_first->bitmapBpp < 1) || (stream_bitmap_first->bitmapBpp > 32))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, stream_bitmap_first->bitmapBpp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT16(s, stream_bitmap_first->bitmapType); /* bitmapType (2 bytes) */
|
||||
Stream_Read_UINT16(s, stream_bitmap_first->bitmapWidth); /* bitmapWidth (2 bytes) */
|
||||
Stream_Read_UINT16(s, stream_bitmap_first->bitmapHeight); /* bitmapHeigth (2 bytes) */
|
||||
|
|
|
@ -431,11 +431,12 @@ void freerdp_peer_context_new(freerdp_peer* client)
|
|||
{
|
||||
rdpRdp* rdp;
|
||||
|
||||
client->context = (rdpContext*) malloc(client->ContextSize);
|
||||
ZeroMemory(client->context, client->ContextSize);
|
||||
client->context = (rdpContext *)calloc(1, client->ContextSize);
|
||||
|
||||
client->context->ServerMode = TRUE;
|
||||
|
||||
client->context->metrics = metrics_new(client->context);
|
||||
|
||||
rdp = rdp_new(client->context);
|
||||
|
||||
client->input = rdp->input;
|
||||
|
@ -468,14 +469,15 @@ void freerdp_peer_context_new(freerdp_peer* client)
|
|||
void freerdp_peer_context_free(freerdp_peer* client)
|
||||
{
|
||||
IFCALL(client->ContextFree, client, client->context);
|
||||
|
||||
metrics_free(client->context->metrics);
|
||||
}
|
||||
|
||||
freerdp_peer* freerdp_peer_new(int sockfd)
|
||||
{
|
||||
freerdp_peer* client;
|
||||
|
||||
client = (freerdp_peer*) malloc(sizeof(freerdp_peer));
|
||||
ZeroMemory(client, sizeof(freerdp_peer));
|
||||
client = (freerdp_peer*) calloc(1, sizeof(freerdp_peer));
|
||||
|
||||
freerdp_tcp_set_no_delay(sockfd, TRUE);
|
||||
|
||||
|
|
|
@ -427,9 +427,11 @@ BOOL WTSVirtualChannelManagerCheckFileDescriptor(HANDLE hServer)
|
|||
|
||||
if (channel)
|
||||
{
|
||||
ULONG written;
|
||||
|
||||
vcm->drdynvc_channel = channel;
|
||||
dynvc_caps = 0x00010050; /* DYNVC_CAPS_VERSION1 (4 bytes) */
|
||||
WTSVirtualChannelWrite(channel, (PCHAR) &dynvc_caps, sizeof(dynvc_caps), NULL);
|
||||
WTSVirtualChannelWrite(channel, (PCHAR) &dynvc_caps, sizeof(dynvc_caps), &written);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -916,6 +918,7 @@ HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualNam
|
|||
BOOL joined = FALSE;
|
||||
freerdp_peer* client;
|
||||
rdpPeerChannel* channel;
|
||||
ULONG written;
|
||||
WTSVirtualChannelManager* vcm;
|
||||
|
||||
if (SessionId == WTS_CURRENT_SESSION)
|
||||
|
@ -968,7 +971,7 @@ HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualNam
|
|||
|
||||
s = Stream_New(NULL, 64);
|
||||
wts_write_drdynvc_create_request(s, channel->channelId, pVirtualName);
|
||||
WTSVirtualChannelWrite(vcm->drdynvc_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(vcm->drdynvc_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return channel;
|
||||
|
@ -997,9 +1000,11 @@ BOOL WINAPI FreeRDP_WTSVirtualChannelClose(HANDLE hChannelHandle)
|
|||
|
||||
if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED)
|
||||
{
|
||||
ULONG written;
|
||||
|
||||
s = Stream_New(NULL, 8);
|
||||
wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channelId);
|
||||
WTSVirtualChannelWrite(vcm->drdynvc_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(vcm->drdynvc_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,7 +236,6 @@ rdpSettings* freerdp_settings_new(DWORD flags)
|
|||
settings->SaltedChecksum = TRUE;
|
||||
settings->ServerPort = 3389;
|
||||
settings->GatewayPort = 443;
|
||||
settings->GatewayBypassLocal = TRUE;
|
||||
settings->DesktopResize = TRUE;
|
||||
settings->ToggleFullscreen = TRUE;
|
||||
settings->DesktopPosX = 0;
|
||||
|
@ -257,9 +256,9 @@ rdpSettings* freerdp_settings_new(DWORD flags)
|
|||
settings->CompressionEnabled = TRUE;
|
||||
|
||||
if (settings->ServerMode)
|
||||
settings->CompressionLevel = PACKET_COMPR_TYPE_64K;
|
||||
settings->CompressionLevel = PACKET_COMPR_TYPE_RDP61;
|
||||
else
|
||||
settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
|
||||
settings->CompressionLevel = PACKET_COMPR_TYPE_RDP61;
|
||||
|
||||
settings->Authentication = TRUE;
|
||||
settings->AuthenticationOnly = FALSE;
|
||||
|
|
|
@ -38,6 +38,12 @@ static int update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT3
|
|||
Stream_Read_UINT16(s, cmd->destRight);
|
||||
Stream_Read_UINT16(s, cmd->destBottom);
|
||||
Stream_Read_UINT8(s, cmd->bpp);
|
||||
if ((cmd->bpp < 1) || (cmd->bpp > 32))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, cmd->bpp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Seek(s, 2); /* reserved1, reserved2 */
|
||||
Stream_Read_UINT8(s, cmd->codecID);
|
||||
Stream_Read_UINT16(s, cmd->width);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <fcntl.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/winsock.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netdb.h>
|
||||
|
@ -55,9 +56,6 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#define close(_fd) closesocket(_fd)
|
||||
#endif
|
||||
|
||||
#include <freerdp/utils/tcp.h>
|
||||
|
@ -66,6 +64,185 @@
|
|||
|
||||
#include "tcp.h"
|
||||
|
||||
/* Simple Socket BIO */
|
||||
|
||||
static int transport_bio_simple_new(BIO* bio);
|
||||
static int transport_bio_simple_free(BIO* bio);
|
||||
|
||||
long transport_bio_simple_callback(BIO* bio, int mode, const char* argp, int argi, long argl, long ret)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int transport_bio_simple_write(BIO* bio, const char* buf, int size)
|
||||
{
|
||||
int error;
|
||||
int status = 0;
|
||||
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
|
||||
|
||||
status = _send((SOCKET) bio->num, buf, size, 0);
|
||||
|
||||
if (status <= 0)
|
||||
{
|
||||
error = WSAGetLastError();
|
||||
|
||||
if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) ||
|
||||
(error == WSAEINPROGRESS) || (error == WSAEALREADY))
|
||||
{
|
||||
BIO_set_flags(bio, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY));
|
||||
}
|
||||
else
|
||||
{
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int transport_bio_simple_read(BIO* bio, char* buf, int size)
|
||||
{
|
||||
int error;
|
||||
int status = 0;
|
||||
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
BIO_clear_flags(bio, BIO_FLAGS_READ);
|
||||
|
||||
status = _recv((SOCKET) bio->num, buf, size, 0);
|
||||
|
||||
if (status <= 0)
|
||||
{
|
||||
error = WSAGetLastError();
|
||||
|
||||
if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) ||
|
||||
(error == WSAEINPROGRESS) || (error == WSAEALREADY))
|
||||
{
|
||||
BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY));
|
||||
}
|
||||
else
|
||||
{
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int transport_bio_simple_puts(BIO* bio, const char* str)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int transport_bio_simple_gets(BIO* bio, char* str, int size)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static long transport_bio_simple_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
|
||||
{
|
||||
int status = -1;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case BIO_C_SET_FD:
|
||||
if (arg2)
|
||||
{
|
||||
transport_bio_simple_free(bio);
|
||||
bio->flags = BIO_FLAGS_SHOULD_RETRY;
|
||||
bio->num = *((int*) arg2);
|
||||
bio->shutdown = (int) arg1;
|
||||
bio->init = 1;
|
||||
status = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIO_C_GET_FD:
|
||||
if (bio->init)
|
||||
{
|
||||
if (arg2)
|
||||
*((int*) arg2) = bio->num;
|
||||
status = bio->num;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIO_CTRL_GET_CLOSE:
|
||||
status = bio->shutdown;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_SET_CLOSE:
|
||||
bio->shutdown = (int) arg1;
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_DUP:
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_FLUSH:
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int transport_bio_simple_new(BIO* bio)
|
||||
{
|
||||
bio->init = 0;
|
||||
bio->num = 0;
|
||||
bio->ptr = NULL;
|
||||
bio->flags = BIO_FLAGS_SHOULD_RETRY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int transport_bio_simple_free(BIO* bio)
|
||||
{
|
||||
if (!bio)
|
||||
return 0;
|
||||
|
||||
if (bio->shutdown)
|
||||
{
|
||||
if (bio->init)
|
||||
closesocket((SOCKET) bio->num);
|
||||
|
||||
bio->init = 0;
|
||||
bio->flags = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BIO_METHOD transport_bio_simple_socket_methods =
|
||||
{
|
||||
BIO_TYPE_SIMPLE,
|
||||
"SimpleSocket",
|
||||
transport_bio_simple_write,
|
||||
transport_bio_simple_read,
|
||||
transport_bio_simple_puts,
|
||||
transport_bio_simple_gets,
|
||||
transport_bio_simple_ctrl,
|
||||
transport_bio_simple_new,
|
||||
transport_bio_simple_free,
|
||||
NULL,
|
||||
};
|
||||
|
||||
BIO_METHOD* BIO_s_simple_socket(void)
|
||||
{
|
||||
return &transport_bio_simple_socket_methods;
|
||||
}
|
||||
|
||||
/* Buffered Socket BIO */
|
||||
|
||||
long transport_bio_buffered_callback(BIO* bio, int mode, const char* argp, int argi, long argl, long ret)
|
||||
{
|
||||
return 1;
|
||||
|
@ -74,18 +251,18 @@ long transport_bio_buffered_callback(BIO* bio, int mode, const char* argp, int a
|
|||
static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
|
||||
{
|
||||
int status, ret;
|
||||
rdpTcp *tcp = (rdpTcp *)bio->ptr;
|
||||
rdpTcp* tcp = (rdpTcp*) bio->ptr;
|
||||
int nchunks, committedBytes, i;
|
||||
DataChunk chunks[2];
|
||||
|
||||
ret = num;
|
||||
BIO_clear_retry_flags(bio);
|
||||
tcp->writeBlocked = FALSE;
|
||||
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
|
||||
|
||||
/* we directly append extra bytes in the xmit buffer, this could be prevented
|
||||
* but for now it makes the code more simple.
|
||||
*/
|
||||
if (buf && num && !ringbuffer_write(&tcp->xmitBuffer, (const BYTE *)buf, num))
|
||||
if (buf && num && !ringbuffer_write(&tcp->xmitBuffer, (const BYTE*) buf, num))
|
||||
{
|
||||
fprintf(stderr, "%s: an error occured when writing(toWrite=%d)\n", __FUNCTION__, num);
|
||||
return -1;
|
||||
|
@ -93,26 +270,28 @@ static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
|
|||
|
||||
committedBytes = 0;
|
||||
nchunks = ringbuffer_peek(&tcp->xmitBuffer, chunks, ringbuffer_used(&tcp->xmitBuffer));
|
||||
|
||||
for (i = 0; i < nchunks; i++)
|
||||
{
|
||||
while (chunks[i].size)
|
||||
{
|
||||
status = BIO_write(bio->next_bio, chunks[i].data, chunks[i].size);
|
||||
/*fprintf(stderr, "%s: i=%d/%d size=%d/%d status=%d retry=%d\n", __FUNCTION__, i, nchunks,
|
||||
chunks[i].size, ringbuffer_used(&tcp->xmitBuffer), status,
|
||||
BIO_should_retry(bio->next_bio)
|
||||
);*/
|
||||
|
||||
if (status <= 0)
|
||||
{
|
||||
if (BIO_should_retry(bio->next_bio))
|
||||
if (!BIO_should_retry(bio->next_bio))
|
||||
{
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
ret = -1; /* fatal error */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (BIO_should_write(bio->next_bio))
|
||||
{
|
||||
BIO_set_flags(bio, BIO_FLAGS_WRITE);
|
||||
tcp->writeBlocked = TRUE;
|
||||
goto out; /* EWOULDBLOCK */
|
||||
}
|
||||
|
||||
/* any other is an error, but we still have to commit written bytes */
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
committedBytes += status;
|
||||
|
@ -129,20 +308,33 @@ out:
|
|||
static int transport_bio_buffered_read(BIO* bio, char* buf, int size)
|
||||
{
|
||||
int status;
|
||||
rdpTcp *tcp = (rdpTcp *)bio->ptr;
|
||||
rdpTcp* tcp = (rdpTcp*) bio->ptr;
|
||||
|
||||
tcp->readBlocked = FALSE;
|
||||
BIO_clear_retry_flags(bio);
|
||||
BIO_clear_flags(bio, BIO_FLAGS_READ);
|
||||
|
||||
status = BIO_read(bio->next_bio, buf, size);
|
||||
/*fprintf(stderr, "%s: size=%d status=%d shouldRetry=%d\n", __FUNCTION__, size, status, BIO_should_retry(bio->next_bio)); */
|
||||
|
||||
if (status <= 0 && BIO_should_retry(bio->next_bio))
|
||||
if (status <= 0)
|
||||
{
|
||||
BIO_set_retry_read(bio);
|
||||
tcp->readBlocked = TRUE;
|
||||
if (!BIO_should_retry(bio->next_bio))
|
||||
{
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
status = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
|
||||
if (BIO_should_read(bio->next_bio))
|
||||
{
|
||||
BIO_set_flags(bio, BIO_FLAGS_READ);
|
||||
tcp->readBlocked = TRUE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -158,19 +350,21 @@ static int transport_bio_buffered_gets(BIO* bio, char* str, int size)
|
|||
|
||||
static long transport_bio_buffered_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
|
||||
{
|
||||
rdpTcp *tcp = (rdpTcp *)bio->ptr;
|
||||
rdpTcp* tcp = (rdpTcp*) bio->ptr;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case BIO_CTRL_FLUSH:
|
||||
return 1;
|
||||
case BIO_CTRL_WPENDING:
|
||||
return ringbuffer_used(&tcp->xmitBuffer);
|
||||
case BIO_CTRL_PENDING:
|
||||
return 0;
|
||||
default:
|
||||
/*fprintf(stderr, "%s: passing to next BIO, bio=%p cmd=%d arg1=%d arg2=%p\n", __FUNCTION__, bio, cmd, arg1, arg2); */
|
||||
return BIO_ctrl(bio->next_bio, cmd, arg1, arg2);
|
||||
case BIO_CTRL_FLUSH:
|
||||
return 1;
|
||||
|
||||
case BIO_CTRL_WPENDING:
|
||||
return ringbuffer_used(&tcp->xmitBuffer);
|
||||
|
||||
case BIO_CTRL_PENDING:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return BIO_ctrl(bio->next_bio, cmd, arg1, arg2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -181,8 +375,7 @@ static int transport_bio_buffered_new(BIO* bio)
|
|||
bio->init = 1;
|
||||
bio->num = 0;
|
||||
bio->ptr = NULL;
|
||||
bio->flags = 0;
|
||||
|
||||
bio->flags = BIO_FLAGS_SHOULD_RETRY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -191,7 +384,6 @@ static int transport_bio_buffered_free(BIO* bio)
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static BIO_METHOD transport_bio_buffered_socket_methods =
|
||||
{
|
||||
BIO_TYPE_BUFFERED,
|
||||
|
@ -213,18 +405,17 @@ BIO_METHOD* BIO_s_buffered_socket(void)
|
|||
|
||||
BOOL transport_bio_buffered_drain(BIO *bio)
|
||||
{
|
||||
rdpTcp *tcp = (rdpTcp *)bio->ptr;
|
||||
int status;
|
||||
rdpTcp* tcp = (rdpTcp*) bio->ptr;
|
||||
|
||||
if (!ringbuffer_used(&tcp->xmitBuffer))
|
||||
return 1;
|
||||
|
||||
status = transport_bio_buffered_write(bio, NULL, 0);
|
||||
|
||||
return status >= 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void tcp_get_ip_address(rdpTcp* tcp)
|
||||
{
|
||||
BYTE* ip;
|
||||
|
@ -284,8 +475,9 @@ void tcp_get_mac_address(rdpTcp* tcp)
|
|||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); */
|
||||
}
|
||||
|
||||
BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port)
|
||||
BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout)
|
||||
{
|
||||
int status;
|
||||
UINT32 option_value;
|
||||
socklen_t option_len;
|
||||
|
||||
|
@ -295,26 +487,65 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port)
|
|||
if (hostname[0] == '/')
|
||||
{
|
||||
tcp->sockfd = freerdp_uds_connect(hostname);
|
||||
|
||||
if (tcp->sockfd < 0)
|
||||
return FALSE;
|
||||
|
||||
tcp->socketBio = BIO_new_fd(tcp->sockfd, 1);
|
||||
|
||||
if (!tcp->socketBio)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fd_set cfds;
|
||||
struct timeval tv;
|
||||
|
||||
tcp->socketBio = BIO_new(BIO_s_connect());
|
||||
|
||||
if (!tcp->socketBio)
|
||||
return FALSE;
|
||||
|
||||
if (BIO_set_conn_hostname(tcp->socketBio, hostname) < 0 || BIO_set_conn_int_port(tcp->socketBio, &port) < 0)
|
||||
if (BIO_set_conn_hostname(tcp->socketBio, hostname) < 0 || BIO_set_conn_int_port(tcp->socketBio, &port) < 0)
|
||||
return FALSE;
|
||||
|
||||
if (BIO_do_connect(tcp->socketBio) <= 0)
|
||||
BIO_set_nbio(tcp->socketBio, 1);
|
||||
|
||||
status = BIO_do_connect(tcp->socketBio);
|
||||
|
||||
if ((status <= 0) && !BIO_should_retry(tcp->socketBio))
|
||||
return FALSE;
|
||||
|
||||
tcp->sockfd = BIO_get_fd(tcp->socketBio, NULL);
|
||||
|
||||
if (tcp->sockfd < 0)
|
||||
return FALSE;
|
||||
|
||||
if (status <= 0)
|
||||
{
|
||||
FD_ZERO(&cfds);
|
||||
FD_SET(tcp->sockfd, &cfds);
|
||||
|
||||
tv.tv_sec = timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
status = select(tcp->sockfd + 1, NULL, &cfds, NULL, &tv);
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
return FALSE; /* timeout */
|
||||
}
|
||||
}
|
||||
|
||||
BIO_set_close(tcp->socketBio, BIO_NOCLOSE);
|
||||
BIO_free(tcp->socketBio);
|
||||
|
||||
tcp->socketBio = BIO_new(BIO_s_simple_socket());
|
||||
|
||||
if (!tcp->socketBio)
|
||||
return -1;
|
||||
|
||||
BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE);
|
||||
}
|
||||
|
||||
SetEventFileDescriptor(tcp->event, tcp->sockfd);
|
||||
|
@ -324,6 +555,7 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port)
|
|||
|
||||
option_value = 1;
|
||||
option_len = sizeof(option_value);
|
||||
|
||||
if (setsockopt(tcp->sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &option_value, option_len) < 0)
|
||||
fprintf(stderr, "%s: unable to set TCP_NODELAY\n", __FUNCTION__);
|
||||
|
||||
|
@ -334,6 +566,7 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port)
|
|||
{
|
||||
option_value = 1024 * 32;
|
||||
option_len = sizeof(option_value);
|
||||
|
||||
if (setsockopt(tcp->sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &option_value, option_len) < 0)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to set receive buffer len\n", __FUNCTION__);
|
||||
|
@ -346,15 +579,17 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port)
|
|||
return FALSE;
|
||||
|
||||
tcp->bufferedBio = BIO_new(BIO_s_buffered_socket());
|
||||
|
||||
if (!tcp->bufferedBio)
|
||||
return FALSE;
|
||||
|
||||
tcp->bufferedBio->ptr = tcp;
|
||||
|
||||
tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL tcp_disconnect(rdpTcp* tcp)
|
||||
{
|
||||
freerdp_tcp_disconnect(tcp->sockfd);
|
||||
|
@ -469,16 +704,21 @@ int tcp_attach(rdpTcp* tcp, int sockfd)
|
|||
}
|
||||
else
|
||||
{
|
||||
tcp->socketBio = BIO_new_socket(sockfd, 1);
|
||||
tcp->socketBio = BIO_new(BIO_s_simple_socket());
|
||||
|
||||
if (!tcp->socketBio)
|
||||
return -1;
|
||||
|
||||
BIO_set_fd(tcp->socketBio, sockfd, BIO_CLOSE);
|
||||
}
|
||||
|
||||
if (!tcp->bufferedBio)
|
||||
{
|
||||
tcp->bufferedBio = BIO_new(BIO_s_buffered_socket());
|
||||
|
||||
if (!tcp->bufferedBio)
|
||||
return FALSE;
|
||||
|
||||
tcp->bufferedBio->ptr = tcp;
|
||||
|
||||
tcp->bufferedBio = BIO_push(tcp->bufferedBio, tcp->socketBio);
|
||||
|
@ -503,7 +743,8 @@ rdpTcp* tcp_new(rdpSettings* settings)
|
|||
{
|
||||
rdpTcp* tcp;
|
||||
|
||||
tcp = (rdpTcp *)calloc(1, sizeof(rdpTcp));
|
||||
tcp = (rdpTcp*) calloc(1, sizeof(rdpTcp));
|
||||
|
||||
if (!tcp)
|
||||
return NULL;
|
||||
|
||||
|
@ -513,17 +754,19 @@ rdpTcp* tcp_new(rdpSettings* settings)
|
|||
tcp->sockfd = -1;
|
||||
tcp->settings = settings;
|
||||
|
||||
if (0)
|
||||
goto out_ringbuffer; /* avoid unreferenced label warning on Windows */
|
||||
|
||||
#ifndef _WIN32
|
||||
tcp->event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, tcp->sockfd);
|
||||
|
||||
if (!tcp->event || tcp->event == INVALID_HANDLE_VALUE)
|
||||
goto out_ringbuffer;
|
||||
#endif
|
||||
|
||||
return tcp;
|
||||
#ifndef _WIN32
|
||||
out_ringbuffer:
|
||||
ringbuffer_destroy(&tcp->xmitBuffer);
|
||||
#endif
|
||||
out_free:
|
||||
free(tcp);
|
||||
return NULL;
|
||||
|
|
|
@ -38,7 +38,8 @@
|
|||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
#define BIO_TYPE_BUFFERED 66
|
||||
#define BIO_TYPE_SIMPLE 66
|
||||
#define BIO_TYPE_BUFFERED 67
|
||||
|
||||
typedef struct rdp_tcp rdpTcp;
|
||||
|
||||
|
@ -51,16 +52,15 @@ struct rdp_tcp
|
|||
#ifdef _WIN32
|
||||
WSAEVENT wsa_event;
|
||||
#endif
|
||||
BIO *socketBio;
|
||||
BIO *bufferedBio;
|
||||
BIO* socketBio;
|
||||
BIO* bufferedBio;
|
||||
RingBuffer xmitBuffer;
|
||||
BOOL writeBlocked;
|
||||
BOOL readBlocked;
|
||||
|
||||
HANDLE event;
|
||||
};
|
||||
|
||||
BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port);
|
||||
BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout);
|
||||
BOOL tcp_disconnect(rdpTcp* tcp);
|
||||
int tcp_read(rdpTcp* tcp, BYTE* data, int length);
|
||||
int tcp_write(rdpTcp* tcp, BYTE* data, int length);
|
||||
|
|
|
@ -133,15 +133,20 @@ static int transport_bio_tsg_write(BIO* bio, const char* buf, int num)
|
|||
|
||||
tsg = (rdpTsg*) bio->ptr;
|
||||
|
||||
BIO_clear_retry_flags(bio);
|
||||
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
|
||||
|
||||
status = tsg_write(tsg, (BYTE*) buf, num);
|
||||
if (status > 0)
|
||||
return status;
|
||||
|
||||
if (status == 0)
|
||||
BIO_set_retry_write(bio);
|
||||
if (status < 0)
|
||||
{
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
}
|
||||
else
|
||||
{
|
||||
BIO_set_flags(bio, BIO_FLAGS_WRITE);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return status >= 0 ? status : -1;
|
||||
}
|
||||
|
||||
static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
|
||||
|
@ -150,18 +155,18 @@ static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
|
|||
rdpTsg* tsg;
|
||||
|
||||
tsg = (rdpTsg*) bio->ptr;
|
||||
|
||||
BIO_clear_flags(bio, BIO_FLAGS_READ);
|
||||
|
||||
status = tsg_read(bio->ptr, (BYTE*) buf, size);
|
||||
|
||||
BIO_clear_retry_flags(bio);
|
||||
|
||||
if (status == 0)
|
||||
if (status < 0)
|
||||
{
|
||||
BIO_set_retry_read(bio);
|
||||
status = -1;
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
}
|
||||
else if (status == -1)
|
||||
else
|
||||
{
|
||||
status = 0;
|
||||
BIO_set_flags(bio, BIO_FLAGS_READ);
|
||||
}
|
||||
|
||||
return status >= 0 ? status : -1;
|
||||
|
@ -192,8 +197,7 @@ static int transport_bio_tsg_new(BIO* bio)
|
|||
bio->init = 1;
|
||||
bio->num = 0;
|
||||
bio->ptr = NULL;
|
||||
bio->flags = 0;
|
||||
|
||||
bio->flags = BIO_FLAGS_SHOULD_RETRY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -223,8 +227,6 @@ BIO_METHOD* BIO_s_tsg(void)
|
|||
return &transport_bio_tsg_methods;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL transport_connect_tls(rdpTransport* transport)
|
||||
{
|
||||
rdpSettings *settings = transport->settings;
|
||||
|
@ -266,6 +268,8 @@ BOOL transport_connect_tls(rdpTransport* transport)
|
|||
if (targetTls->port == 0)
|
||||
targetTls->port = 3389;
|
||||
|
||||
targetTls->isGatewayTransport = FALSE;
|
||||
|
||||
tls_status = tls_connect(targetTls, targetBio);
|
||||
|
||||
if (tls_status < 1)
|
||||
|
@ -371,6 +375,7 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16
|
|||
context = instance->context;
|
||||
|
||||
tsg = tsg_new(transport);
|
||||
|
||||
if (!tsg)
|
||||
return FALSE;
|
||||
|
||||
|
@ -381,12 +386,15 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16
|
|||
if (!transport->TlsIn)
|
||||
{
|
||||
transport->TlsIn = tls_new(settings);
|
||||
|
||||
if (!transport->TlsIn)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!transport->TlsOut)
|
||||
{
|
||||
transport->TlsOut = tls_new(settings);
|
||||
|
||||
if (!transport->TlsOut)
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -398,8 +406,10 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16
|
|||
transport->TlsIn->hostname = transport->TlsOut->hostname = settings->GatewayHostname;
|
||||
transport->TlsIn->port = transport->TlsOut->port = settings->GatewayPort;
|
||||
|
||||
transport->TlsIn->isGatewayTransport = TRUE;
|
||||
|
||||
tls_status = tls_connect(transport->TlsIn, transport->TcpIn->bufferedBio);
|
||||
|
||||
if (tls_status < 1)
|
||||
{
|
||||
if (tls_status < 0)
|
||||
|
@ -416,7 +426,10 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
transport->TlsOut->isGatewayTransport = TRUE;
|
||||
|
||||
tls_status = tls_connect(transport->TlsOut, transport->TcpOut->bufferedBio);
|
||||
|
||||
if (tls_status < 1)
|
||||
{
|
||||
if (tls_status < 0)
|
||||
|
@ -438,10 +451,11 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16
|
|||
|
||||
transport->frontBio = BIO_new(BIO_s_tsg());
|
||||
transport->frontBio->ptr = tsg;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port)
|
||||
BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port, int timeout)
|
||||
{
|
||||
BOOL status = FALSE;
|
||||
rdpSettings* settings = transport->settings;
|
||||
|
@ -454,21 +468,22 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por
|
|||
transport->SplitInputOutput = TRUE;
|
||||
transport->TcpOut = tcp_new(settings);
|
||||
|
||||
if (!tcp_connect(transport->TcpIn, settings->GatewayHostname, settings->GatewayPort) ||
|
||||
if (!tcp_connect(transport->TcpIn, settings->GatewayHostname, settings->GatewayPort, timeout) ||
|
||||
!tcp_set_blocking_mode(transport->TcpIn, FALSE))
|
||||
return FALSE;
|
||||
|
||||
if (!tcp_connect(transport->TcpOut, settings->GatewayHostname, settings->GatewayPort) ||
|
||||
if (!tcp_connect(transport->TcpOut, settings->GatewayHostname, settings->GatewayPort, timeout) ||
|
||||
!tcp_set_blocking_mode(transport->TcpOut, FALSE))
|
||||
return FALSE;
|
||||
|
||||
if (!transport_tsg_connect(transport, hostname, port))
|
||||
return FALSE;
|
||||
|
||||
status = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = tcp_connect(transport->TcpIn, hostname, port);
|
||||
status = tcp_connect(transport->TcpIn, hostname, port, timeout);
|
||||
|
||||
transport->SplitInputOutput = FALSE;
|
||||
transport->TcpOut = transport->TcpIn;
|
||||
|
@ -633,6 +648,7 @@ static int transport_wait_for_read(rdpTransport* transport)
|
|||
rdpTcp *tcpIn;
|
||||
|
||||
tcpIn = transport->TcpIn;
|
||||
|
||||
if (tcpIn->readBlocked)
|
||||
{
|
||||
rsetPtr = &rset;
|
||||
|
@ -658,7 +674,6 @@ static int transport_wait_for_read(rdpTransport* transport)
|
|||
return select(tcpIn->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv);
|
||||
}
|
||||
|
||||
|
||||
static int transport_wait_for_write(rdpTransport* transport)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
@ -692,26 +707,24 @@ static int transport_wait_for_write(rdpTransport* transport)
|
|||
return select(tcpOut->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv);
|
||||
}
|
||||
|
||||
|
||||
int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes)
|
||||
{
|
||||
int read = 0;
|
||||
int status = -1;
|
||||
|
||||
if (!transport->frontBio)
|
||||
{
|
||||
transport->layer = TRANSPORT_LAYER_CLOSED;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (read < bytes)
|
||||
{
|
||||
status = BIO_read(transport->frontBio, data + read, bytes - read);
|
||||
|
||||
if (!status)
|
||||
if (status <= 0)
|
||||
{
|
||||
transport->layer = TRANSPORT_LAYER_CLOSED;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
if (!BIO_should_retry(transport->frontBio))
|
||||
if (!transport->frontBio || !BIO_should_retry(transport->frontBio))
|
||||
{
|
||||
/* something unexpected happened, let's close */
|
||||
transport->layer = TRANSPORT_LAYER_CLOSED;
|
||||
|
@ -742,8 +755,6 @@ int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes)
|
|||
return read;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int transport_read(rdpTransport* transport, wStream* s)
|
||||
{
|
||||
int status;
|
||||
|
@ -1101,7 +1112,7 @@ int transport_check_fds(rdpTransport* transport)
|
|||
return status;
|
||||
|
||||
if ((pos = Stream_GetPosition(transport->ReceiveBuffer)) < 2)
|
||||
return status;
|
||||
return 0;
|
||||
|
||||
Stream_SetPosition(transport->ReceiveBuffer, 0);
|
||||
length = 0;
|
||||
|
@ -1287,6 +1298,7 @@ static void* transport_client_thread(void* arg)
|
|||
transport_get_read_handles(transport, (HANDLE*) &handles, &nCount);
|
||||
|
||||
status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
|
||||
|
||||
if (transport->layer == TRANSPORT_LAYER_CLOSED)
|
||||
{
|
||||
rdpRdp* rdp = (rdpRdp*) transport->rdp;
|
||||
|
@ -1299,7 +1311,9 @@ static void* transport_client_thread(void* arg)
|
|||
break;
|
||||
|
||||
if (!freerdp_check_fds(instance))
|
||||
break;
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ struct rdp_transport
|
|||
};
|
||||
|
||||
wStream* transport_send_stream_init(rdpTransport* transport, int size);
|
||||
BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port);
|
||||
BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port, int timeout);
|
||||
void transport_attach(rdpTransport* transport, int sockfd);
|
||||
BOOL transport_disconnect(rdpTransport* transport);
|
||||
BOOL transport_connect_rdp(rdpTransport* transport);
|
||||
|
|
|
@ -286,16 +286,32 @@ BOOL update_read_pointer_system(wStream* s, POINTER_SYSTEM_UPDATE* pointer_syste
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL update_read_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color)
|
||||
BOOL update_read_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color, int xorBpp)
|
||||
{
|
||||
BYTE *newMask;
|
||||
int scanlineSize;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 14)
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT16(s, pointer_color->cacheIndex); /* cacheIndex (2 bytes) */
|
||||
Stream_Read_UINT16(s, pointer_color->xPos); /* xPos (2 bytes) */
|
||||
Stream_Read_UINT16(s, pointer_color->yPos); /* yPos (2 bytes) */
|
||||
|
||||
/**
|
||||
* As stated in 2.2.9.1.1.4.4 Color Pointer Update:
|
||||
* The maximum allowed pointer width/height is 96 pixels if the client indicated support
|
||||
* for large pointers by setting the LARGE_POINTER_FLAG (0x00000001) in the Large
|
||||
* Pointer Capability Set (section 2.2.7.2.7). If the LARGE_POINTER_FLAG was not
|
||||
* set, the maximum allowed pointer width/height is 32 pixels.
|
||||
*
|
||||
* So we check for a maximum of 96 for CVE-2014-0250.
|
||||
*/
|
||||
Stream_Read_UINT16(s, pointer_color->width); /* width (2 bytes) */
|
||||
Stream_Read_UINT16(s, pointer_color->height); /* height (2 bytes) */
|
||||
if ((pointer_color->width > 96) || (pointer_color->height > 96))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT16(s, pointer_color->lengthAndMask); /* lengthAndMask (2 bytes) */
|
||||
Stream_Read_UINT16(s, pointer_color->lengthXorMask); /* lengthXorMask (2 bytes) */
|
||||
|
||||
|
@ -312,26 +328,65 @@ BOOL update_read_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color)
|
|||
|
||||
if (pointer_color->lengthXorMask > 0)
|
||||
{
|
||||
/**
|
||||
* Spec states that:
|
||||
*
|
||||
* xorMaskData (variable): A variable-length array of bytes. Contains the 24-bpp, bottom-up
|
||||
* XOR mask scan-line data. The XOR mask is padded to a 2-byte boundary for each encoded
|
||||
* scan-line. For example, if a 3x3 pixel cursor is being sent, then each scan-line will consume 10
|
||||
* bytes (3 pixels per scan-line multiplied by 3 bytes per pixel, rounded up to the next even
|
||||
* number of bytes).
|
||||
*
|
||||
* In fact instead of 24-bpp, the bpp parameter is given by the containing packet.
|
||||
*/
|
||||
if (Stream_GetRemainingLength(s) < pointer_color->lengthXorMask)
|
||||
return FALSE;
|
||||
|
||||
if (!pointer_color->xorMaskData)
|
||||
pointer_color->xorMaskData = malloc(pointer_color->lengthXorMask);
|
||||
else
|
||||
pointer_color->xorMaskData = realloc(pointer_color->xorMaskData, pointer_color->lengthXorMask);
|
||||
scanlineSize = (7 + xorBpp * pointer_color->width) / 8;
|
||||
scanlineSize = ((scanlineSize + 1) / 2) * 2;
|
||||
if (scanlineSize * pointer_color->height != pointer_color->lengthXorMask)
|
||||
{
|
||||
fprintf(stderr, "%s: invalid lengthXorMask: width=%d height=%d, %d instead of %d\n", __FUNCTION__,
|
||||
pointer_color->width, pointer_color->height,
|
||||
pointer_color->lengthXorMask, scanlineSize * pointer_color->height);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
newMask = realloc(pointer_color->xorMaskData, pointer_color->lengthXorMask);
|
||||
if (!newMask)
|
||||
return FALSE;
|
||||
|
||||
pointer_color->xorMaskData = newMask;
|
||||
|
||||
Stream_Read(s, pointer_color->xorMaskData, pointer_color->lengthXorMask);
|
||||
}
|
||||
|
||||
if (pointer_color->lengthAndMask > 0)
|
||||
{
|
||||
/**
|
||||
* andMaskData (variable): A variable-length array of bytes. Contains the 1-bpp, bottom-up
|
||||
* AND mask scan-line data. The AND mask is padded to a 2-byte boundary for each encoded
|
||||
* scan-line. For example, if a 7x7 pixel cursor is being sent, then each scan-line will consume 2
|
||||
* bytes (7 pixels per scan-line multiplied by 1 bpp, rounded up to the next even number of
|
||||
* bytes).
|
||||
*/
|
||||
if (Stream_GetRemainingLength(s) < pointer_color->lengthAndMask)
|
||||
return FALSE;
|
||||
|
||||
if (!pointer_color->andMaskData)
|
||||
pointer_color->andMaskData = malloc(pointer_color->lengthAndMask);
|
||||
else
|
||||
pointer_color->andMaskData = realloc(pointer_color->andMaskData, pointer_color->lengthAndMask);
|
||||
scanlineSize = ((7 + pointer_color->width) / 8);
|
||||
scanlineSize = ((1 + scanlineSize) / 2) * 2;
|
||||
if (scanlineSize * pointer_color->height != pointer_color->lengthAndMask)
|
||||
{
|
||||
fprintf(stderr, "%s: invalid lengthAndMask: %d instead of %d\n", __FUNCTION__,
|
||||
pointer_color->lengthAndMask, scanlineSize * pointer_color->height);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
newMask = realloc(pointer_color->andMaskData, pointer_color->lengthAndMask);
|
||||
if (!newMask)
|
||||
return FALSE;
|
||||
|
||||
pointer_color->andMaskData = newMask;
|
||||
|
||||
Stream_Read(s, pointer_color->andMaskData, pointer_color->lengthAndMask);
|
||||
}
|
||||
|
@ -348,7 +403,12 @@ BOOL update_read_pointer_new(wStream* s, POINTER_NEW_UPDATE* pointer_new)
|
|||
return FALSE;
|
||||
|
||||
Stream_Read_UINT16(s, pointer_new->xorBpp); /* xorBpp (2 bytes) */
|
||||
return update_read_pointer_color(s, &pointer_new->colorPtrAttr); /* colorPtrAttr */
|
||||
if ((pointer_new->xorBpp < 1) || (pointer_new->xorBpp > 32))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid xorBpp %d\n", __FUNCTION__, pointer_new->xorBpp);
|
||||
return FALSE;
|
||||
}
|
||||
return update_read_pointer_color(s, &pointer_new->colorPtrAttr, pointer_new->xorBpp); /* colorPtrAttr */
|
||||
}
|
||||
|
||||
BOOL update_read_pointer_cached(wStream* s, POINTER_CACHED_UPDATE* pointer_cached)
|
||||
|
@ -387,7 +447,7 @@ BOOL update_recv_pointer(rdpUpdate* update, wStream* s)
|
|||
break;
|
||||
|
||||
case PTR_MSG_TYPE_COLOR:
|
||||
if (!update_read_pointer_color(s, &pointer->pointer_color))
|
||||
if (!update_read_pointer_color(s, &pointer->pointer_color, 24))
|
||||
return FALSE;
|
||||
IFCALL(pointer->PointerColor, context, &pointer->pointer_color);
|
||||
break;
|
||||
|
|
|
@ -53,7 +53,7 @@ BOOL update_recv(rdpUpdate* update, wStream* s);
|
|||
|
||||
BOOL update_read_pointer_position(wStream* s, POINTER_POSITION_UPDATE* pointer_position);
|
||||
BOOL update_read_pointer_system(wStream* s, POINTER_SYSTEM_UPDATE* pointer_system);
|
||||
BOOL update_read_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color);
|
||||
BOOL update_read_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color, int xorBpp);
|
||||
BOOL update_read_pointer_new(wStream* s, POINTER_NEW_UPDATE* pointer_new);
|
||||
BOOL update_read_pointer_cached(wStream* s, POINTER_CACHED_UPDATE* pointer_cached);
|
||||
|
||||
|
|
|
@ -30,12 +30,19 @@
|
|||
|
||||
BOOL update_read_icon_info(wStream* s, ICON_INFO* iconInfo)
|
||||
{
|
||||
BYTE *newBitMask;
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT16(s, iconInfo->cacheEntry); /* cacheEntry (2 bytes) */
|
||||
Stream_Read_UINT8(s, iconInfo->cacheId); /* cacheId (1 byte) */
|
||||
Stream_Read_UINT8(s, iconInfo->bpp); /* bpp (1 byte) */
|
||||
if ((iconInfo->bpp < 1) || (iconInfo->bpp > 32))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid bpp value %d", __FUNCTION__, iconInfo->bpp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT16(s, iconInfo->width); /* width (2 bytes) */
|
||||
Stream_Read_UINT16(s, iconInfo->height); /* height (2 bytes) */
|
||||
|
||||
|
@ -62,10 +69,10 @@ BOOL update_read_icon_info(wStream* s, ICON_INFO* iconInfo)
|
|||
return FALSE;
|
||||
|
||||
/* bitsMask */
|
||||
if (iconInfo->bitsMask == NULL)
|
||||
iconInfo->bitsMask = (BYTE*) malloc(iconInfo->cbBitsMask);
|
||||
else
|
||||
iconInfo->bitsMask = (BYTE*) realloc(iconInfo->bitsMask, iconInfo->cbBitsMask);
|
||||
newBitMask = (BYTE*) realloc(iconInfo->bitsMask, iconInfo->cbBitsMask);
|
||||
if (!newBitMask)
|
||||
return FALSE;
|
||||
iconInfo->bitsMask = newBitMask;
|
||||
|
||||
Stream_Read(s, iconInfo->bitsMask, iconInfo->cbBitsMask);
|
||||
|
||||
|
@ -89,10 +96,10 @@ BOOL update_read_icon_info(wStream* s, ICON_INFO* iconInfo)
|
|||
Stream_Read(s, iconInfo->colorTable, iconInfo->cbColorTable);
|
||||
|
||||
/* bitsColor */
|
||||
if (iconInfo->bitsColor == NULL)
|
||||
iconInfo->bitsColor = (BYTE*) malloc(iconInfo->cbBitsColor);
|
||||
else
|
||||
iconInfo->bitsColor = (BYTE*) realloc(iconInfo->bitsColor, iconInfo->cbBitsColor);
|
||||
newBitMask = (BYTE *)realloc(iconInfo->bitsColor, iconInfo->cbBitsColor);
|
||||
if (!newBitMask)
|
||||
return FALSE;
|
||||
iconInfo->bitsColor = newBitMask;
|
||||
|
||||
Stream_Read(s, iconInfo->bitsColor, iconInfo->cbBitsColor);
|
||||
|
||||
|
|
|
@ -33,6 +33,445 @@
|
|||
#include <freerdp/crypto/tls.h>
|
||||
#include "../core/tcp.h"
|
||||
|
||||
struct _BIO_RDP_TLS
|
||||
{
|
||||
SSL* ssl;
|
||||
};
|
||||
typedef struct _BIO_RDP_TLS BIO_RDP_TLS;
|
||||
|
||||
long bio_rdp_tls_callback(BIO* bio, int mode, const char* argp, int argi, long argl, long ret)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bio_rdp_tls_write(BIO* bio, const char* buf, int size)
|
||||
{
|
||||
int status;
|
||||
BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr;
|
||||
|
||||
if (!buf || !tls)
|
||||
return 0;
|
||||
|
||||
BIO_clear_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL);
|
||||
|
||||
status = SSL_write(tls->ssl, buf, size);
|
||||
|
||||
if (status <= 0)
|
||||
{
|
||||
switch (SSL_get_error(tls->ssl, status))
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
BIO_set_flags(bio, BIO_FLAGS_WRITE);
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
BIO_set_flags(bio, BIO_FLAGS_READ);
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
|
||||
bio->retry_reason = BIO_RR_SSL_X509_LOOKUP;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
|
||||
bio->retry_reason = BIO_RR_CONNECT;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_SYSCALL:
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
break;
|
||||
|
||||
case SSL_ERROR_SSL:
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int bio_rdp_tls_read(BIO* bio, char* buf, int size)
|
||||
{
|
||||
int status;
|
||||
BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr;
|
||||
|
||||
if (!buf || !tls)
|
||||
return 0;
|
||||
|
||||
BIO_clear_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL);
|
||||
|
||||
status = SSL_read(tls->ssl, buf, size);
|
||||
|
||||
if (status <= 0)
|
||||
{
|
||||
switch (SSL_get_error(tls->ssl, status))
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
BIO_set_flags(bio, BIO_FLAGS_READ);
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
BIO_set_flags(bio, BIO_FLAGS_WRITE);
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
|
||||
bio->retry_reason = BIO_RR_SSL_X509_LOOKUP;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_ACCEPT:
|
||||
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
|
||||
bio->retry_reason = BIO_RR_ACCEPT;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
|
||||
bio->retry_reason = BIO_RR_CONNECT;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_SSL:
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
break;
|
||||
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
break;
|
||||
|
||||
case SSL_ERROR_SYSCALL:
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int bio_rdp_tls_puts(BIO* bio, const char* str)
|
||||
{
|
||||
int size;
|
||||
int status;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
size = strlen(str);
|
||||
status = BIO_write(bio, str, size);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int bio_rdp_tls_gets(BIO* bio, char* str, int size)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr)
|
||||
{
|
||||
BIO* rbio;
|
||||
int status = -1;
|
||||
BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr;
|
||||
|
||||
if (!tls)
|
||||
return 0;
|
||||
|
||||
if (!tls->ssl && (cmd != BIO_C_SET_SSL))
|
||||
return 0;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case BIO_CTRL_RESET:
|
||||
SSL_shutdown(tls->ssl);
|
||||
|
||||
if (tls->ssl->handshake_func == tls->ssl->method->ssl_connect)
|
||||
SSL_set_connect_state(tls->ssl);
|
||||
else if (tls->ssl->handshake_func == tls->ssl->method->ssl_accept)
|
||||
SSL_set_accept_state(tls->ssl);
|
||||
|
||||
SSL_clear(tls->ssl);
|
||||
|
||||
if (bio->next_bio)
|
||||
status = BIO_ctrl(bio->next_bio, cmd, num, ptr);
|
||||
else if (tls->ssl->rbio)
|
||||
status = BIO_ctrl(tls->ssl->rbio, cmd, num, ptr);
|
||||
else
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
case BIO_C_GET_FD:
|
||||
status = BIO_ctrl(tls->ssl->rbio, cmd, num, ptr);
|
||||
break;
|
||||
|
||||
case BIO_CTRL_INFO:
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_SET_CALLBACK:
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_GET_CALLBACK:
|
||||
*((ULONG_PTR*) ptr) = (ULONG_PTR) SSL_get_info_callback(tls->ssl);
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
case BIO_C_SSL_MODE:
|
||||
if (num)
|
||||
SSL_set_connect_state(tls->ssl);
|
||||
else
|
||||
SSL_set_accept_state(tls->ssl);
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_GET_CLOSE:
|
||||
status = bio->shutdown;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_SET_CLOSE:
|
||||
bio->shutdown = (int) num;
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_WPENDING:
|
||||
status = BIO_ctrl(tls->ssl->wbio, cmd, num, ptr);
|
||||
break;
|
||||
|
||||
case BIO_CTRL_PENDING:
|
||||
status = SSL_pending(tls->ssl);
|
||||
if (status == 0)
|
||||
status = BIO_pending(tls->ssl->rbio);
|
||||
break;
|
||||
|
||||
case BIO_CTRL_FLUSH:
|
||||
BIO_clear_retry_flags(bio);
|
||||
status = BIO_ctrl(tls->ssl->wbio, cmd, num, ptr);
|
||||
BIO_copy_next_retry(bio);
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_PUSH:
|
||||
if (bio->next_bio && (bio->next_bio != tls->ssl->rbio))
|
||||
{
|
||||
SSL_set_bio(tls->ssl, bio->next_bio, bio->next_bio);
|
||||
CRYPTO_add(&(bio->next_bio->references), 1, CRYPTO_LOCK_BIO);
|
||||
}
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_POP:
|
||||
if (bio == ptr)
|
||||
{
|
||||
if (tls->ssl->rbio != tls->ssl->wbio)
|
||||
BIO_free_all(tls->ssl->wbio);
|
||||
|
||||
if (bio->next_bio)
|
||||
CRYPTO_add(&(bio->next_bio->references), -1, CRYPTO_LOCK_BIO);
|
||||
|
||||
tls->ssl->wbio = tls->ssl->rbio = NULL;
|
||||
}
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
case BIO_C_GET_SSL:
|
||||
if (ptr)
|
||||
{
|
||||
*((SSL**) ptr) = tls->ssl;
|
||||
status = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIO_C_SET_SSL:
|
||||
bio->shutdown = (int) num;
|
||||
|
||||
if (ptr)
|
||||
tls->ssl = (SSL*) ptr;
|
||||
|
||||
rbio = SSL_get_rbio(tls->ssl);
|
||||
|
||||
if (rbio)
|
||||
{
|
||||
if (bio->next_bio)
|
||||
BIO_push(rbio, bio->next_bio);
|
||||
|
||||
bio->next_bio = rbio;
|
||||
CRYPTO_add(&(rbio->references), 1, CRYPTO_LOCK_BIO);
|
||||
}
|
||||
|
||||
bio->init = 1;
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
case BIO_C_DO_STATE_MACHINE:
|
||||
BIO_clear_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL);
|
||||
bio->retry_reason = 0;
|
||||
|
||||
status = SSL_do_handshake(tls->ssl);
|
||||
|
||||
if (status <= 0)
|
||||
{
|
||||
switch (SSL_get_error(tls->ssl, status))
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY);
|
||||
bio->retry_reason = bio->next_bio->retry_reason;
|
||||
break;
|
||||
|
||||
default:
|
||||
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
status = BIO_ctrl(tls->ssl->rbio, cmd, num, ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int bio_rdp_tls_new(BIO* bio)
|
||||
{
|
||||
BIO_RDP_TLS* tls;
|
||||
|
||||
bio->init = 0;
|
||||
bio->num = 0;
|
||||
bio->flags = BIO_FLAGS_SHOULD_RETRY;
|
||||
bio->next_bio = NULL;
|
||||
|
||||
tls = calloc(1, sizeof(BIO_RDP_TLS));
|
||||
|
||||
if (!tls)
|
||||
return 0;
|
||||
|
||||
bio->ptr = (void*) tls;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bio_rdp_tls_free(BIO* bio)
|
||||
{
|
||||
BIO_RDP_TLS* tls;
|
||||
|
||||
if (!bio)
|
||||
return 0;
|
||||
|
||||
tls = (BIO_RDP_TLS*) bio->ptr;
|
||||
|
||||
if (!tls)
|
||||
return 0;
|
||||
|
||||
if (bio->shutdown)
|
||||
{
|
||||
if (bio->init && tls->ssl)
|
||||
{
|
||||
SSL_shutdown(tls->ssl);
|
||||
SSL_free(tls->ssl);
|
||||
}
|
||||
|
||||
bio->init = 0;
|
||||
bio->flags = 0;
|
||||
}
|
||||
|
||||
free(tls);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static long bio_rdp_tls_callback_ctrl(BIO* bio, int cmd, bio_info_cb* fp)
|
||||
{
|
||||
int status = 0;
|
||||
BIO_RDP_TLS* tls;
|
||||
|
||||
if (!bio)
|
||||
return 0;
|
||||
|
||||
tls = (BIO_RDP_TLS*) bio->ptr;
|
||||
|
||||
if (!tls)
|
||||
return 0;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case BIO_CTRL_SET_CALLBACK:
|
||||
SSL_set_info_callback(tls->ssl, (void (*)(const SSL *, int, int)) fp);
|
||||
status = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
status = BIO_callback_ctrl(tls->ssl->rbio, cmd, fp);
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#define BIO_TYPE_RDP_TLS 68
|
||||
|
||||
static BIO_METHOD bio_rdp_tls_methods =
|
||||
{
|
||||
BIO_TYPE_RDP_TLS,
|
||||
"RdpTls",
|
||||
bio_rdp_tls_write,
|
||||
bio_rdp_tls_read,
|
||||
bio_rdp_tls_puts,
|
||||
bio_rdp_tls_gets,
|
||||
bio_rdp_tls_ctrl,
|
||||
bio_rdp_tls_new,
|
||||
bio_rdp_tls_free,
|
||||
bio_rdp_tls_callback_ctrl,
|
||||
};
|
||||
|
||||
BIO_METHOD* BIO_s_rdp_tls(void)
|
||||
{
|
||||
return &bio_rdp_tls_methods;
|
||||
}
|
||||
|
||||
BIO* BIO_new_rdp_tls(SSL_CTX* ctx, int client)
|
||||
{
|
||||
BIO* bio;
|
||||
SSL* ssl;
|
||||
|
||||
bio = BIO_new(BIO_s_rdp_tls());
|
||||
|
||||
if (!bio)
|
||||
return NULL;
|
||||
|
||||
ssl = SSL_new(ctx);
|
||||
|
||||
if (!ssl)
|
||||
{
|
||||
BIO_free(bio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (client)
|
||||
SSL_set_connect_state(ssl);
|
||||
else
|
||||
SSL_set_accept_state(ssl);
|
||||
|
||||
BIO_set_ssl(bio, ssl, BIO_CLOSE);
|
||||
|
||||
return bio;
|
||||
}
|
||||
|
||||
static CryptoCert tls_get_certificate(rdpTls* tls, BOOL peer)
|
||||
{
|
||||
CryptoCert cert;
|
||||
|
@ -41,7 +480,7 @@ static CryptoCert tls_get_certificate(rdpTls* tls, BOOL peer)
|
|||
if (peer)
|
||||
remote_cert = SSL_get_peer_certificate(tls->ssl);
|
||||
else
|
||||
remote_cert = SSL_get_certificate(tls->ssl);
|
||||
remote_cert = X509_dup( SSL_get_certificate(tls->ssl) );
|
||||
|
||||
if (!remote_cert)
|
||||
{
|
||||
|
@ -109,7 +548,11 @@ out_free:
|
|||
}
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
BOOL tls_prepare(rdpTls* tls, BIO *underlying, SSL_METHOD *method, int options, BOOL clientMode)
|
||||
#else
|
||||
BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int options, BOOL clientMode)
|
||||
#endif
|
||||
{
|
||||
tls->ctx = SSL_CTX_new(method);
|
||||
if (!tls->ctx)
|
||||
|
@ -123,7 +566,8 @@ BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int opt
|
|||
SSL_CTX_set_options(tls->ctx, options);
|
||||
SSL_CTX_set_read_ahead(tls->ctx, 1);
|
||||
|
||||
tls->bio = BIO_new_ssl(tls->ctx, clientMode);
|
||||
tls->bio = BIO_new_rdp_tls(tls->ctx, clientMode);
|
||||
|
||||
if (BIO_get_ssl(tls->bio, &tls->ssl) < 0)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to retrieve the SSL of the connection\n", __FUNCTION__);
|
||||
|
@ -131,6 +575,7 @@ BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int opt
|
|||
}
|
||||
|
||||
BIO_push(tls->bio, underlying);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -146,8 +591,10 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode)
|
|||
int fd;
|
||||
|
||||
status = BIO_do_handshake(tls->bio);
|
||||
|
||||
if (status == 1)
|
||||
break;
|
||||
|
||||
if (!BIO_should_retry(tls->bio))
|
||||
return -1;
|
||||
|
||||
|
@ -156,6 +603,7 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode)
|
|||
FD_ZERO(&rset);
|
||||
|
||||
fd = BIO_get_fd(tls->bio, NULL);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to retrieve BIO fd\n", __FUNCTION__);
|
||||
|
@ -167,6 +615,7 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode)
|
|||
tv.tv_usec = 10 * 1000; /* 10ms */
|
||||
|
||||
status = select(fd + 1, &rset, NULL, NULL, &tv);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
fprintf(stderr, "%s: error during select()\n", __FUNCTION__);
|
||||
|
@ -175,9 +624,6 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode)
|
|||
}
|
||||
while (TRUE);
|
||||
|
||||
if (!clientMode)
|
||||
return 1;
|
||||
|
||||
cert = tls_get_certificate(tls, clientMode);
|
||||
if (!cert)
|
||||
{
|
||||
|
@ -189,26 +635,34 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode)
|
|||
if (!tls->Bindings)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to retrieve bindings\n", __FUNCTION__);
|
||||
return -1;
|
||||
verify_status = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!crypto_cert_get_public_key(cert, &tls->PublicKey, &tls->PublicKeyLength))
|
||||
{
|
||||
fprintf(stderr, "%s: crypto_cert_get_public_key failed to return the server public key.\n", __FUNCTION__);
|
||||
tls_free_certificate(cert);
|
||||
return -1;
|
||||
verify_status = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
verify_status = tls_verify_certificate(tls, cert, tls->hostname, tls->port);
|
||||
|
||||
if (verify_status < 1)
|
||||
/* Note: server-side NLA needs public keys (keys from us, the server) but no
|
||||
* certificate verify
|
||||
*/
|
||||
verify_status = 1;
|
||||
if (clientMode)
|
||||
{
|
||||
fprintf(stderr, "%s: certificate not trusted, aborting.\n", __FUNCTION__);
|
||||
tls_disconnect(tls);
|
||||
tls_free_certificate(cert);
|
||||
return 0;
|
||||
verify_status = tls_verify_certificate(tls, cert, tls->hostname, tls->port);
|
||||
|
||||
if (verify_status < 1)
|
||||
{
|
||||
fprintf(stderr, "%s: certificate not trusted, aborting.\n", __FUNCTION__);
|
||||
tls_disconnect(tls);
|
||||
verify_status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
tls_free_certificate(cert);
|
||||
|
||||
return verify_status;
|
||||
|
@ -379,22 +833,23 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
|
|||
fd_set rset, wset;
|
||||
fd_set *rsetPtr, *wsetPtr;
|
||||
struct timeval tv;
|
||||
BIO *bio = tls->bio;
|
||||
BIO* bio = tls->bio;
|
||||
DataChunk chunks[2];
|
||||
|
||||
BIO *bufferedBio = findBufferedBio(bio);
|
||||
BIO* bufferedBio = findBufferedBio(bio);
|
||||
|
||||
if (!bufferedBio)
|
||||
{
|
||||
fprintf(stderr, "%s: error unable to retrieve the bufferedBio in the BIO chain\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tcp = (rdpTcp *)bufferedBio->ptr;
|
||||
tcp = (rdpTcp*) bufferedBio->ptr;
|
||||
|
||||
do
|
||||
{
|
||||
status = BIO_write(bio, data, length);
|
||||
/*fprintf(stderr, "%s: BIO_write(len=%d) = %d (retry=%d)\n", __FUNCTION__, length, status, BIO_should_retry(bio));*/
|
||||
|
||||
if (status > 0)
|
||||
break;
|
||||
|
||||
|
@ -403,6 +858,7 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
|
|||
|
||||
/* we try to handle SSL want_read and want_write nicely */
|
||||
rsetPtr = wsetPtr = 0;
|
||||
|
||||
if (tcp->writeBlocked)
|
||||
{
|
||||
wsetPtr = &wset;
|
||||
|
@ -426,6 +882,7 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
|
|||
tv.tv_usec = 100 * 1000;
|
||||
|
||||
status = select(tcp->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
}
|
||||
|
@ -442,6 +899,7 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
|
|||
while (chunks[i].size)
|
||||
{
|
||||
status = BIO_write(tcp->socketBio, chunks[i].data, chunks[i].size);
|
||||
|
||||
if (status > 0)
|
||||
{
|
||||
chunks[i].size -= status;
|
||||
|
@ -452,12 +910,14 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
|
|||
|
||||
if (!BIO_should_retry(tcp->socketBio))
|
||||
goto out_fail;
|
||||
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(tcp->sockfd, &rset);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100 * 1000;
|
||||
|
||||
status = select(tcp->sockfd + 1, &rset, NULL, NULL, &tv);
|
||||
|
||||
if (status < 0)
|
||||
goto out_fail;
|
||||
}
|
||||
|
@ -473,8 +933,6 @@ out_fail:
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int tls_set_alert_code(rdpTls* tls, int level, int description)
|
||||
{
|
||||
tls->alertLevel = level;
|
||||
|
@ -587,7 +1045,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por
|
|||
|
||||
if (instance->VerifyX509Certificate)
|
||||
{
|
||||
status = instance->VerifyX509Certificate(instance, pemCert, length, hostname, port, 0);
|
||||
status = instance->VerifyX509Certificate(instance, pemCert, length, hostname, port, tls->isGatewayTransport);
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: (length = %d) status: %d\n%s\n", __FUNCTION__, length, status, pemCert);
|
||||
|
@ -794,7 +1252,8 @@ rdpTls* tls_new(rdpSettings* settings)
|
|||
{
|
||||
rdpTls* tls;
|
||||
|
||||
tls = (rdpTls *)calloc(1, sizeof(rdpTls));
|
||||
tls = (rdpTls*) calloc(1, sizeof(rdpTls));
|
||||
|
||||
if (!tls)
|
||||
return NULL;
|
||||
|
||||
|
@ -803,11 +1262,13 @@ rdpTls* tls_new(rdpSettings* settings)
|
|||
|
||||
tls->settings = settings;
|
||||
tls->certificate_store = certificate_store_new(settings);
|
||||
|
||||
if (!tls->certificate_store)
|
||||
goto out_free;
|
||||
|
||||
tls->alertLevel = TLS_ALERT_LEVEL_WARNING;
|
||||
tls->alertDescription = TLS_ALERT_DESCRIPTION_CLOSE_NOTIFY;
|
||||
|
||||
return tls;
|
||||
|
||||
out_free:
|
||||
|
|
|
@ -187,6 +187,7 @@ int freerdp_tcp_write(int sockfd, BYTE* data, int length)
|
|||
int freerdp_tcp_wait_read(int sockfd)
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
|
||||
if (sockfd < 1)
|
||||
{
|
||||
|
@ -196,7 +197,11 @@ int freerdp_tcp_wait_read(int sockfd)
|
|||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(sockfd, &fds);
|
||||
select(sockfd+1, &fds, NULL, NULL, NULL);
|
||||
timeout.tv_sec = 5;
|
||||
timeout.tv_usec = 0;
|
||||
select(sockfd+1, &fds, NULL, NULL, &timeout);
|
||||
if (!FD_ISSET(sockfd, &fds))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -204,6 +209,7 @@ int freerdp_tcp_wait_read(int sockfd)
|
|||
int freerdp_tcp_wait_write(int sockfd)
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
|
||||
if (sockfd < 1)
|
||||
{
|
||||
|
@ -213,7 +219,11 @@ int freerdp_tcp_wait_write(int sockfd)
|
|||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(sockfd, &fds);
|
||||
select(sockfd+1, NULL, &fds, NULL, NULL);
|
||||
timeout.tv_sec = 5;
|
||||
timeout.tv_usec = 0;
|
||||
select(sockfd+1, NULL, &fds, NULL, &timeout);
|
||||
if (!FD_ISSET(sockfd, &fds))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
TestFreeRDPutils.c
|
||||
TestFreeRDPUtils.c
|
||||
|
|
|
@ -405,6 +405,7 @@ static void* tf_debug_channel_thread_func(void* arg)
|
|||
wStream* s;
|
||||
void* buffer;
|
||||
DWORD BytesReturned = 0;
|
||||
ULONG written;
|
||||
testPeerContext* context = (testPeerContext*) arg;
|
||||
|
||||
if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer, &BytesReturned) == TRUE)
|
||||
|
@ -417,7 +418,7 @@ static void* tf_debug_channel_thread_func(void* arg)
|
|||
|
||||
s = Stream_New(NULL, 4096);
|
||||
|
||||
WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test1", 5, NULL);
|
||||
WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test1", 5, &written);
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
@ -533,7 +534,8 @@ BOOL tf_peer_activate(freerdp_peer* client)
|
|||
|
||||
//client->settings->CompressionLevel = PACKET_COMPR_TYPE_8K;
|
||||
//client->settings->CompressionLevel = PACKET_COMPR_TYPE_64K;
|
||||
client->settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
|
||||
//client->settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
|
||||
client->settings->CompressionLevel = PACKET_COMPR_TYPE_RDP61;
|
||||
|
||||
if (test_pcap_file != NULL)
|
||||
{
|
||||
|
@ -582,7 +584,8 @@ void tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
|
|||
{
|
||||
if (context->debug_channel)
|
||||
{
|
||||
WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test2", 5, NULL);
|
||||
ULONG written;
|
||||
WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test2", 5, &written);
|
||||
}
|
||||
}
|
||||
else if ((flags & 0x4000) && code == 0x2D) /* 'x' key */
|
||||
|
|
|
@ -541,6 +541,10 @@ static void* xf_peer_main_loop(void* arg)
|
|||
settings->RemoteFxCodec = TRUE;
|
||||
settings->ColorDepth = 32;
|
||||
|
||||
settings->NlaSecurity = FALSE;
|
||||
settings->TlsSecurity = TRUE;
|
||||
settings->RdpSecurity = FALSE;
|
||||
|
||||
client->Capabilities = xf_peer_capabilities;
|
||||
client->PostConnect = xf_peer_post_connect;
|
||||
client->Activate = xf_peer_activate;
|
||||
|
|
|
@ -67,9 +67,6 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINPR_EXPORTS")
|
|||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/winpr/config.h)
|
||||
|
||||
add_subdirectory(include)
|
||||
|
||||
add_subdirectory(libwinpr)
|
||||
|
|
|
@ -32,6 +32,22 @@
|
|||
|
||||
#ifndef _WIN32
|
||||
|
||||
static INLINE UINT32 _rotl(UINT32 value, int shift) {
|
||||
return (value << shift) | (value >> (32 - shift));
|
||||
}
|
||||
|
||||
static INLINE UINT64 _rotl64(UINT64 value, int shift) {
|
||||
return (value << shift) | (value >> (64 - shift));
|
||||
}
|
||||
|
||||
static INLINE UINT32 _rotr(UINT32 value, int shift) {
|
||||
return (value >> shift) | (value << (32 - shift));
|
||||
}
|
||||
|
||||
static INLINE UINT64 _rotr64(UINT64 value, int shift) {
|
||||
return (value >> shift) | (value << (64 - shift));
|
||||
}
|
||||
|
||||
#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2))
|
||||
|
||||
#define _byteswap_ushort(_val) __builtin_bswap16(_val)
|
||||
|
|
|
@ -29,7 +29,22 @@
|
|||
|
||||
#include <wincrypt.h>
|
||||
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifndef ALG_TYPE_RESERVED7
|
||||
#define ALG_TYPE_RESERVED7 (7 << 9)
|
||||
#endif
|
||||
|
||||
#if (NTDDI_VERSION <= 0x05010200)
|
||||
#define ALG_SID_SHA_256 12
|
||||
#define ALG_SID_SHA_384 13
|
||||
#define ALG_SID_SHA_512 14
|
||||
#define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
|
||||
#define CALG_SHA_384 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384)
|
||||
#define CALG_SHA_512 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512)
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/* ncrypt.h */
|
||||
|
||||
|
@ -60,7 +75,6 @@ typedef ULONG_PTR NCRYPT_SECRET_HANDLE;
|
|||
#define ALG_TYPE_STREAM (4 << 9)
|
||||
#define ALG_TYPE_DH (5 << 9)
|
||||
#define ALG_TYPE_SECURECHANNEL (6 << 9)
|
||||
#define ALG_TYPE_RESERVED7 (7 << 9)
|
||||
|
||||
#define ALG_SID_ANY (0)
|
||||
|
||||
|
@ -74,8 +88,6 @@ typedef ULONG_PTR NCRYPT_SECRET_HANDLE;
|
|||
#define ALG_SID_DSS_PKCS 1
|
||||
#define ALG_SID_DSS_DMS 2
|
||||
|
||||
#define ALG_SID_ECDSA 3
|
||||
|
||||
#define ALG_SID_DES 1
|
||||
#define ALG_SID_3DES 3
|
||||
#define ALG_SID_DESX 4
|
||||
|
@ -192,7 +204,6 @@ typedef ULONG_PTR NCRYPT_SECRET_HANDLE;
|
|||
|
||||
#define CALG_ECDH (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_ECDH)
|
||||
#define CALG_ECMQV (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_ECMQV)
|
||||
#define CALG_ECDSA (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA)
|
||||
|
||||
typedef struct _CRYPTOAPI_BLOB
|
||||
{
|
||||
|
@ -594,5 +605,10 @@ BOOL CryptBinaryToStringA(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, L
|
|||
|
||||
#endif
|
||||
|
||||
#ifndef ALG_SID_ECSDA
|
||||
#define ALG_SID_ECDSA 3
|
||||
#define CALG_ECDSA (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA)
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_CRYPTO_H */
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -20,37 +20,23 @@
|
|||
#ifndef WINPR_SSPI_H
|
||||
#define WINPR_SSPI_H
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <wchar.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/windows.h>
|
||||
#include <winpr/security.h>
|
||||
|
||||
#define _NO_KSECDD_IMPORT_ 1
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <tchar.h>
|
||||
#include <winerror.h>
|
||||
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
#define SECURITY_WIN32
|
||||
#include <sspi.h>
|
||||
#include <security.h>
|
||||
#else
|
||||
#define WINPR_SSPI
|
||||
#define SEC_ENTRY __stdcall
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define WINPR_SSPI
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WINPR_SSPI
|
||||
#ifndef _WIN32
|
||||
|
||||
#ifndef SEC_ENTRY
|
||||
#define SEC_ENTRY
|
||||
|
@ -266,7 +252,7 @@ typedef SecPkgInfoW* PSecPkgInfoW;
|
|||
#define SECPKG_ATTR_NEGO_STATUS 32
|
||||
#define SECPKG_ATTR_CONTEXT_DELETED 33
|
||||
|
||||
#ifdef WINPR_SSPI
|
||||
#ifndef _WIN32
|
||||
|
||||
struct _SecPkgContext_AccessToken
|
||||
{
|
||||
|
@ -593,7 +579,7 @@ typedef SecPkgCredentials_NamesW* PSecPkgCredentials_NamesW;
|
|||
#define SEC_WINNT_AUTH_IDENTITY_ANSI 0x1
|
||||
#define SEC_WINNT_AUTH_IDENTITY_UNICODE 0x2
|
||||
|
||||
#ifdef WINPR_SSPI
|
||||
#ifndef _WIN32
|
||||
|
||||
typedef struct _SEC_WINNT_AUTH_IDENTITY_W
|
||||
{
|
||||
|
@ -679,7 +665,7 @@ typedef CtxtHandle* PCtxtHandle;
|
|||
#define SECBUFFER_READONLY_WITH_CHECKSUM 0x10000000
|
||||
#define SECBUFFER_RESERVED 0x60000000
|
||||
|
||||
#ifdef WINPR_SSPI
|
||||
#ifndef _WIN32
|
||||
|
||||
struct _SecBuffer
|
||||
{
|
||||
|
@ -1000,8 +986,7 @@ WINPR_API SECURITY_STATUS SEC_ENTRY VerifySignature(PCtxtHandle phContext, PSecB
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif // WINPR_SSPI
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -1009,14 +994,56 @@ extern "C" {
|
|||
|
||||
/* Custom API */
|
||||
|
||||
#define SECPKG_ATTR_AUTH_IDENTITY 1001
|
||||
#define SECPKG_ATTR_AUTH_PASSWORD 1002
|
||||
#define SECPKG_ATTR_AUTH_NTLM_HASH 1003
|
||||
|
||||
struct _SecPkgContext_AuthIdentity
|
||||
{
|
||||
char User[256 + 1];
|
||||
char Domain[256 + 1];
|
||||
};
|
||||
typedef struct _SecPkgContext_AuthIdentity SecPkgContext_AuthIdentity;
|
||||
|
||||
struct _SecPkgContext_AuthPassword
|
||||
{
|
||||
char Password[256 + 1];
|
||||
};
|
||||
typedef struct _SecPkgContext_AuthPassword SecPkgContext_AuthPassword;
|
||||
|
||||
struct _SecPkgContext_AuthNtlmHash
|
||||
{
|
||||
BYTE NtlmHash[16];
|
||||
};
|
||||
typedef struct _SecPkgContext_AuthNtlmHash SecPkgContext_AuthNtlmHash;
|
||||
|
||||
#define SSPI_INTERFACE_WINPR 0x00000001
|
||||
#define SSPI_INTERFACE_NATIVE 0x00000002
|
||||
|
||||
typedef PSecurityFunctionTableA (SEC_ENTRY * INIT_SECURITY_INTERFACE_EX_A)(DWORD flags);
|
||||
typedef PSecurityFunctionTableW (SEC_ENTRY * INIT_SECURITY_INTERFACE_EX_W)(DWORD flags);
|
||||
|
||||
WINPR_API void sspi_GlobalInit(void);
|
||||
WINPR_API void sspi_GlobalFinish(void);
|
||||
|
||||
WINPR_API void sspi_SecBufferAlloc(PSecBuffer SecBuffer, ULONG size);
|
||||
WINPR_API void* sspi_SecBufferAlloc(PSecBuffer SecBuffer, ULONG size);
|
||||
WINPR_API void sspi_SecBufferFree(PSecBuffer SecBuffer);
|
||||
|
||||
WINPR_API void sspi_SetAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, char* user, char* domain, char* password);
|
||||
WINPR_API void sspi_CopyAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, SEC_WINNT_AUTH_IDENTITY* srcIdentity);
|
||||
WINPR_API int sspi_SetAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, const char* user, const char* domain, const char* password);
|
||||
WINPR_API int sspi_CopyAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, SEC_WINNT_AUTH_IDENTITY* srcIdentity);
|
||||
|
||||
WINPR_API const char* GetSecurityStatusString(SECURITY_STATUS status);
|
||||
|
||||
WINPR_API SecurityFunctionTableW* SEC_ENTRY InitSecurityInterfaceExW(DWORD flags);
|
||||
WINPR_API SecurityFunctionTableA* SEC_ENTRY InitSecurityInterfaceExA(DWORD flags);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define InitSecurityInterfaceEx InitSecurityInterfaceExW
|
||||
#define INIT_SECURITY_INTERFACE_EX INIT_SECURITY_INTERFACE_EX_W
|
||||
#else
|
||||
#define InitSecurityInterfaceEx InitSecurityInterfaceExA
|
||||
#define INIT_SECURITY_INTERFACE_EX INIT_SECURITY_INTERFACE_EX_A
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -214,7 +214,13 @@ WINPR_API BOOL GetVersionExW(LPOSVERSIONINFOW lpVersionInformation);
|
|||
#define GetVersionEx GetVersionExA
|
||||
#endif
|
||||
|
||||
WINPR_API void GetSystemTime(LPSYSTEMTIME lpSystemTime);
|
||||
WINPR_API BOOL SetSystemTime(CONST SYSTEMTIME* lpSystemTime);
|
||||
WINPR_API VOID GetLocalTime(LPSYSTEMTIME lpSystemTime);
|
||||
WINPR_API BOOL SetLocalTime(CONST SYSTEMTIME* lpSystemTime);
|
||||
|
||||
WINPR_API VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime);
|
||||
WINPR_API BOOL GetSystemTimeAdjustment(PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement, PBOOL lpTimeAdjustmentDisabled);
|
||||
|
||||
WINPR_API DWORD GetTickCount(void);
|
||||
|
||||
|
|
|
@ -23,9 +23,71 @@
|
|||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
typedef struct _TIME_ZONE_INFORMATION
|
||||
{
|
||||
LONG Bias;
|
||||
WCHAR StandardName[32];
|
||||
SYSTEMTIME StandardDate;
|
||||
LONG StandardBias;
|
||||
WCHAR DaylightName[32];
|
||||
SYSTEMTIME DaylightDate;
|
||||
LONG DaylightBias;
|
||||
} TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION;
|
||||
|
||||
typedef struct _TIME_DYNAMIC_ZONE_INFORMATION
|
||||
{
|
||||
LONG Bias;
|
||||
WCHAR StandardName[32];
|
||||
SYSTEMTIME StandardDate;
|
||||
LONG StandardBias;
|
||||
WCHAR DaylightName[32];
|
||||
SYSTEMTIME DaylightDate;
|
||||
LONG DaylightBias;
|
||||
WCHAR TimeZoneKeyName[128];
|
||||
BOOLEAN DynamicDaylightTimeDisabled;
|
||||
} DYNAMIC_TIME_ZONE_INFORMATION, *PDYNAMIC_TIME_ZONE_INFORMATION, *LPDYNAMIC_TIME_ZONE_INFORMATION;
|
||||
|
||||
WINPR_API DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation);
|
||||
WINPR_API BOOL SetTimeZoneInformation(const TIME_ZONE_INFORMATION* lpTimeZoneInformation);
|
||||
WINPR_API BOOL SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime, LPFILETIME lpFileTime);
|
||||
WINPR_API BOOL FileTimeToSystemTime(const FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime);
|
||||
WINPR_API BOOL SystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION lpTimeZone,
|
||||
LPSYSTEMTIME lpUniversalTime, LPSYSTEMTIME lpLocalTime);
|
||||
WINPR_API BOOL TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,
|
||||
LPSYSTEMTIME lpLocalTime, LPSYSTEMTIME lpUniversalTime);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* GetDynamicTimeZoneInformation is provided by the SDK if _WIN32_WINNT >= 0x0600 in SDKs above 7.1A
|
||||
* and incorrectly if _WIN32_WINNT >= 0x0501 in older SDKs
|
||||
*/
|
||||
#if !defined(_WIN32) || (defined(_WIN32) && (defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0600 || !defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0501)) /* Windows Vista */
|
||||
|
||||
WINPR_API DWORD GetDynamicTimeZoneInformation(PDYNAMIC_TIME_ZONE_INFORMATION pTimeZoneInformation);
|
||||
WINPR_API BOOL SetDynamicTimeZoneInformation(const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation);
|
||||
WINPR_API BOOL GetTimeZoneInformationForYear(USHORT wYear, PDYNAMIC_TIME_ZONE_INFORMATION pdtzi, LPTIME_ZONE_INFORMATION ptzi);
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0601)) /* Windows 7 */
|
||||
|
||||
WINPR_API BOOL SystemTimeToTzSpecificLocalTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation,
|
||||
const SYSTEMTIME* lpUniversalTime, LPSYSTEMTIME lpLocalTime);
|
||||
WINPR_API BOOL TzSpecificLocalTimeToSystemTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation,
|
||||
const SYSTEMTIME* lpLocalTime, LPSYSTEMTIME lpUniversalTime);
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0602)) /* Windows 8 */
|
||||
|
||||
WINPR_API DWORD EnumDynamicTimeZoneInformation(const DWORD dwIndex, PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation);
|
||||
WINPR_API DWORD GetDynamicTimeZoneInformationEffectiveYears(const PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation,
|
||||
LPDWORD FirstYear, LPDWORD LastYear);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -26,6 +26,36 @@
|
|||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define _accept accept
|
||||
#define _bind bind
|
||||
#define _connect connect
|
||||
#define _ioctlsocket ioctlsocket
|
||||
#define _getpeername getpeername
|
||||
#define _getsockname getsockname
|
||||
#define _getsockopt getsockopt
|
||||
#define _htonl htonl
|
||||
#define _htons htons
|
||||
#define _inet_addr inet_addr
|
||||
#define _inet_ntoa inet_ntoa
|
||||
#define _listen listen
|
||||
#define _ntohl ntohl
|
||||
#define _ntohs ntohs
|
||||
#define _recv recv
|
||||
#define _recvfrom recvfrom
|
||||
#define _select select
|
||||
#define _send send
|
||||
#define _sendto sendto
|
||||
#define _setsockopt setsockopt
|
||||
#define _shutdown shutdown
|
||||
#define _socket socket
|
||||
#define _gethostbyaddr gethostbyaddr
|
||||
#define _gethostbyname gethostbyname
|
||||
#define _gethostname gethostname
|
||||
#define _getservbyport getservbyport
|
||||
#define _getservbyname getservbyname
|
||||
#define _getprotobynumber getprotobynumber
|
||||
#define _getprotobyname getprotobyname
|
||||
|
||||
#if (_WIN32_WINNT < 0x0600)
|
||||
|
||||
PCSTR inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize);
|
||||
|
@ -52,6 +82,12 @@ typedef struct sockaddr_storage SOCKADDR_STORAGE;
|
|||
#define WSADESCRIPTION_LEN 256
|
||||
#define WSASYS_STATUS_LEN 128
|
||||
|
||||
#define SD_RECEIVE 0
|
||||
#define SD_SEND 1
|
||||
#define SD_BOTH 2
|
||||
|
||||
#define SOCKET_ERROR (-1)
|
||||
|
||||
typedef struct WSAData
|
||||
{
|
||||
WORD wVersion;
|
||||
|
|
|
@ -145,6 +145,7 @@ struct _wLogAppender
|
|||
|
||||
#define WLOG_CONSOLE_STDOUT 1
|
||||
#define WLOG_CONSOLE_STDERR 2
|
||||
#define WLOG_CONSOLE_DEBUG 3
|
||||
|
||||
struct _wLogConsoleAppender
|
||||
{
|
||||
|
@ -176,6 +177,18 @@ struct _wLogBinaryAppender
|
|||
};
|
||||
typedef struct _wLogBinaryAppender wLogBinaryAppender;
|
||||
|
||||
/**
|
||||
* Filter
|
||||
*/
|
||||
|
||||
struct _wLogFilter
|
||||
{
|
||||
DWORD Level;
|
||||
LPSTR* Names;
|
||||
DWORD NameCount;
|
||||
};
|
||||
typedef struct _wLogFilter wLogFilter;
|
||||
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <wctype.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
|
@ -303,7 +304,15 @@ int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
|
|||
allocate = TRUE;
|
||||
|
||||
if (allocate)
|
||||
*lpWideCharStr = (LPWSTR) malloc(cchWideChar * sizeof(WCHAR));
|
||||
{
|
||||
*lpWideCharStr = (LPWSTR) calloc(cchWideChar, sizeof(WCHAR));
|
||||
|
||||
if (!(*lpWideCharStr))
|
||||
{
|
||||
//SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
status = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, *lpWideCharStr, cchWideChar);
|
||||
|
||||
|
@ -342,15 +351,22 @@ int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int
|
|||
|
||||
if (allocate)
|
||||
{
|
||||
*lpMultiByteStr = (LPSTR) malloc(cbMultiByte + 1);
|
||||
ZeroMemory(*lpMultiByteStr, cbMultiByte + 1);
|
||||
*lpMultiByteStr = (LPSTR) calloc(1, cbMultiByte + 1);
|
||||
|
||||
if (!(*lpMultiByteStr))
|
||||
{
|
||||
//SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
status = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar,
|
||||
*lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
|
||||
|
||||
if (status != cbMultiByte)
|
||||
if ((status != cbMultiByte) && allocate)
|
||||
{
|
||||
status = 0;
|
||||
}
|
||||
|
||||
if ((status <= 0) && allocate)
|
||||
{
|
||||
|
|
|
@ -234,7 +234,7 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|||
|
||||
free(name);
|
||||
|
||||
pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE));
|
||||
pNamedPipe = (WINPR_NAMED_PIPE*) calloc(1, sizeof(WINPR_NAMED_PIPE));
|
||||
hNamedPipe = (HANDLE) pNamedPipe;
|
||||
|
||||
WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE);
|
||||
|
@ -361,8 +361,6 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
|||
|
||||
if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
|
||||
{
|
||||
io_status = nNumberOfBytesToRead;
|
||||
|
||||
if (pipe->clientfd == -1)
|
||||
return FALSE;
|
||||
|
||||
|
@ -374,9 +372,9 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
|||
{
|
||||
case ECONNRESET:
|
||||
SetLastError(ERROR_BROKEN_PIPE);
|
||||
io_status = 0;
|
||||
break;
|
||||
}
|
||||
status = FALSE;
|
||||
}
|
||||
else if (io_status < 0)
|
||||
{
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "../handle/handle.h"
|
||||
|
||||
BOOL CloseHandle(HANDLE hObject)
|
||||
|
@ -163,30 +165,24 @@ BOOL CloseHandle(HANDLE hObject)
|
|||
}
|
||||
else if (Type == HANDLE_TYPE_NAMED_PIPE)
|
||||
{
|
||||
WINPR_NAMED_PIPE* pipe;
|
||||
WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*) Object;
|
||||
|
||||
pipe = (WINPR_NAMED_PIPE*) Object;
|
||||
|
||||
if (--pipe->dwRefCount == 0)
|
||||
{
|
||||
pipe->pfnRemoveBaseNamedPipeFromList(pipe);
|
||||
|
||||
if (pipe->pBaseNamedPipe)
|
||||
{
|
||||
CloseHandle((HANDLE) pipe->pBaseNamedPipe);
|
||||
}
|
||||
|
||||
if (pipe->clientfd != -1)
|
||||
close(pipe->clientfd);
|
||||
|
||||
if (pipe->serverfd != -1)
|
||||
close(pipe->serverfd);
|
||||
|
||||
free((char *)pipe->lpFileName);
|
||||
free((char *)pipe->lpFilePath);
|
||||
free((char *)pipe->name);
|
||||
free(pipe);
|
||||
if (pNamedPipe->clientfd != -1) {
|
||||
//fprintf(stderr, "%s: closing clientfd %d\n", __FUNCTION__, pNamedPipe->clientfd);
|
||||
close(pNamedPipe->clientfd);
|
||||
}
|
||||
if (pNamedPipe->serverfd != -1) {
|
||||
//fprintf(stderr, "%s: closing serverfd %d\n", __FUNCTION__, pNamedPipe->serverfd);
|
||||
close(pNamedPipe->serverfd);
|
||||
}
|
||||
|
||||
if (pNamedPipe->pfnUnrefNamedPipe)
|
||||
pNamedPipe->pfnUnrefNamedPipe(pNamedPipe);
|
||||
|
||||
free((void*)pNamedPipe->lpFileName);
|
||||
free((void*)pNamedPipe->lpFilePath);
|
||||
free((void*)pNamedPipe->name);
|
||||
free(pNamedPipe);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define WINPR_HANDLE_PRIVATE_H
|
||||
|
||||
#include <winpr/handle.h>
|
||||
#include <winpr/file.h>
|
||||
|
||||
#define HANDLE_TYPE_NONE 0
|
||||
#define HANDLE_TYPE_PROCESS 1
|
||||
|
@ -52,7 +53,7 @@ static inline BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObj
|
|||
{
|
||||
WINPR_HANDLE* wHandle;
|
||||
|
||||
if (handle == NULL)
|
||||
if (handle == NULL || handle == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
wHandle = (WINPR_HANDLE*) handle;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "pipe.h"
|
||||
|
||||
|
@ -48,34 +49,32 @@
|
|||
* Since the WinPR implementation of named pipes makes use of UNIX domain
|
||||
* sockets, it is not possible to bind the same name more than once (i.e.,
|
||||
* SO_REUSEADDR does not work with UNIX domain sockets). As a result, the
|
||||
* first call to CreateNamedPipe must create the UNIX domain socket and
|
||||
* subsequent calls to CreateNamedPipe will reference the first named pipe
|
||||
* handle and duplicate the socket descriptor.
|
||||
* first call to CreateNamedPipe with name n creates a "shared" UNIX domain
|
||||
* socket descriptor that gets duplicated via dup() for the first and all
|
||||
* subsequent calls to CreateNamedPipe with name n.
|
||||
*
|
||||
* The following array keeps track of the named pipe handles for the first
|
||||
* instance. If multiple instances are created, subsequent instances store
|
||||
* a pointer to the first instance and a reference count is maintained. When
|
||||
* the last instance is closed, the named pipe handle is removed from the list.
|
||||
* The following array keeps track of the references to the shared socked
|
||||
* descriptors. If an entry's reference count is zero the base socket
|
||||
* descriptor gets closed and the entry is removed from the list.
|
||||
*/
|
||||
|
||||
static wArrayList* g_BaseNamedPipeList = NULL;
|
||||
static wArrayList* g_NamedPipeServerSockets = NULL;
|
||||
|
||||
static BOOL g_Initialized = FALSE;
|
||||
typedef struct _NamedPipeServerSocketEntry
|
||||
{
|
||||
char* name;
|
||||
int serverfd;
|
||||
int references;
|
||||
} NamedPipeServerSocketEntry;
|
||||
|
||||
static void InitWinPRPipeModule()
|
||||
{
|
||||
if (g_Initialized)
|
||||
if (g_NamedPipeServerSockets)
|
||||
return;
|
||||
|
||||
g_BaseNamedPipeList = ArrayList_New(TRUE);
|
||||
|
||||
g_Initialized = TRUE;
|
||||
g_NamedPipeServerSockets = ArrayList_New(FALSE);
|
||||
}
|
||||
|
||||
void WinPR_RemoveBaseNamedPipeFromList(WINPR_NAMED_PIPE* pNamedPipe)
|
||||
{
|
||||
ArrayList_Remove(g_BaseNamedPipeList, pNamedPipe);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unnamed pipe
|
||||
|
@ -126,48 +125,70 @@ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpP
|
|||
* Named pipe
|
||||
*/
|
||||
|
||||
static void winpr_unref_named_pipe(WINPR_NAMED_PIPE* pNamedPipe)
|
||||
{
|
||||
int index;
|
||||
NamedPipeServerSocketEntry *baseSocket;
|
||||
|
||||
if (!pNamedPipe)
|
||||
return;
|
||||
|
||||
assert(pNamedPipe->name);
|
||||
assert(g_NamedPipeServerSockets);
|
||||
|
||||
//fprintf(stderr, "%s: %p (%s)\n", __FUNCTION__, pNamedPipe, pNamedPipe->name);
|
||||
|
||||
ArrayList_Lock(g_NamedPipeServerSockets);
|
||||
for (index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
|
||||
{
|
||||
baseSocket = (NamedPipeServerSocketEntry*) ArrayList_GetItem(
|
||||
g_NamedPipeServerSockets, index);
|
||||
assert(baseSocket->name);
|
||||
if (!strcmp(baseSocket->name, pNamedPipe->name))
|
||||
{
|
||||
assert(baseSocket->references > 0);
|
||||
assert(baseSocket->serverfd != -1);
|
||||
if (--baseSocket->references == 0)
|
||||
{
|
||||
//fprintf(stderr, "%s: removing shared server socked resource\n", __FUNCTION__);
|
||||
//fprintf(stderr, "%s: closing shared serverfd %d\n", __FUNCTION__, baseSocket->serverfd);
|
||||
ArrayList_Remove(g_NamedPipeServerSockets, baseSocket);
|
||||
close(baseSocket->serverfd);
|
||||
free(baseSocket->name);
|
||||
free(baseSocket);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ArrayList_Unlock(g_NamedPipeServerSockets);
|
||||
}
|
||||
|
||||
HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
|
||||
DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
||||
{
|
||||
int index;
|
||||
int status;
|
||||
HANDLE hNamedPipe;
|
||||
HANDLE hNamedPipe = INVALID_HANDLE_VALUE;
|
||||
char* lpPipePath;
|
||||
struct sockaddr_un s;
|
||||
WINPR_NAMED_PIPE* pNamedPipe;
|
||||
WINPR_NAMED_PIPE* pBaseNamedPipe;
|
||||
WINPR_NAMED_PIPE* pNamedPipe = NULL;
|
||||
int serverfd = -1;
|
||||
NamedPipeServerSocketEntry *baseSocket = NULL;
|
||||
|
||||
if (!lpName)
|
||||
return INVALID_HANDLE_VALUE;
|
||||
|
||||
InitWinPRPipeModule();
|
||||
|
||||
/* Find the base named pipe instance (i.e., the first instance). */
|
||||
pBaseNamedPipe = NULL;
|
||||
|
||||
ArrayList_Lock(g_BaseNamedPipeList);
|
||||
|
||||
for (index = 0; index < ArrayList_Count(g_BaseNamedPipeList); index++)
|
||||
{
|
||||
WINPR_NAMED_PIPE* p = (WINPR_NAMED_PIPE*) ArrayList_GetItem(g_BaseNamedPipeList, index);
|
||||
|
||||
if (strcmp(p->name, lpName) == 0)
|
||||
{
|
||||
pBaseNamedPipe = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList_Unlock(g_BaseNamedPipeList);
|
||||
|
||||
pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE));
|
||||
hNamedPipe = (HANDLE) pNamedPipe;
|
||||
pNamedPipe = (WINPR_NAMED_PIPE*) calloc(1, sizeof(WINPR_NAMED_PIPE));
|
||||
|
||||
WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE);
|
||||
|
||||
pNamedPipe->pfnRemoveBaseNamedPipeFromList = WinPR_RemoveBaseNamedPipeFromList;
|
||||
|
||||
pNamedPipe->name = _strdup(lpName);
|
||||
if (!(pNamedPipe->name = _strdup(lpName)))
|
||||
goto out;
|
||||
if (!(pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName)))
|
||||
goto out;
|
||||
if (!(pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName)))
|
||||
goto out;
|
||||
pNamedPipe->dwOpenMode = dwOpenMode;
|
||||
pNamedPipe->dwPipeMode = dwPipeMode;
|
||||
pNamedPipe->nMaxInstances = nMaxInstances;
|
||||
|
@ -176,20 +197,29 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD
|
|||
pNamedPipe->nDefaultTimeOut = nDefaultTimeOut;
|
||||
pNamedPipe->dwFlagsAndAttributes = dwOpenMode;
|
||||
|
||||
pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
|
||||
pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName);
|
||||
|
||||
pNamedPipe->clientfd = -1;
|
||||
pNamedPipe->ServerMode = TRUE;
|
||||
|
||||
pNamedPipe->pBaseNamedPipe = pBaseNamedPipe;
|
||||
pNamedPipe->dwRefCount = 1;
|
||||
ArrayList_Lock(g_NamedPipeServerSockets);
|
||||
|
||||
for (index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
|
||||
{
|
||||
baseSocket = (NamedPipeServerSocketEntry*) ArrayList_GetItem(
|
||||
g_NamedPipeServerSockets, index);
|
||||
if (!strcmp(baseSocket->name, lpName))
|
||||
{
|
||||
serverfd = baseSocket->serverfd;
|
||||
//fprintf(stderr, "using shared socked resource for pipe %p (%s)\n", pNamedPipe, lpName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is the first instance of the named pipe... */
|
||||
if (pBaseNamedPipe == NULL)
|
||||
if (serverfd == -1)
|
||||
{
|
||||
/* Create the UNIX domain socket and start listening. */
|
||||
lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
|
||||
if (!(lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA()))
|
||||
goto out;
|
||||
|
||||
if (!PathFileExistsA(lpPipePath))
|
||||
{
|
||||
|
@ -204,48 +234,49 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD
|
|||
DeleteFileA(pNamedPipe->lpFilePath);
|
||||
}
|
||||
|
||||
pNamedPipe->serverfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (pNamedPipe->serverfd == -1)
|
||||
if ((serverfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||
{
|
||||
fprintf(stderr, "CreateNamedPipeA: socket error, %s\n", strerror(errno));
|
||||
goto err_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ZeroMemory(&s, sizeof(struct sockaddr_un));
|
||||
s.sun_family = AF_UNIX;
|
||||
strcpy(s.sun_path, pNamedPipe->lpFilePath);
|
||||
|
||||
status = bind(pNamedPipe->serverfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un));
|
||||
|
||||
if (status != 0)
|
||||
if (bind(serverfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)) == -1)
|
||||
{
|
||||
fprintf(stderr, "CreateNamedPipeA: bind error, %s\n", strerror(errno));
|
||||
goto err_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = listen(pNamedPipe->serverfd, 2);
|
||||
|
||||
if (status != 0)
|
||||
if (listen(serverfd, 2) == -1)
|
||||
{
|
||||
fprintf(stderr, "CreateNamedPipeA: listen error, %s\n", strerror(errno));
|
||||
goto err_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
|
||||
|
||||
/* Add the named pipe to the list of base named pipe instances. */
|
||||
ArrayList_Add(g_BaseNamedPipeList, pNamedPipe);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Duplicate the file handle for the UNIX domain socket in the first instance. */
|
||||
pNamedPipe->serverfd = dup(pBaseNamedPipe->serverfd);
|
||||
if (!(baseSocket = (NamedPipeServerSocketEntry *) malloc(sizeof(NamedPipeServerSocketEntry))))
|
||||
goto out;
|
||||
if (!(baseSocket->name = _strdup(lpName)))
|
||||
{
|
||||
free(baseSocket);
|
||||
goto out;
|
||||
}
|
||||
baseSocket->serverfd = serverfd;
|
||||
baseSocket->references = 0;
|
||||
ArrayList_Add(g_NamedPipeServerSockets, baseSocket);
|
||||
//fprintf(stderr, "created shared socked resource for pipe %p (%s). base serverfd = %d\n", pNamedPipe, lpName, serverfd);
|
||||
|
||||
/* Update the reference count in the base named pipe instance. */
|
||||
pBaseNamedPipe->dwRefCount++;
|
||||
}
|
||||
|
||||
pNamedPipe->serverfd = dup(baseSocket->serverfd);
|
||||
//fprintf(stderr, "using serverfd %d (duplicated from %d)\n", pNamedPipe->serverfd, baseSocket->serverfd);
|
||||
pNamedPipe->pfnUnrefNamedPipe = winpr_unref_named_pipe;
|
||||
baseSocket->references++;
|
||||
|
||||
if (dwOpenMode & FILE_FLAG_OVERLAPPED)
|
||||
{
|
||||
#if 0
|
||||
|
@ -256,15 +287,23 @@ HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD
|
|||
#endif
|
||||
}
|
||||
|
||||
return hNamedPipe;
|
||||
hNamedPipe = (HANDLE) pNamedPipe;
|
||||
|
||||
err_out:
|
||||
if (pNamedPipe) {
|
||||
if (pNamedPipe->serverfd != -1)
|
||||
close(pNamedPipe->serverfd);
|
||||
free(pNamedPipe);
|
||||
out:
|
||||
if (hNamedPipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (pNamedPipe)
|
||||
{
|
||||
free((void*)pNamedPipe->name);
|
||||
free((void*)pNamedPipe->lpFileName);
|
||||
free((void*)pNamedPipe->lpFilePath);
|
||||
free(pNamedPipe);
|
||||
}
|
||||
if (serverfd != -1)
|
||||
close(serverfd);
|
||||
}
|
||||
return INVALID_HANDLE_VALUE;
|
||||
ArrayList_Unlock(g_NamedPipeServerSockets);
|
||||
return hNamedPipe;
|
||||
}
|
||||
|
||||
HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "../handle/handle.h"
|
||||
|
||||
|
||||
struct winpr_pipe
|
||||
{
|
||||
WINPR_HANDLE_DEF();
|
||||
|
@ -37,16 +38,12 @@ typedef struct winpr_pipe WINPR_PIPE;
|
|||
|
||||
typedef struct winpr_named_pipe WINPR_NAMED_PIPE;
|
||||
|
||||
typedef void ( * fnRemoveBaseNamedPipeFromList)(WINPR_NAMED_PIPE* pNamedPipe);
|
||||
typedef void(*fnUnrefNamedPipe)(WINPR_NAMED_PIPE* pNamedPipe);
|
||||
|
||||
struct winpr_named_pipe
|
||||
{
|
||||
WINPR_HANDLE_DEF();
|
||||
|
||||
WINPR_NAMED_PIPE* pBaseNamedPipe;
|
||||
|
||||
DWORD dwRefCount;
|
||||
|
||||
int clientfd;
|
||||
int serverfd;
|
||||
|
||||
|
@ -64,9 +61,11 @@ struct winpr_named_pipe
|
|||
DWORD dwFlagsAndAttributes;
|
||||
LPOVERLAPPED lpOverlapped;
|
||||
|
||||
fnRemoveBaseNamedPipeFromList pfnRemoveBaseNamedPipeFromList;
|
||||
fnUnrefNamedPipe pfnUnrefNamedPipe;
|
||||
};
|
||||
|
||||
BOOL winpr_destroy_named_pipe(WINPR_NAMED_PIPE* pNamedPipe);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_PIPE_PRIVATE_H */
|
||||
|
|
|
@ -8,18 +8,25 @@
|
|||
#include <winpr/print.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#ifndef _WIN32
|
||||
#include <signal.h>
|
||||
#endif
|
||||
#include "../pipe.h"
|
||||
|
||||
#define PIPE_BUFFER_SIZE 32
|
||||
|
||||
static HANDLE ReadyEvent;
|
||||
|
||||
static LPTSTR lpszPipeName = _T("\\\\.\\pipe\\winpr_test_pipe");
|
||||
static LPTSTR lpszPipeNameMt = _T("\\\\.\\pipe\\winpr_test_pipe_mt");
|
||||
static LPTSTR lpszPipeNameSt = _T("\\\\.\\pipe\\winpr_test_pipe_st");
|
||||
|
||||
BOOL testFailed = FALSE;
|
||||
|
||||
static void* named_pipe_client_thread(void* arg)
|
||||
{
|
||||
HANDLE hNamedPipe;
|
||||
BYTE* lpReadBuffer;
|
||||
BYTE* lpWriteBuffer;
|
||||
HANDLE hNamedPipe = NULL;
|
||||
BYTE* lpReadBuffer = NULL;
|
||||
BYTE* lpWriteBuffer = NULL;
|
||||
BOOL fSuccess = FALSE;
|
||||
DWORD nNumberOfBytesToRead;
|
||||
DWORD nNumberOfBytesToWrite;
|
||||
|
@ -28,39 +35,42 @@ static void* named_pipe_client_thread(void* arg)
|
|||
|
||||
WaitForSingleObject(ReadyEvent, INFINITE);
|
||||
|
||||
hNamedPipe = CreateFile(lpszPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
hNamedPipe = CreateFile(lpszPipeNameMt, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if (!hNamedPipe)
|
||||
{
|
||||
printf("Named Pipe CreateFile failure: NULL handle\n");
|
||||
return NULL;
|
||||
printf("%s:Named Pipe CreateFile failure: NULL handle\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hNamedPipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
printf("Named Pipe CreateFile failure: INVALID_HANDLE_VALUE\n");
|
||||
return NULL;
|
||||
printf("%s: Named Pipe CreateFile failure: INVALID_HANDLE_VALUE\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE);
|
||||
lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE);
|
||||
if (!(lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE)))
|
||||
{
|
||||
printf("%s: Error allocating read buffer\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE)))
|
||||
{
|
||||
printf("%s: Error allocating write buffer\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lpNumberOfBytesWritten = 0;
|
||||
nNumberOfBytesToWrite = PIPE_BUFFER_SIZE;
|
||||
|
||||
FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x59);
|
||||
|
||||
fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL);
|
||||
|
||||
if (!fSuccess || (lpNumberOfBytesWritten == 0))
|
||||
if (!WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL) ||
|
||||
lpNumberOfBytesWritten != nNumberOfBytesToWrite)
|
||||
{
|
||||
printf("Client NamedPipe WriteFile failure\n");
|
||||
|
||||
free(lpReadBuffer);
|
||||
free(lpWriteBuffer);
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
return NULL;
|
||||
printf("%s: Client NamedPipe WriteFile failure\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lpNumberOfBytesRead = 0;
|
||||
|
@ -68,34 +78,31 @@ static void* named_pipe_client_thread(void* arg)
|
|||
|
||||
ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE);
|
||||
|
||||
fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL);
|
||||
|
||||
if (!fSuccess || (lpNumberOfBytesRead == 0))
|
||||
if (!ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL) ||
|
||||
lpNumberOfBytesRead != nNumberOfBytesToRead)
|
||||
{
|
||||
printf("Client NamedPipe ReadFile failure\n");
|
||||
free(lpReadBuffer);
|
||||
free(lpWriteBuffer);
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
return NULL;
|
||||
printf("%s: Client NamedPipe ReadFile failure\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Client ReadFile (%d):\n", lpNumberOfBytesRead);
|
||||
winpr_HexDump(lpReadBuffer, lpNumberOfBytesRead);
|
||||
fSuccess = TRUE;
|
||||
|
||||
out:
|
||||
free(lpReadBuffer);
|
||||
free(lpWriteBuffer);
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
|
||||
if (!fSuccess)
|
||||
testFailed = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void* named_pipe_server_thread(void* arg)
|
||||
{
|
||||
HANDLE hNamedPipe;
|
||||
BYTE* lpReadBuffer;
|
||||
BYTE* lpWriteBuffer;
|
||||
HANDLE hNamedPipe = NULL;
|
||||
BYTE* lpReadBuffer = NULL;
|
||||
BYTE* lpWriteBuffer = NULL;
|
||||
BOOL fSuccess = FALSE;
|
||||
BOOL fConnected = FALSE;
|
||||
DWORD nNumberOfBytesToRead;
|
||||
|
@ -103,20 +110,20 @@ static void* named_pipe_server_thread(void* arg)
|
|||
DWORD lpNumberOfBytesRead;
|
||||
DWORD lpNumberOfBytesWritten;
|
||||
|
||||
hNamedPipe = CreateNamedPipe(lpszPipeName,
|
||||
hNamedPipe = CreateNamedPipe(lpszPipeNameMt,
|
||||
PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL);
|
||||
|
||||
if (!hNamedPipe)
|
||||
{
|
||||
printf("CreateNamedPipe failure: NULL handle\n");
|
||||
return NULL;
|
||||
printf("%s: CreateNamedPipe failure: NULL handle\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hNamedPipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
printf("CreateNamedPipe failure: INVALID_HANDLE_VALUE\n");
|
||||
return NULL;
|
||||
printf("%s: CreateNamedPipe failure: INVALID_HANDLE_VALUE\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
SetEvent(ReadyEvent);
|
||||
|
@ -128,30 +135,32 @@ static void* named_pipe_server_thread(void* arg)
|
|||
|
||||
if (!fConnected)
|
||||
{
|
||||
printf("ConnectNamedPipe failure\n");
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
return NULL;
|
||||
printf("%s: ConnectNamedPipe failure\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE);
|
||||
lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE);
|
||||
if (!(lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE)))
|
||||
{
|
||||
printf("%s: Error allocating read buffer\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE)))
|
||||
{
|
||||
printf("%s: Error allocating write buffer\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lpNumberOfBytesRead = 0;
|
||||
nNumberOfBytesToRead = PIPE_BUFFER_SIZE;
|
||||
|
||||
ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE);
|
||||
|
||||
fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL);
|
||||
|
||||
if (!fSuccess || (lpNumberOfBytesRead == 0))
|
||||
if (!ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL) ||
|
||||
lpNumberOfBytesRead != nNumberOfBytesToRead)
|
||||
{
|
||||
printf("Server NamedPipe ReadFile failure\n");
|
||||
free(lpReadBuffer);
|
||||
free(lpWriteBuffer);
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
return NULL;
|
||||
printf("%s: Server NamedPipe ReadFile failure\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Server ReadFile (%d):\n", lpNumberOfBytesRead);
|
||||
|
@ -162,42 +171,307 @@ static void* named_pipe_server_thread(void* arg)
|
|||
|
||||
FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x45);
|
||||
|
||||
fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL);
|
||||
|
||||
if (!fSuccess || (lpNumberOfBytesWritten == 0))
|
||||
if (!WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL) ||
|
||||
lpNumberOfBytesWritten != nNumberOfBytesToWrite)
|
||||
{
|
||||
printf("Server NamedPipe WriteFile failure\n");
|
||||
free(lpReadBuffer);
|
||||
free(lpWriteBuffer);
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
return NULL;
|
||||
printf("%s: Server NamedPipe WriteFile failure\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
fSuccess = TRUE;
|
||||
|
||||
out:
|
||||
free(lpReadBuffer);
|
||||
free(lpWriteBuffer);
|
||||
|
||||
CloseHandle(hNamedPipe);
|
||||
|
||||
if (!fSuccess)
|
||||
testFailed = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define TESTNUMPIPESST 16
|
||||
static void* named_pipe_single_thread(void* arg)
|
||||
{
|
||||
HANDLE servers[TESTNUMPIPESST];
|
||||
HANDLE clients[TESTNUMPIPESST];
|
||||
char sndbuf[PIPE_BUFFER_SIZE];
|
||||
char rcvbuf[PIPE_BUFFER_SIZE];
|
||||
DWORD dwRead;
|
||||
DWORD dwWritten;
|
||||
int i;
|
||||
int numPipes;
|
||||
BOOL bSuccess = FALSE;
|
||||
#ifndef _WIN32
|
||||
WINPR_NAMED_PIPE* p;
|
||||
#endif
|
||||
|
||||
numPipes = TESTNUMPIPESST;
|
||||
|
||||
memset(servers, 0, sizeof(servers));
|
||||
memset(clients, 0, sizeof(clients));
|
||||
|
||||
WaitForSingleObject(ReadyEvent, INFINITE);
|
||||
|
||||
for (i = 0; i < numPipes; i++)
|
||||
{
|
||||
if (!(servers[i] = CreateNamedPipe(lpszPipeNameSt,
|
||||
PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL)))
|
||||
{
|
||||
printf("%s: CreateNamedPipe #%d failed\n", __FUNCTION__, i);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
for (i = 0; i < numPipes; i++)
|
||||
{
|
||||
p = (WINPR_NAMED_PIPE*)servers[i];
|
||||
|
||||
if (strcmp(lpszPipeNameSt, p->name))
|
||||
{
|
||||
printf("%s: Pipe name mismatch for pipe #%d ([%s] instead of [%s])\n",
|
||||
__FUNCTION__, i, p->name, lpszPipeNameSt);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (p->clientfd != -1)
|
||||
{
|
||||
printf("%s: Unexpected client fd value for pipe #%d (%d instead of -1)\n",
|
||||
__FUNCTION__, i, p->clientfd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (p->serverfd < 1)
|
||||
{
|
||||
printf("%s: Unexpected server fd value for pipe #%d (%d is not > 0)\n",
|
||||
__FUNCTION__, i, p->serverfd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (p->ServerMode == FALSE)
|
||||
{
|
||||
printf("%s: Unexpected ServerMode value for pipe #%d (0 instead of 1)\n",
|
||||
__FUNCTION__, i);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < numPipes; i++)
|
||||
{
|
||||
if (!(clients[i] = CreateFile(lpszPipeNameSt, GENERIC_READ | GENERIC_WRITE,
|
||||
0, NULL, OPEN_EXISTING, 0, NULL)))
|
||||
{
|
||||
printf("%s: CreateFile #%d failed\n", __FUNCTION__, i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ConnectNamedPipe(servers[i], NULL))
|
||||
{
|
||||
printf("%s: ConnectNamedPipe #%d failed\n", __FUNCTION__, i);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
for (i = 0; i < numPipes; i++)
|
||||
{
|
||||
p = servers[i];
|
||||
|
||||
if (p->clientfd < 1)
|
||||
{
|
||||
printf("%s: Unexpected client fd value for pipe #%d (%d is not > 0)\n",
|
||||
__FUNCTION__, i, p->clientfd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (p->ServerMode)
|
||||
{
|
||||
printf("%s: Unexpected ServerMode value for pipe #%d (1 instead of 0)\n",
|
||||
__FUNCTION__, i);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < numPipes; i++)
|
||||
{
|
||||
/* Test writing from clients to servers */
|
||||
|
||||
ZeroMemory(sndbuf, sizeof(sndbuf));
|
||||
ZeroMemory(rcvbuf, sizeof(rcvbuf));
|
||||
sprintf_s(sndbuf, sizeof(sndbuf), "CLIENT->SERVER ON PIPE #%05d", i);
|
||||
|
||||
p = servers[i];
|
||||
|
||||
if (!WriteFile(clients[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL) ||
|
||||
dwWritten != sizeof(sndbuf))
|
||||
{
|
||||
printf("%s: Error writing to client end of pipe #%d\n", __FUNCTION__, i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ReadFile(servers[i], rcvbuf, dwWritten, &dwRead, NULL) ||
|
||||
dwRead != dwWritten)
|
||||
{
|
||||
printf("%s: Error reading on server end of pipe #%d\n", __FUNCTION__, i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memcmp(sndbuf, rcvbuf, sizeof(sndbuf)))
|
||||
{
|
||||
printf("%s: Error data read on server end of pipe #%d is corrupted\n",
|
||||
__FUNCTION__, i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Test writing from servers to clients */
|
||||
|
||||
ZeroMemory(sndbuf, sizeof(sndbuf));
|
||||
ZeroMemory(rcvbuf, sizeof(rcvbuf));
|
||||
sprintf_s(sndbuf, sizeof(sndbuf), "SERVER->CLIENT ON PIPE #%05d", i);
|
||||
|
||||
p = servers[i];
|
||||
if (!WriteFile(servers[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL) ||
|
||||
dwWritten != sizeof(sndbuf))
|
||||
{
|
||||
printf("%s: Error writing to server end of pipe #%d\n", __FUNCTION__, i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ReadFile(clients[i], rcvbuf, dwWritten, &dwRead, NULL) ||
|
||||
dwRead != dwWritten)
|
||||
{
|
||||
printf("%s: Error reading on client end of pipe #%d\n", __FUNCTION__, i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memcmp(sndbuf, rcvbuf, sizeof(sndbuf)))
|
||||
{
|
||||
printf("%s: Error data read on client end of pipe #%d is corrupted\n",
|
||||
__FUNCTION__, i);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* After DisconnectNamedPipe on server end
|
||||
* ReadFile/WriteFile must fail on client end
|
||||
*/
|
||||
i = numPipes - 1;
|
||||
|
||||
DisconnectNamedPipe(servers[i]);
|
||||
|
||||
if (ReadFile(clients[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL))
|
||||
{
|
||||
printf("%s: Error ReadFile on client should have failed after DisconnectNamedPipe on server\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (WriteFile(clients[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL))
|
||||
{
|
||||
printf("%s: Error WriteFile on client end should have failed after DisconnectNamedPipe on server\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
CloseHandle(servers[i]);
|
||||
CloseHandle(clients[i]);
|
||||
|
||||
numPipes--;
|
||||
|
||||
|
||||
/**
|
||||
* After CloseHandle (without calling DisconnectNamedPipe first) on server end
|
||||
* ReadFile/WriteFile must fail on client end
|
||||
*/
|
||||
i = numPipes - 1;
|
||||
|
||||
CloseHandle(servers[i]);
|
||||
|
||||
if (ReadFile(clients[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL))
|
||||
{
|
||||
printf("%s: Error ReadFile on client end should have failed after CloseHandle on server\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (WriteFile(clients[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL))
|
||||
{
|
||||
printf("%s: Error WriteFile on client end should have failed after CloseHandle on server\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
CloseHandle(clients[i]);
|
||||
|
||||
numPipes--;
|
||||
|
||||
|
||||
/**
|
||||
* After CloseHandle on client end
|
||||
* ReadFile/WriteFile must fail on server end
|
||||
*/
|
||||
i = numPipes - 1;
|
||||
|
||||
CloseHandle(clients[i]);
|
||||
|
||||
if (ReadFile(servers[i], rcvbuf, sizeof(rcvbuf), &dwRead, NULL))
|
||||
{
|
||||
printf("%s: Error ReadFile on server end should have failed after CloseHandle on client\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (WriteFile(clients[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL))
|
||||
{
|
||||
printf("%s: Error WriteFile on server end should have failed after CloseHandle on client\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
DisconnectNamedPipe(servers[i]);
|
||||
CloseHandle(servers[i]);
|
||||
|
||||
numPipes--;
|
||||
|
||||
/* Close all remaining pipes */
|
||||
for (i = 0; i < numPipes; i++)
|
||||
{
|
||||
DisconnectNamedPipe(servers[i]);
|
||||
CloseHandle(servers[i]);
|
||||
CloseHandle(clients[i]);
|
||||
}
|
||||
numPipes = 0;
|
||||
|
||||
bSuccess = TRUE;
|
||||
|
||||
out:
|
||||
if (!bSuccess)
|
||||
testFailed = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int TestPipeCreateNamedPipe(int argc, char* argv[])
|
||||
{
|
||||
HANDLE SingleThread;
|
||||
HANDLE ClientThread;
|
||||
HANDLE ServerThread;
|
||||
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
ReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
SingleThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_single_thread, NULL, 0, NULL);
|
||||
ClientThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_client_thread, NULL, 0, NULL);
|
||||
ServerThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_server_thread, NULL, 0, NULL);
|
||||
|
||||
WaitForSingleObject(SingleThread, INFINITE);
|
||||
WaitForSingleObject(ClientThread, INFINITE);
|
||||
WaitForSingleObject(ServerThread, INFINITE);
|
||||
|
||||
CloseHandle(SingleThread);
|
||||
CloseHandle(ClientThread);
|
||||
CloseHandle(ServerThread);
|
||||
|
||||
return 0;
|
||||
return testFailed;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,12 +22,18 @@ if(PCSC_WINPR_FOUND)
|
|||
add_definitions(-DWITH_WINPR_PCSC)
|
||||
endif()
|
||||
|
||||
if(WITH_SMARTCARD_INSPECT)
|
||||
add_definitions(-DWITH_SMARTCARD_INSPECT)
|
||||
endif()
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
smartcard.c
|
||||
smartcard.h
|
||||
smartcard_link.c
|
||||
smartcard_pcsc.c
|
||||
smartcard_pcsc.h)
|
||||
smartcard_pcsc.h
|
||||
smartcard_inspect.c
|
||||
smartcard_inspect.h)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND ${MODULE_PREFIX}_SRCS
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#include "smartcard.h"
|
||||
|
||||
#include "smartcard_inspect.h"
|
||||
|
||||
static BOOL g_Initialized = FALSE;
|
||||
static PSCardApiFunctionTable g_SCardApi = NULL;
|
||||
|
||||
|
@ -1010,4 +1012,8 @@ void InitializeSCardApiStubs(void)
|
|||
g_SCardApi = WinSCard_GetSCardApiFunctionTable();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_SMARTCARD_INSPECT
|
||||
g_SCardApi = Inspect_RegisterSCardApi(g_SCardApi);
|
||||
#endif
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,8 @@
|
|||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* config.h definitions for installable headers
|
||||
* Smart Card API
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,16 +17,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_CONFIG_H
|
||||
#define WINPR_CONFIG_H
|
||||
#ifndef WINPR_SMARTCARD_INSPECT_PRIVATE_H
|
||||
#define WINPR_SMARTCARD_INSPECT_PRIVATE_H
|
||||
|
||||
/*
|
||||
* This generated config.h header is meant for installation, which is why
|
||||
* all definitions MUST be prefixed to avoid conflicting with third-party
|
||||
* libraries. Only add configurable definitions which really must be used
|
||||
* from installable headers, such as the base type definition types.
|
||||
*/
|
||||
#include <winpr/platform.h>
|
||||
#include <winpr/smartcard.h>
|
||||
|
||||
#cmakedefine WITH_NATIVE_SSPI
|
||||
PSCardApiFunctionTable Inspect_RegisterSCardApi(PSCardApiFunctionTable pSCardApi);
|
||||
|
||||
#endif /* WINPR_CONFIG_H */
|
||||
#endif /* WINPR_SMARTCARD_INSPECT_PRIVATE_H */
|
|
@ -103,16 +103,18 @@
|
|||
|
||||
struct _PCSC_SCARDCONTEXT
|
||||
{
|
||||
SCARDCONTEXT hContext;
|
||||
SCARDHANDLE hCard;
|
||||
CRITICAL_SECTION lock;
|
||||
SCARDCONTEXT hContext;
|
||||
DWORD dwCardHandleCount;
|
||||
BOOL isTransactionLocked;
|
||||
};
|
||||
typedef struct _PCSC_SCARDCONTEXT PCSC_SCARDCONTEXT;
|
||||
|
||||
struct _PCSC_SCARDHANDLE
|
||||
{
|
||||
SCARDCONTEXT hContext;
|
||||
CRITICAL_SECTION lock;
|
||||
SCARDCONTEXT hSharedContext;
|
||||
SCARDCONTEXT hPrivateContext;
|
||||
};
|
||||
typedef struct _PCSC_SCARDHANDLE PCSC_SCARDHANDLE;
|
||||
|
||||
|
@ -132,6 +134,32 @@ static int g_StartedEventRefCount = 0;
|
|||
static BOOL g_SCardAutoAllocate = FALSE;
|
||||
static BOOL g_PnP_Notification = TRUE;
|
||||
|
||||
/**
|
||||
* g_LockTransactions: enable pcsc-lite SCardBeginTransaction/SCardEndTransaction.
|
||||
*
|
||||
* After wasting months trying to fix and work around an appalling number of serious issues
|
||||
* in both the pcsc-lite client library and the pcscd daemon, I decided to just give up on
|
||||
* the transaction system. Using them inevitably leads to multiple SCardConnect calls deadlocking.
|
||||
*
|
||||
* It is not very clear how WinSCard transactions should lock: some logs on Windows show that is
|
||||
* possible to call SCardBeginTransaction twice on the same SCARDHANDLE without the second call
|
||||
* being blocked. Worse, in this specific case one corresponding SCardEndTransaction is missing.
|
||||
*
|
||||
* pcsc-lite apparently implements these "nested" transactions as well, because it allows the same
|
||||
* SCARDHANDLE to be locked more than once with a counter. However, there must be a bug even in the
|
||||
* latest pcsc-lite daemon as we still get deadlocked on SCardConnect calls when using those.
|
||||
*
|
||||
* Trying to disable nested transactions by letting pcsc-lite know about only one transaction level
|
||||
* gives the same deadlocks on SCardConnect. In other words, there are serious deadlock issues in
|
||||
* pcsc-lite even when disabling nested transactions.
|
||||
*
|
||||
* Transactions are simply too much of a pain to support properly without deadlocking the entire
|
||||
* smartcard subsystem. In practice, there is not much of a difference if locking occurs or not.
|
||||
* We could revisit transactions later on based on the demand, but for now we just want things to work.
|
||||
*/
|
||||
|
||||
static BOOL g_LockTransactions = FALSE;
|
||||
|
||||
static wArrayList* g_Readers = NULL;
|
||||
static wListDictionary* g_CardHandles = NULL;
|
||||
static wListDictionary* g_CardContexts = NULL;
|
||||
|
@ -147,6 +175,9 @@ const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(PC
|
|||
const PCSC_SCARD_IO_REQUEST g_PCSC_rgSCardRawPci = { PCSC_SCARD_PROTOCOL_RAW, sizeof(PCSC_SCARD_IO_REQUEST) };
|
||||
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardFreeMemory_Internal(SCARDCONTEXT hContext, LPCVOID pvMem);
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext_Internal(DWORD dwScope,
|
||||
LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext);
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardReleaseContext_Internal(SCARDCONTEXT hContext);
|
||||
|
||||
LONG PCSC_MapErrorCodeToWinSCard(LONG errorCode)
|
||||
{
|
||||
|
@ -313,7 +344,10 @@ void PCSC_ReleaseCardContext(SCARDCONTEXT hContext)
|
|||
pContext = PCSC_GetCardContextData(hContext);
|
||||
|
||||
if (!pContext)
|
||||
{
|
||||
printf("PCSC_ReleaseCardContext: null pContext!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&(pContext->lock));
|
||||
|
||||
|
@ -383,22 +417,34 @@ SCARDCONTEXT PCSC_GetCardContextFromHandle(SCARDHANDLE hCard)
|
|||
if (!pCard)
|
||||
return 0;
|
||||
|
||||
return pCard->hContext;
|
||||
return pCard->hPrivateContext;
|
||||
}
|
||||
|
||||
PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard)
|
||||
PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hSharedContext, SCARDCONTEXT hPrivateContext, SCARDHANDLE hCard)
|
||||
{
|
||||
PCSC_SCARDHANDLE* pCard;
|
||||
PCSC_SCARDCONTEXT* pContext;
|
||||
|
||||
pContext = PCSC_GetCardContextData(hSharedContext);
|
||||
|
||||
if (!pContext)
|
||||
{
|
||||
printf("PCSC_ConnectCardHandle: null pContext!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pCard = (PCSC_SCARDHANDLE*) calloc(1, sizeof(PCSC_SCARDHANDLE));
|
||||
|
||||
if (!pCard)
|
||||
return NULL;
|
||||
|
||||
pCard->hContext = hContext;
|
||||
pCard->hSharedContext = hSharedContext;
|
||||
pCard->hPrivateContext = hPrivateContext;
|
||||
|
||||
InitializeCriticalSectionAndSpinCount(&(pCard->lock), 4000);
|
||||
|
||||
pContext->dwCardHandleCount++;
|
||||
|
||||
if (!g_CardHandles)
|
||||
g_CardHandles = ListDictionary_New(TRUE);
|
||||
|
||||
|
@ -410,6 +456,7 @@ PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hContext, SCARDHANDLE hCar
|
|||
void PCSC_DisconnectCardHandle(SCARDHANDLE hCard)
|
||||
{
|
||||
PCSC_SCARDHANDLE* pCard;
|
||||
PCSC_SCARDCONTEXT* pContext;
|
||||
|
||||
pCard = PCSC_GetCardHandleData(hCard);
|
||||
|
||||
|
@ -418,12 +465,24 @@ void PCSC_DisconnectCardHandle(SCARDHANDLE hCard)
|
|||
|
||||
DeleteCriticalSection(&(pCard->lock));
|
||||
|
||||
pContext = PCSC_GetCardContextData(pCard->hSharedContext);
|
||||
|
||||
PCSC_SCardReleaseContext_Internal(pCard->hPrivateContext);
|
||||
|
||||
free(pCard);
|
||||
|
||||
if (!g_CardHandles)
|
||||
return;
|
||||
|
||||
ListDictionary_Remove(g_CardHandles, (void*) hCard);
|
||||
|
||||
if (!pContext)
|
||||
{
|
||||
printf("PCSC_DisconnectCardHandle: null pContext!");
|
||||
return;
|
||||
}
|
||||
|
||||
pContext->dwCardHandleCount--;
|
||||
}
|
||||
|
||||
BOOL PCSC_LockCardHandle(SCARDHANDLE hCard)
|
||||
|
@ -847,7 +906,7 @@ void* PCSC_SCardAllocMemory(SCARDCONTEXT hContext, size_t size)
|
|||
* Standard Windows Smart Card API (PCSC)
|
||||
*/
|
||||
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext(DWORD dwScope,
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext_Internal(DWORD dwScope,
|
||||
LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
|
||||
{
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
|
@ -861,13 +920,23 @@ WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext(DWORD dwScope,
|
|||
status = (LONG) g_PCSC.pfnSCardEstablishContext(pcsc_dwScope, pvReserved1, pvReserved2, phContext);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardEstablishContext(DWORD dwScope,
|
||||
LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
|
||||
{
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
|
||||
status = PCSC_SCardEstablishContext_Internal(dwScope, pvReserved1, pvReserved2, phContext);
|
||||
|
||||
if (status == SCARD_S_SUCCESS)
|
||||
PCSC_EstablishCardContext(*phContext);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardReleaseContext(SCARDCONTEXT hContext)
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardReleaseContext_Internal(SCARDCONTEXT hContext)
|
||||
{
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
|
||||
|
@ -883,7 +952,16 @@ WINSCARDAPI LONG WINAPI PCSC_SCardReleaseContext(SCARDCONTEXT hContext)
|
|||
status = (LONG) g_PCSC.pfnSCardReleaseContext(hContext);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
|
||||
if (!status)
|
||||
return status;
|
||||
}
|
||||
|
||||
WINSCARDAPI LONG WINAPI PCSC_SCardReleaseContext(SCARDCONTEXT hContext)
|
||||
{
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
|
||||
status = PCSC_SCardReleaseContext_Internal(hContext);
|
||||
|
||||
if (status != SCARD_S_SUCCESS)
|
||||
PCSC_ReleaseCardContext(hContext);
|
||||
|
||||
return status;
|
||||
|
@ -1590,6 +1668,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnect_Internal(SCARDCONTEXT hContext,
|
|||
{
|
||||
char* szReaderPCSC;
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
SCARDCONTEXT hPrivateContext = 0;
|
||||
PCSC_DWORD pcsc_dwShareMode = (PCSC_DWORD) dwShareMode;
|
||||
PCSC_DWORD pcsc_dwPreferredProtocols = 0;
|
||||
PCSC_DWORD pcsc_dwActiveProtocol = 0;
|
||||
|
@ -1597,6 +1676,11 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnect_Internal(SCARDCONTEXT hContext,
|
|||
if (!g_PCSC.pfnSCardConnect)
|
||||
return SCARD_E_NO_SERVICE;
|
||||
|
||||
status = PCSC_SCardEstablishContext_Internal(SCARD_SCOPE_SYSTEM, NULL, NULL, &hPrivateContext);
|
||||
|
||||
if (status != SCARD_S_SUCCESS)
|
||||
return status;
|
||||
|
||||
szReaderPCSC = PCSC_GetReaderNameFromAlias((char*) szReader);
|
||||
|
||||
if (!szReaderPCSC)
|
||||
|
@ -1604,15 +1688,19 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnect_Internal(SCARDCONTEXT hContext,
|
|||
|
||||
pcsc_dwPreferredProtocols = (PCSC_DWORD) PCSC_ConvertProtocolsFromWinSCard(dwPreferredProtocols);
|
||||
|
||||
status = (LONG) g_PCSC.pfnSCardConnect(hContext, szReaderPCSC,
|
||||
status = (LONG) g_PCSC.pfnSCardConnect(hPrivateContext, szReaderPCSC,
|
||||
pcsc_dwShareMode, pcsc_dwPreferredProtocols, phCard, &pcsc_dwActiveProtocol);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
|
||||
if (status == SCARD_S_SUCCESS)
|
||||
{
|
||||
PCSC_ConnectCardHandle(hContext, *phCard);
|
||||
PCSC_ConnectCardHandle(hContext, hPrivateContext, *phCard);
|
||||
*pdwActiveProtocol = PCSC_ConvertProtocolsToWinSCard((DWORD) pcsc_dwActiveProtocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
PCSC_SCardReleaseContext(hPrivateContext);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -1704,12 +1792,32 @@ WINSCARDAPI LONG WINAPI PCSC_SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposit
|
|||
WINSCARDAPI LONG WINAPI PCSC_SCardBeginTransaction(SCARDHANDLE hCard)
|
||||
{
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
PCSC_SCARDHANDLE* pCard = NULL;
|
||||
PCSC_SCARDCONTEXT* pContext = NULL;
|
||||
|
||||
if (!g_PCSC.pfnSCardBeginTransaction)
|
||||
return SCARD_E_NO_SERVICE;
|
||||
|
||||
status = (LONG) g_PCSC.pfnSCardBeginTransaction(hCard);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
pCard = PCSC_GetCardHandleData(hCard);
|
||||
|
||||
if (!pCard)
|
||||
return SCARD_E_INVALID_HANDLE;
|
||||
|
||||
pContext = PCSC_GetCardContextData(pCard->hSharedContext);
|
||||
|
||||
if (!pContext)
|
||||
return SCARD_E_INVALID_HANDLE;
|
||||
|
||||
if (pContext->isTransactionLocked)
|
||||
return SCARD_S_SUCCESS; /* disable nested transactions */
|
||||
|
||||
if (g_LockTransactions)
|
||||
{
|
||||
status = (LONG) g_PCSC.pfnSCardBeginTransaction(hCard);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
}
|
||||
|
||||
pContext->isTransactionLocked = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -1717,13 +1825,33 @@ WINSCARDAPI LONG WINAPI PCSC_SCardBeginTransaction(SCARDHANDLE hCard)
|
|||
WINSCARDAPI LONG WINAPI PCSC_SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
|
||||
{
|
||||
LONG status = SCARD_S_SUCCESS;
|
||||
PCSC_SCARDHANDLE* pCard = NULL;
|
||||
PCSC_SCARDCONTEXT* pContext = NULL;
|
||||
PCSC_DWORD pcsc_dwDisposition = (PCSC_DWORD) dwDisposition;
|
||||
|
||||
if (!g_PCSC.pfnSCardEndTransaction)
|
||||
return SCARD_E_NO_SERVICE;
|
||||
|
||||
status = (LONG) g_PCSC.pfnSCardEndTransaction(hCard, pcsc_dwDisposition);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
pCard = PCSC_GetCardHandleData(hCard);
|
||||
|
||||
if (!pCard)
|
||||
return SCARD_E_INVALID_HANDLE;
|
||||
|
||||
pContext = PCSC_GetCardContextData(pCard->hSharedContext);
|
||||
|
||||
if (!pContext)
|
||||
return SCARD_E_INVALID_HANDLE;
|
||||
|
||||
if (!pContext->isTransactionLocked)
|
||||
return SCARD_S_SUCCESS; /* disable nested transactions */
|
||||
|
||||
if (g_LockTransactions)
|
||||
{
|
||||
status = (LONG) g_PCSC.pfnSCardEndTransaction(hCard, pcsc_dwDisposition);
|
||||
status = PCSC_MapErrorCodeToWinSCard(status);
|
||||
}
|
||||
|
||||
pContext->isTransactionLocked = FALSE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -2648,7 +2776,7 @@ extern int PCSC_InitializeSCardApi_Link(void);
|
|||
int PCSC_InitializeSCardApi(void)
|
||||
{
|
||||
/* Disable pcsc-lite's (poor) blocking so we can handle it ourselves */
|
||||
//SetEnvironmentVariableA("PCSCLITE_NO_BLOCKING", "1");
|
||||
SetEnvironmentVariableA("PCSCLITE_NO_BLOCKING", "1");
|
||||
|
||||
#ifndef DISABLE_PCSC_LINK
|
||||
if (PCSC_InitializeSCardApi_Link() >= 0)
|
||||
|
|
|
@ -121,7 +121,7 @@ PSCardApiFunctionTable WinSCard_GetSCardApiFunctionTable(void)
|
|||
|
||||
int WinSCard_InitializeSCardApi(void)
|
||||
{
|
||||
g_WinSCardModule = LoadLibraryA("winscard.dll");
|
||||
g_WinSCardModule = LoadLibraryA("WinSCard.dll");
|
||||
|
||||
if (!g_WinSCardModule)
|
||||
return -1;
|
||||
|
|
|
@ -43,20 +43,21 @@ set(${MODULE_PREFIX}_CREDSSP_SRCS
|
|||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_CREDSSP_SRCS}
|
||||
sspi_winpr.c
|
||||
sspi_winpr.h
|
||||
sspi_export.c
|
||||
sspi.c
|
||||
sspi.h)
|
||||
|
||||
if(NOT WITH_NATIVE_SSPI)
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_NTLM_SRCS}
|
||||
${${MODULE_PREFIX}_KERBEROS_SRCS}
|
||||
${${MODULE_PREFIX}_NEGOTIATE_SRCS}
|
||||
${${MODULE_PREFIX}_SCHANNEL_SRCS}
|
||||
${${MODULE_PREFIX}_SRCS})
|
||||
endif()
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_NTLM_SRCS}
|
||||
${${MODULE_PREFIX}_KERBEROS_SRCS}
|
||||
${${MODULE_PREFIX}_NEGOTIATE_SRCS}
|
||||
${${MODULE_PREFIX}_SCHANNEL_SRCS}
|
||||
${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
if(MSVC AND (NOT MONOLITHIC_BUILD))
|
||||
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def)
|
||||
#set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def)
|
||||
endif()
|
||||
|
||||
add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
|
||||
|
@ -80,7 +81,7 @@ endif()
|
|||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
|
||||
MODULE winpr
|
||||
MODULES winpr-crt winpr-sysinfo winpr-registry winpr-crypto winpr-utils)
|
||||
MODULES winpr-crt winpr-sysinfo winpr-registry winpr-crypto winpr-library winpr-utils)
|
||||
|
||||
if(MONOLITHIC_BUILD)
|
||||
set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* Credential Security Support Provider (CredSSP)
|
||||
*
|
||||
* Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2010-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -35,7 +35,7 @@ SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextW(PCredHandle phCrede
|
|||
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
|
@ -44,22 +44,24 @@ SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextA(PCredHandle phCrede
|
|||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
CREDSSP_CONTEXT* context;
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
context = sspi_SecureHandleGetLowerPointer(phContext);
|
||||
context = (CREDSSP_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = credssp_ContextNew();
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
if (!context)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) CREDSSP_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
|
||||
}
|
||||
|
||||
CREDSSP_CONTEXT* credssp_ContextNew()
|
||||
|
@ -68,10 +70,8 @@ CREDSSP_CONTEXT* credssp_ContextNew()
|
|||
|
||||
context = (CREDSSP_CONTEXT*) calloc(1, sizeof(CREDSSP_CONTEXT));
|
||||
|
||||
if (context != NULL)
|
||||
{
|
||||
|
||||
}
|
||||
if (!context)
|
||||
return NULL;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
@ -99,19 +99,23 @@ SECURITY_STATUS SEC_ENTRY credssp_AcquireCredentialsHandleW(SEC_WCHAR* pszPrinci
|
|||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage,
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SEC_WINNT_AUTH_IDENTITY* identity;
|
||||
|
||||
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
|
@ -122,21 +126,21 @@ SECURITY_STATUS SEC_ENTRY credssp_AcquireCredentialsHandleA(SEC_CHAR* pszPrincip
|
|||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesW(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesA(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
@ -146,12 +150,12 @@ SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesA(PCredHandle phCred
|
|||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_FreeCredentialsHandle(PCredHandle phCredential)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
if (!phCredential)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
@ -163,22 +167,22 @@ SECURITY_STATUS SEC_ENTRY credssp_FreeCredentialsHandle(PCredHandle phCredential
|
|||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_MakeSignature(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
const SecurityFunctionTableA CREDSSP_SecurityFunctionTableA =
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -41,145 +41,195 @@
|
|||
|
||||
char* NTLM_PACKAGE_NAME = "NTLM";
|
||||
|
||||
void ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
|
||||
int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
|
||||
{
|
||||
char *ws = Workstation;
|
||||
int status;
|
||||
DWORD nSize = 0;
|
||||
char* ws = Workstation;
|
||||
|
||||
if (!Workstation)
|
||||
{
|
||||
GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize);
|
||||
ws = malloc(nSize);
|
||||
GetComputerNameExA(ComputerNameNetBIOS, ws, &nSize);
|
||||
|
||||
ws = (char*) malloc(nSize);
|
||||
|
||||
if (!ws)
|
||||
return -1;
|
||||
|
||||
if (!GetComputerNameExA(ComputerNameNetBIOS, ws, &nSize))
|
||||
return 0;
|
||||
}
|
||||
|
||||
context->Workstation.Length = ConvertToUnicode(CP_UTF8, 0,
|
||||
ws, -1, &context->Workstation.Buffer, 0) - 1;
|
||||
context->Workstation.Buffer = NULL;
|
||||
status = ConvertToUnicode(CP_UTF8, 0, ws, -1, &context->Workstation.Buffer, 0);
|
||||
free(ws);
|
||||
|
||||
if (status <= 0)
|
||||
return -1;
|
||||
|
||||
context->Workstation.Length = (USHORT) (status - 1);
|
||||
context->Workstation.Length *= 2;
|
||||
|
||||
if (!Workstation)
|
||||
free(Workstation);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
|
||||
int ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
|
||||
{
|
||||
context->ServicePrincipalName.Length = _wcslen(ServicePrincipalName) * 2;
|
||||
if (!ServicePrincipalName)
|
||||
{
|
||||
context->ServicePrincipalName.Buffer = NULL;
|
||||
return;
|
||||
context->ServicePrincipalName.Length = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
context->ServicePrincipalName.Length = _wcslen(ServicePrincipalName) * 2;
|
||||
context->ServicePrincipalName.Buffer = (PWSTR) malloc(context->ServicePrincipalName.Length + 2);
|
||||
|
||||
if (!context->ServicePrincipalName.Buffer)
|
||||
return -1;
|
||||
|
||||
CopyMemory(context->ServicePrincipalName.Buffer, ServicePrincipalName, context->ServicePrincipalName.Length + 2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_SetContextServicePrincipalNameA(NTLM_CONTEXT* context, char* ServicePrincipalName)
|
||||
int ntlm_SetContextServicePrincipalNameA(NTLM_CONTEXT* context, char* ServicePrincipalName)
|
||||
{
|
||||
context->ServicePrincipalName.Length = ConvertToUnicode(CP_UTF8, 0,
|
||||
ServicePrincipalName, -1, &context->ServicePrincipalName.Buffer, 0) - 1;
|
||||
context->ServicePrincipalName.Length *= 2;
|
||||
int status;
|
||||
|
||||
context->ServicePrincipalName.Buffer = NULL;
|
||||
|
||||
status = ConvertToUnicode(CP_UTF8, 0, ServicePrincipalName, -1, &context->ServicePrincipalName.Buffer, 0);
|
||||
|
||||
if (status <= 0)
|
||||
return -1;
|
||||
|
||||
context->ServicePrincipalName.Length = (USHORT) ((status - 1) * 2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
|
||||
int ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
|
||||
{
|
||||
char *name = TargetName;
|
||||
int status;
|
||||
DWORD nSize = 0;
|
||||
char* name = TargetName;
|
||||
|
||||
if (!TargetName)
|
||||
{
|
||||
GetComputerNameExA(ComputerNameDnsHostname, NULL, &nSize);
|
||||
name = malloc(nSize);
|
||||
GetComputerNameExA(ComputerNameDnsHostname, name, &nSize);
|
||||
if (!GetComputerNameExA(ComputerNameDnsHostname, NULL, &nSize))
|
||||
return -1;
|
||||
|
||||
name = (char*) malloc(nSize);
|
||||
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
if (!GetComputerNameExA(ComputerNameDnsHostname, name, &nSize))
|
||||
return -1;
|
||||
|
||||
CharUpperA(TargetName);
|
||||
}
|
||||
|
||||
context->TargetName.cbBuffer = ConvertToUnicode(CP_UTF8, 0,
|
||||
name, -1, (LPWSTR*) &context->TargetName.pvBuffer, 0) - 1;
|
||||
context->TargetName.cbBuffer *= 2;
|
||||
context->TargetName.pvBuffer = NULL;
|
||||
status = ConvertToUnicode(CP_UTF8, 0, name, -1, (LPWSTR*) &context->TargetName.pvBuffer, 0);
|
||||
|
||||
if (status <= 0)
|
||||
return -1;
|
||||
|
||||
context->TargetName.cbBuffer = (USHORT) ((status - 1) * 2);
|
||||
|
||||
if (!TargetName)
|
||||
free(name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
NTLM_CONTEXT* ntlm_ContextNew()
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
DWORD dwValue;
|
||||
NTLM_CONTEXT* context;
|
||||
|
||||
context = (NTLM_CONTEXT*) malloc(sizeof(NTLM_CONTEXT));
|
||||
ZeroMemory(context, sizeof(NTLM_CONTEXT));
|
||||
context = (NTLM_CONTEXT*) calloc(1, sizeof(NTLM_CONTEXT));
|
||||
|
||||
if (context != NULL)
|
||||
if (!context)
|
||||
return NULL;
|
||||
|
||||
context->NTLMv2 = TRUE;
|
||||
context->UseMIC = FALSE;
|
||||
context->SendVersionInfo = TRUE;
|
||||
context->SendSingleHostData = FALSE;
|
||||
context->SendWorkstationName = TRUE;
|
||||
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\WinPR\\NTLM"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
DWORD dwValue;
|
||||
if (RegQueryValueEx(hKey, _T("NTLMv2"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->NTLMv2 = dwValue ? 1 : 0;
|
||||
|
||||
context->NTLMv2 = TRUE;
|
||||
context->UseMIC = FALSE;
|
||||
context->SendVersionInfo = TRUE;
|
||||
context->SendSingleHostData = FALSE;
|
||||
context->SendWorkstationName = TRUE;
|
||||
if (RegQueryValueEx(hKey, _T("UseMIC"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->UseMIC = dwValue ? 1 : 0;
|
||||
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\WinPR\\NTLM"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
if (RegQueryValueEx(hKey, _T("SendVersionInfo"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendVersionInfo = dwValue ? 1 : 0;
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
if (RegQueryValueEx(hKey, _T("SendSingleHostData"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendSingleHostData = dwValue ? 1 : 0;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("SendWorkstationName"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendWorkstationName = dwValue ? 1 : 0;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("WorkstationName"), NULL, &dwType, NULL, &dwSize) == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("NTLMv2"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->NTLMv2 = dwValue ? 1 : 0;
|
||||
char* workstation = (char*) malloc(dwSize + 1);
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("UseMIC"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->UseMIC = dwValue ? 1 : 0;
|
||||
if (!workstation)
|
||||
return NULL;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("SendVersionInfo"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendVersionInfo = dwValue ? 1 : 0;
|
||||
status = RegQueryValueExA(hKey, "WorkstationName", NULL, &dwType, (BYTE*) workstation, &dwSize);
|
||||
workstation[dwSize] = '\0';
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("SendSingleHostData"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendSingleHostData = dwValue ? 1 : 0;
|
||||
if (ntlm_SetContextWorkstation(context, workstation) < 0)
|
||||
return NULL;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("SendWorkstationName"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendWorkstationName = dwValue ? 1 : 0;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("WorkstationName"), NULL, &dwType, NULL, &dwSize) == ERROR_SUCCESS)
|
||||
{
|
||||
char* workstation = (char*) malloc(dwSize + 1);
|
||||
|
||||
status = RegQueryValueExA(hKey, "WorkstationName", NULL, &dwType, (BYTE*) workstation, &dwSize);
|
||||
workstation[dwSize] = '\0';
|
||||
|
||||
ntlm_SetContextWorkstation(context, workstation);
|
||||
free(workstation);
|
||||
}
|
||||
|
||||
RegCloseKey(hKey);
|
||||
free(workstation);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended Protection is enabled by default in Windows 7,
|
||||
* but enabling it in WinPR breaks TS Gateway at this point
|
||||
*/
|
||||
context->SuppressExtendedProtection = FALSE;
|
||||
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\LSA"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("SuppressExtendedProtection"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SuppressExtendedProtection = dwValue ? 1 : 0;
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
context->NegotiateFlags = 0;
|
||||
context->LmCompatibilityLevel = 3;
|
||||
context->state = NTLM_STATE_INITIAL;
|
||||
memset(context->MachineID, 0xAA, sizeof(context->MachineID));
|
||||
|
||||
if (context->NTLMv2)
|
||||
context->UseMIC = TRUE;
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended Protection is enabled by default in Windows 7,
|
||||
* but enabling it in WinPR breaks TS Gateway at this point
|
||||
*/
|
||||
context->SuppressExtendedProtection = FALSE;
|
||||
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\LSA"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("SuppressExtendedProtection"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SuppressExtendedProtection = dwValue ? 1 : 0;
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
context->NegotiateFlags = 0;
|
||||
context->LmCompatibilityLevel = 3;
|
||||
context->state = NTLM_STATE_INITIAL;
|
||||
FillMemory(context->MachineID, sizeof(context->MachineID), 0xAA);
|
||||
|
||||
if (context->NTLMv2)
|
||||
context->UseMIC = TRUE;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
@ -197,10 +247,6 @@ void ntlm_ContextFree(NTLM_CONTEXT* context)
|
|||
sspi_SecBufferFree(&context->LmChallengeResponse);
|
||||
|
||||
free(context->ServicePrincipalName.Buffer);
|
||||
|
||||
free(context->identity.User);
|
||||
free(context->identity.Password);
|
||||
free(context->identity.Domain);
|
||||
free(context->Workstation.Buffer);
|
||||
free(context);
|
||||
}
|
||||
|
@ -209,39 +255,32 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal
|
|||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SEC_WINNT_AUTH_IDENTITY* identity;
|
||||
|
||||
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
|
||||
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_INBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_BOTH))
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity != NULL)
|
||||
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
}
|
||||
else if (fCredentialUse == SECPKG_CRED_INBOUND)
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
if (identity)
|
||||
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
else
|
||||
ZeroMemory(&(credentials->identity), sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
if (!credentials)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
credentials->fCredentialUse = fCredentialUse;
|
||||
credentials->pGetKeyFn = pGetKeyFn;
|
||||
credentials->pvGetKeyArgument = pvGetKeyArgument;
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity)
|
||||
sspi_CopyAuthIdentity(&(credentials->identity), identity);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
@ -250,49 +289,44 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal,
|
|||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SEC_WINNT_AUTH_IDENTITY* identity;
|
||||
|
||||
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
|
||||
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_INBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_BOTH))
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity != NULL)
|
||||
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
}
|
||||
else if (fCredentialUse == SECPKG_CRED_INBOUND)
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
if (identity != NULL)
|
||||
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
if (!credentials)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
credentials->fCredentialUse = fCredentialUse;
|
||||
credentials->pGetKeyFn = pGetKeyFn;
|
||||
credentials->pvGetKeyArgument = pvGetKeyArgument;
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity)
|
||||
sspi_CopyAuthIdentity(&(credentials->identity), identity);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
if (!phCredential)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
@ -326,7 +360,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P
|
|||
{
|
||||
NTLM_CONTEXT* context;
|
||||
SECURITY_STATUS status;
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
PSecBuffer input_buffer;
|
||||
PSecBuffer output_buffer;
|
||||
|
||||
|
@ -339,13 +373,13 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P
|
|||
if (!context)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
context->server = 1;
|
||||
context->server = TRUE;
|
||||
|
||||
if (fContextReq & ASC_REQ_CONFIDENTIALITY)
|
||||
context->confidentiality = 1;
|
||||
context->confidentiality = TRUE;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
context->credentials = credentials;
|
||||
|
||||
ntlm_SetContextTargetName(context, NULL);
|
||||
|
||||
|
@ -414,7 +448,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P
|
|||
|
||||
if (pOutput)
|
||||
{
|
||||
int i;
|
||||
ULONG i;
|
||||
|
||||
for (i = 0; i < pOutput->cBuffers; i++)
|
||||
{
|
||||
|
@ -441,7 +475,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredenti
|
|||
{
|
||||
NTLM_CONTEXT* context;
|
||||
SECURITY_STATUS status;
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
PSecBuffer input_buffer = NULL;
|
||||
PSecBuffer output_buffer = NULL;
|
||||
PSecBuffer channel_bindings = NULL;
|
||||
|
@ -456,15 +490,19 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredenti
|
|||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (fContextReq & ISC_REQ_CONFIDENTIALITY)
|
||||
context->confidentiality = 1;
|
||||
context->confidentiality = TRUE;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
context->credentials = credentials;
|
||||
|
||||
if (context->Workstation.Length < 1)
|
||||
ntlm_SetContextWorkstation(context, NULL);
|
||||
{
|
||||
if (ntlm_SetContextWorkstation(context, NULL) < 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ntlm_SetContextServicePrincipalNameW(context, pszTargetName);
|
||||
sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
|
||||
if (ntlm_SetContextServicePrincipalNameW(context, pszTargetName) < 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME);
|
||||
|
@ -554,20 +592,39 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(PCredHandle phCredenti
|
|||
SECURITY_STATUS status;
|
||||
SEC_WCHAR* pszTargetNameW = NULL;
|
||||
|
||||
if (pszTargetName != NULL)
|
||||
if (pszTargetName)
|
||||
{
|
||||
ConvertToUnicode(CP_UTF8, 0, pszTargetName, -1, &pszTargetNameW, 0);
|
||||
if (ConvertToUnicode(CP_UTF8, 0, pszTargetName, -1, &pszTargetNameW, 0) <= 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
status = ntlm_InitializeSecurityContextW(phCredential, phContext, pszTargetNameW, fContextReq,
|
||||
Reserved1, TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
|
||||
|
||||
if (pszTargetNameW != NULL)
|
||||
if (pszTargetNameW)
|
||||
free(pszTargetNameW);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext, PSecBufferDesc pToken)
|
||||
{
|
||||
NTLM_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (context->server)
|
||||
{
|
||||
status = ntlm_server_AuthenticateComplete(context);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375354 */
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
|
||||
|
@ -588,12 +645,16 @@ SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
|
|||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
NTLM_CONTEXT* context;
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (ulAttribute == SECPKG_ATTR_SIZES)
|
||||
{
|
||||
SecPkgContext_Sizes* ContextSizes = (SecPkgContext_Sizes*) pBuffer;
|
||||
|
@ -605,6 +666,35 @@ SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, UL
|
|||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
else if (ulAttribute == SECPKG_ATTR_AUTH_IDENTITY)
|
||||
{
|
||||
int status;
|
||||
char* UserA = NULL;
|
||||
char* DomainA = NULL;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SecPkgContext_AuthIdentity* AuthIdentity = (SecPkgContext_AuthIdentity*) pBuffer;
|
||||
|
||||
credentials = context->credentials;
|
||||
ZeroMemory(AuthIdentity, sizeof(SecPkgContext_AuthIdentity));
|
||||
|
||||
UserA = AuthIdentity->User;
|
||||
status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) credentials->identity.User,
|
||||
credentials->identity.UserLength,
|
||||
&UserA, 256, NULL, NULL);
|
||||
|
||||
if (status <= 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
DomainA = AuthIdentity->Domain;
|
||||
status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) credentials->identity.Domain,
|
||||
credentials->identity.DomainLength,
|
||||
&DomainA, 256, NULL, NULL);
|
||||
|
||||
if (status <= 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
@ -614,6 +704,38 @@ SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext, UL
|
|||
return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
NTLM_CONTEXT* context;
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
|
||||
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH)
|
||||
{
|
||||
SecPkgContext_AuthNtlmHash* AuthNtlmHash = (SecPkgContext_AuthNtlmHash*) pBuffer;
|
||||
|
||||
if (cbBuffer < sizeof(SecPkgContext_AuthNtlmHash))
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
|
||||
CopyMemory(context->NtlmHash, AuthNtlmHash->NtlmHash, 16);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
return ntlm_SetContextAttributesW(phContext, ulAttribute, pBuffer, cbBuffer);
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
|
@ -654,20 +776,24 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
|
|||
/* Copy original data buffer */
|
||||
length = data_buffer->cbBuffer;
|
||||
data = malloc(length);
|
||||
|
||||
if (!data)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
CopyMemory(data, data_buffer->pvBuffer, length);
|
||||
|
||||
/* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
|
||||
HMAC_CTX_init(&hmac);
|
||||
HMAC_Init_ex(&hmac, context->SendSigningKey, 16, EVP_md5(), NULL);
|
||||
HMAC_Update(&hmac, (void*) &(SeqNo), 4);
|
||||
HMAC_Update(&hmac, data, length);
|
||||
HMAC_Update(&hmac, (void*) data, length);
|
||||
HMAC_Final(&hmac, digest, NULL);
|
||||
HMAC_CTX_cleanup(&hmac);
|
||||
|
||||
/* Encrypt message using with RC4, result overwrites original buffer */
|
||||
|
||||
if (context->confidentiality)
|
||||
RC4(&context->SendRc4Seal, length, data, data_buffer->pvBuffer);
|
||||
RC4(&context->SendRc4Seal, length, (BYTE*) data, (BYTE*) data_buffer->pvBuffer);
|
||||
else
|
||||
CopyMemory(data_buffer->pvBuffer, data, length);
|
||||
|
||||
|
@ -719,7 +845,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
|
|||
PSecBuffer signature_buffer = NULL;
|
||||
|
||||
SeqNo = (UINT32) MessageSeqNo;
|
||||
context = sspi_SecureHandleGetLowerPointer(phContext);
|
||||
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
for (index = 0; index < (int) pMessage->cBuffers; index++)
|
||||
{
|
||||
|
@ -738,12 +864,16 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
|
|||
/* Copy original data buffer */
|
||||
length = data_buffer->cbBuffer;
|
||||
data = malloc(length);
|
||||
|
||||
if (!data)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
CopyMemory(data, data_buffer->pvBuffer, length);
|
||||
|
||||
/* Decrypt message using with RC4, result overwrites original buffer */
|
||||
|
||||
if (context->confidentiality)
|
||||
RC4(&context->RecvRc4Seal, length, data, data_buffer->pvBuffer);
|
||||
RC4(&context->RecvRc4Seal, length, (BYTE*) data, (BYTE*) data_buffer->pvBuffer);
|
||||
else
|
||||
CopyMemory(data_buffer->pvBuffer, data, length);
|
||||
|
||||
|
@ -751,7 +881,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
|
|||
HMAC_CTX_init(&hmac);
|
||||
HMAC_Init_ex(&hmac, context->RecvSigningKey, 16, EVP_md5(), NULL);
|
||||
HMAC_Update(&hmac, (void*) &(SeqNo), 4);
|
||||
HMAC_Update(&hmac, data_buffer->pvBuffer, data_buffer->cbBuffer);
|
||||
HMAC_Update(&hmac, (void*) data_buffer->pvBuffer, data_buffer->cbBuffer);
|
||||
HMAC_Final(&hmac, digest, NULL);
|
||||
HMAC_CTX_cleanup(&hmac);
|
||||
|
||||
|
@ -784,7 +914,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
|
|||
fprintf(stderr, "Expected Signature:\n");
|
||||
winpr_HexDump(expected_signature, 16);
|
||||
fprintf(stderr, "Actual Signature:\n");
|
||||
winpr_HexDump(signature_buffer->pvBuffer, 16);
|
||||
winpr_HexDump((BYTE*) signature_buffer->pvBuffer, 16);
|
||||
|
||||
return SEC_E_MESSAGE_ALTERED;
|
||||
}
|
||||
|
@ -794,12 +924,12 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
|
|||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
const SecurityFunctionTableA NTLM_SecurityFunctionTableA =
|
||||
|
@ -812,7 +942,7 @@ const SecurityFunctionTableA NTLM_SecurityFunctionTableA =
|
|||
NULL, /* Reserved2 */
|
||||
ntlm_InitializeSecurityContextA, /* InitializeSecurityContext */
|
||||
ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
NULL, /* CompleteAuthToken */
|
||||
ntlm_CompleteAuthToken, /* CompleteAuthToken */
|
||||
ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
NULL, /* ApplyControlToken */
|
||||
ntlm_QueryContextAttributesA, /* QueryContextAttributes */
|
||||
|
@ -831,7 +961,7 @@ const SecurityFunctionTableA NTLM_SecurityFunctionTableA =
|
|||
NULL, /* QuerySecurityContextToken */
|
||||
ntlm_EncryptMessage, /* EncryptMessage */
|
||||
ntlm_DecryptMessage, /* DecryptMessage */
|
||||
NULL, /* SetContextAttributes */
|
||||
ntlm_SetContextAttributesA, /* SetContextAttributes */
|
||||
};
|
||||
|
||||
const SecurityFunctionTableW NTLM_SecurityFunctionTableW =
|
||||
|
@ -844,7 +974,7 @@ const SecurityFunctionTableW NTLM_SecurityFunctionTableW =
|
|||
NULL, /* Reserved2 */
|
||||
ntlm_InitializeSecurityContextW, /* InitializeSecurityContext */
|
||||
ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
NULL, /* CompleteAuthToken */
|
||||
ntlm_CompleteAuthToken, /* CompleteAuthToken */
|
||||
ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
NULL, /* ApplyControlToken */
|
||||
ntlm_QueryContextAttributesW, /* QueryContextAttributes */
|
||||
|
@ -863,7 +993,7 @@ const SecurityFunctionTableW NTLM_SecurityFunctionTableW =
|
|||
NULL, /* QuerySecurityContextToken */
|
||||
ntlm_EncryptMessage, /* EncryptMessage */
|
||||
ntlm_DecryptMessage, /* DecryptMessage */
|
||||
NULL, /* SetContextAttributes */
|
||||
ntlm_SetContextAttributesA, /* SetContextAttributes */
|
||||
};
|
||||
|
||||
const SecPkgInfoA NTLM_SecPkgInfoA =
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -23,6 +23,8 @@
|
|||
#include <winpr/sspi.h>
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include <winpr/nt.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/md4.h>
|
||||
|
@ -78,6 +80,7 @@ enum _NTLM_STATE
|
|||
NTLM_STATE_NEGOTIATE,
|
||||
NTLM_STATE_CHALLENGE,
|
||||
NTLM_STATE_AUTHENTICATE,
|
||||
NTLM_STATE_COMPLETION,
|
||||
NTLM_STATE_FINAL
|
||||
};
|
||||
typedef enum _NTLM_STATE NTLM_STATE;
|
||||
|
@ -226,6 +229,8 @@ struct _NTLM_CONTEXT
|
|||
NTLM_STATE state;
|
||||
int SendSeqNum;
|
||||
int RecvSeqNum;
|
||||
BYTE NtlmHash[16];
|
||||
BYTE NtlmV2Hash[16];
|
||||
BYTE MachineID[32];
|
||||
BOOL SendVersionInfo;
|
||||
BOOL confidentiality;
|
||||
|
@ -241,7 +246,7 @@ struct _NTLM_CONTEXT
|
|||
BOOL SendWorkstationName;
|
||||
UNICODE_STRING Workstation;
|
||||
UNICODE_STRING ServicePrincipalName;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
BYTE* ChannelBindingToken;
|
||||
BYTE ChannelBindingsHash[16];
|
||||
SecPkgContext_Bindings Bindings;
|
||||
|
@ -258,6 +263,7 @@ struct _NTLM_CONTEXT
|
|||
SecBuffer TargetName;
|
||||
SecBuffer NtChallengeResponse;
|
||||
SecBuffer LmChallengeResponse;
|
||||
NTLMv2_RESPONSE NTLMv2Response;
|
||||
BYTE Timestamp[8];
|
||||
BYTE ChallengeTimestamp[8];
|
||||
BYTE ServerChallenge[8];
|
||||
|
@ -272,6 +278,7 @@ struct _NTLM_CONTEXT
|
|||
BYTE ServerSigningKey[16];
|
||||
BYTE ServerSealingKey[16];
|
||||
BYTE MessageIntegrityCheck[16];
|
||||
UINT32 MessageIntegrityCheckOffset;
|
||||
};
|
||||
typedef struct _NTLM_CONTEXT NTLM_CONTEXT;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (AV_PAIRs)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -173,34 +173,45 @@ NTLM_AV_PAIR* ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, NTLM_AV_PAIR* pAv
|
|||
return pAvPairCopy;
|
||||
}
|
||||
|
||||
void ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
|
||||
int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
|
||||
{
|
||||
char* name;
|
||||
int length;
|
||||
int status;
|
||||
DWORD nSize = 0;
|
||||
|
||||
GetComputerNameExA(type, NULL, &nSize);
|
||||
name = malloc(nSize);
|
||||
GetComputerNameExA(type, name, &nSize);
|
||||
|
||||
name = (char*) malloc(nSize);
|
||||
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
if (!GetComputerNameExA(type, name, &nSize))
|
||||
return -1;
|
||||
|
||||
if (type == ComputerNameNetBIOS)
|
||||
CharUpperA(name);
|
||||
|
||||
length = ConvertToUnicode(CP_UTF8, 0, name, -1, &pName->Buffer, 0);
|
||||
status = ConvertToUnicode(CP_UTF8, 0, name, -1, &pName->Buffer, 0);
|
||||
|
||||
pName->Length = (length - 1) * 2;
|
||||
if (status <= 0)
|
||||
return status;
|
||||
|
||||
pName->Length = (USHORT) ((status - 1) * 2);
|
||||
pName->MaximumLength = pName->Length;
|
||||
|
||||
free(name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_free_unicode_string(PUNICODE_STRING string)
|
||||
{
|
||||
if (string != NULL)
|
||||
if (string)
|
||||
{
|
||||
if (string->Length > 0)
|
||||
{
|
||||
if (string->Buffer != NULL)
|
||||
if (string->Buffer)
|
||||
free(string->Buffer);
|
||||
|
||||
string->Buffer = NULL;
|
||||
|
@ -297,7 +308,7 @@ void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
|
|||
FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
|
||||
}
|
||||
|
||||
void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
int length;
|
||||
ULONG AvPairsCount;
|
||||
|
@ -310,23 +321,33 @@ void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
|||
UNICODE_STRING DnsComputerName;
|
||||
|
||||
NbDomainName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS);
|
||||
|
||||
if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
|
||||
return -1;
|
||||
|
||||
NbComputerName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS);
|
||||
|
||||
if (ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS) < 0)
|
||||
return -1;
|
||||
|
||||
DnsDomainName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain);
|
||||
|
||||
if (ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain) < 0)
|
||||
return -1;
|
||||
|
||||
DnsComputerName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname);
|
||||
|
||||
if (ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname) < 0)
|
||||
return -1;
|
||||
|
||||
AvPairsCount = 5;
|
||||
AvPairsLength = NbDomainName.Length + NbComputerName.Length +
|
||||
DnsDomainName.Length + DnsComputerName.Length + 8;
|
||||
|
||||
length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength);
|
||||
sspi_SecBufferAlloc(&context->ChallengeTargetInfo, length);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->ChallengeTargetInfo, length))
|
||||
return -1;
|
||||
|
||||
pAvPairList = (NTLM_AV_PAIR*) context->ChallengeTargetInfo.pvBuffer;
|
||||
AvPairListSize = (ULONG) context->ChallengeTargetInfo.cbBuffer;
|
||||
|
@ -342,9 +363,11 @@ void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
|||
ntlm_free_unicode_string(&NbComputerName);
|
||||
ntlm_free_unicode_string(&DnsDomainName);
|
||||
ntlm_free_unicode_string(&DnsComputerName);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
ULONG size;
|
||||
ULONG AvPairsCount;
|
||||
|
@ -369,31 +392,31 @@ void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
|||
AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvDnsTreeName);
|
||||
AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvTimestamp);
|
||||
|
||||
if (AvNbDomainName != NULL)
|
||||
if (AvNbDomainName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvNbDomainName */
|
||||
AvPairsValueLength += AvNbDomainName->AvLen;
|
||||
}
|
||||
|
||||
if (AvNbComputerName != NULL)
|
||||
if (AvNbComputerName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvNbComputerName */
|
||||
AvPairsValueLength += AvNbComputerName->AvLen;
|
||||
}
|
||||
|
||||
if (AvDnsDomainName != NULL)
|
||||
if (AvDnsDomainName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvDnsDomainName */
|
||||
AvPairsValueLength += AvDnsDomainName->AvLen;
|
||||
}
|
||||
|
||||
if (AvDnsComputerName != NULL)
|
||||
if (AvDnsComputerName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvDnsComputerName */
|
||||
AvPairsValueLength += AvDnsComputerName->AvLen;
|
||||
}
|
||||
|
||||
if (AvDnsTreeName != NULL)
|
||||
if (AvDnsTreeName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvDnsTreeName */
|
||||
AvPairsValueLength += AvDnsTreeName->AvLen;
|
||||
|
@ -448,22 +471,22 @@ void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
|||
|
||||
ntlm_av_pair_list_init(AuthenticateTargetInfo);
|
||||
|
||||
if (AvNbDomainName != NULL)
|
||||
if (AvNbDomainName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvNbDomainName);
|
||||
|
||||
if (AvNbComputerName != NULL)
|
||||
if (AvNbComputerName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvNbComputerName);
|
||||
|
||||
if (AvDnsDomainName != NULL)
|
||||
if (AvDnsDomainName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsDomainName);
|
||||
|
||||
if (AvDnsComputerName != NULL)
|
||||
if (AvDnsComputerName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsComputerName);
|
||||
|
||||
if (AvDnsTreeName != NULL)
|
||||
if (AvDnsTreeName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsTreeName);
|
||||
|
||||
if (AvTimestamp != NULL)
|
||||
if (AvTimestamp)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvTimestamp);
|
||||
|
||||
if (context->UseMIC)
|
||||
|
@ -497,4 +520,6 @@ void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
|||
AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvEOL);
|
||||
ZeroMemory((void*) AvEOL, 4);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId);
|
|||
NTLM_AV_PAIR* ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId, PBYTE Value, UINT16 AvLen);
|
||||
NTLM_AV_PAIR* ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, NTLM_AV_PAIR* pAvPair);
|
||||
|
||||
void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context);
|
||||
void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context);
|
||||
int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context);
|
||||
int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context);
|
||||
|
||||
#endif /* WINPR_SSPI_NTLM_AV_PAIRS_H */
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (Compute)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -32,12 +32,15 @@
|
|||
|
||||
#include "ntlm_compute.h"
|
||||
|
||||
const char lm_magic[] = "KGS!@#$%";
|
||||
const char LM_MAGIC[] = "KGS!@#$%";
|
||||
|
||||
static const char client_sign_magic[] = "session key to client-to-server signing key magic constant";
|
||||
static const char server_sign_magic[] = "session key to server-to-client signing key magic constant";
|
||||
static const char client_seal_magic[] = "session key to client-to-server sealing key magic constant";
|
||||
static const char server_seal_magic[] = "session key to server-to-client sealing key magic constant";
|
||||
static const char NTLM_CLIENT_SIGN_MAGIC[] = "session key to client-to-server signing key magic constant";
|
||||
static const char NTLM_SERVER_SIGN_MAGIC[] = "session key to server-to-client signing key magic constant";
|
||||
static const char NTLM_CLIENT_SEAL_MAGIC[] = "session key to client-to-server sealing key magic constant";
|
||||
static const char NTLM_SERVER_SEAL_MAGIC[] = "session key to server-to-client sealing key magic constant";
|
||||
|
||||
static const BYTE NTLM_NULL_HASH[16] =
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
/**
|
||||
* Populate VERSION structure.\n
|
||||
|
@ -66,13 +69,18 @@ void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
|
|||
* @param s
|
||||
*/
|
||||
|
||||
void ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return -1;
|
||||
|
||||
Stream_Read_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */
|
||||
Stream_Read_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */
|
||||
Stream_Read_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */
|
||||
Stream_Read(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */
|
||||
Stream_Read_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,7 +115,7 @@ void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo)
|
|||
fprintf(stderr, "\tNTLMRevisionCurrent: 0x%02X\n", versionInfo->NTLMRevisionCurrent);
|
||||
}
|
||||
|
||||
void ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
|
@ -121,10 +129,16 @@ void ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* cha
|
|||
|
||||
size = Stream_Length(s) - Stream_GetPosition(s);
|
||||
challenge->AvPairs = (NTLM_AV_PAIR*) malloc(size);
|
||||
|
||||
if (!challenge->AvPairs)
|
||||
return -1;
|
||||
|
||||
Stream_Read(s, challenge->AvPairs, size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
{
|
||||
ULONG length;
|
||||
|
||||
|
@ -138,57 +152,22 @@ void ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* ch
|
|||
|
||||
length = ntlm_av_pair_list_length(challenge->AvPairs);
|
||||
Stream_Write(s, challenge->AvPairs, length);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
{
|
||||
Stream_Read(s, response->Response, 16);
|
||||
ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
return ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
|
||||
void ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
{
|
||||
Stream_Write(s, response->Response, 16);
|
||||
ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
return ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/**
|
||||
* Output Restriction_Encoding.\n
|
||||
* Restriction_Encoding @msdn{cc236647}
|
||||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_output_restriction_encoding(NTLM_CONTEXT* context)
|
||||
{
|
||||
wStream* s;
|
||||
AV_PAIR* restrictions = &context->av_pairs->Restrictions;
|
||||
|
||||
BYTE machineID[32] =
|
||||
"\x3A\x15\x8E\xA6\x75\x82\xD8\xF7\x3E\x06\xFA\x7A\xB4\xDF\xFD\x43"
|
||||
"\x84\x6C\x02\x3A\xFD\x5A\x94\xFE\xCF\x97\x0F\x3D\x19\x2C\x38\x20";
|
||||
|
||||
restrictions->value = malloc(48);
|
||||
restrictions->length = 48;
|
||||
|
||||
s = PStreamAllocAttach(restrictions->value, restrictions->length);
|
||||
|
||||
Stream_Write_UINT32(s, 48); /* Size */
|
||||
Stream_Zero(s, 4); /* Z4 (set to zero) */
|
||||
|
||||
/* IntegrityLevel (bit 31 set to 1) */
|
||||
Stream_Write_UINT8(s, 1);
|
||||
Stream_Zero(s, 3);
|
||||
|
||||
Stream_Write_UINT32(s, 0x00002000); /* SubjectIntegrityLevel */
|
||||
Stream_Write(s, machineID, 32); /* MachineID */
|
||||
|
||||
PStreamFreeDetach(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get current time, in tenths of microseconds since midnight of January 1, 1601.
|
||||
* @param[out] timestamp 64-bit little-endian timestamp
|
||||
|
@ -224,20 +203,22 @@ void ntlm_generate_timestamp(NTLM_CONTEXT* context)
|
|||
ntlm_current_time(context->Timestamp);
|
||||
}
|
||||
|
||||
void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
WINPR_SAM* sam;
|
||||
WINPR_SAM_ENTRY* entry;
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
|
||||
sam = SamOpen(1);
|
||||
if (sam == NULL)
|
||||
return;
|
||||
sam = SamOpen(TRUE);
|
||||
|
||||
if (!sam)
|
||||
return -1;
|
||||
|
||||
entry = SamLookupUserW(sam,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2);
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2);
|
||||
|
||||
if (entry != NULL)
|
||||
if (entry)
|
||||
{
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
fprintf(stderr, "NTLM Hash:\n");
|
||||
|
@ -245,20 +226,20 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
|||
#endif
|
||||
|
||||
NTOWFv2FromHashW(entry->NtHash,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
|
||||
(BYTE*) hash);
|
||||
|
||||
SamFreeEntry(sam, entry);
|
||||
SamClose(sam);
|
||||
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
entry = SamLookupUserW(sam,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2, NULL, 0);
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, NULL, 0);
|
||||
|
||||
if (entry != NULL)
|
||||
if (entry)
|
||||
{
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
fprintf(stderr, "NTLM Hash:\n");
|
||||
|
@ -266,32 +247,44 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
|||
#endif
|
||||
|
||||
NTOWFv2FromHashW(entry->NtHash,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
|
||||
(BYTE*) hash);
|
||||
|
||||
SamFreeEntry(sam, entry);
|
||||
SamClose(sam);
|
||||
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: Could not find user in SAM database\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SamClose(sam);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
int status;
|
||||
int i, hn, ln;
|
||||
char* PasswordHash = NULL;
|
||||
UINT32 PasswordHashLength = 0;
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
|
||||
/* Password contains a password hash of length (PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR) */
|
||||
|
||||
PasswordHashLength = context->identity.PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR;
|
||||
ConvertFromUnicode(CP_UTF8, 0, context->identity.Password, PasswordHashLength, &PasswordHash, 0, NULL, NULL);
|
||||
PasswordHashLength = credentials->identity.PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR;
|
||||
|
||||
status = ConvertFromUnicode(CP_UTF8, 0, (LPCWSTR) credentials->identity.Password,
|
||||
PasswordHashLength, &PasswordHash, 0, NULL, NULL);
|
||||
|
||||
if (status <= 0)
|
||||
return -1;
|
||||
|
||||
CharUpperBuffA(PasswordHash, PasswordHashLength);
|
||||
|
||||
for (i = 0; i < 32; i += 2)
|
||||
|
@ -302,62 +295,83 @@ void ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
|||
}
|
||||
|
||||
free(PasswordHash);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
if (context->identity.PasswordLength > 256)
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
|
||||
if (memcmp(context->NtlmHash, NTLM_NULL_HASH, 16) != 0)
|
||||
{
|
||||
BYTE PasswordHash[16];
|
||||
|
||||
/* Special case for WinPR: password hash */
|
||||
ntlm_convert_password_hash(context, PasswordHash);
|
||||
|
||||
NTOWFv2FromHashW(PasswordHash,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
|
||||
NTOWFv2FromHashW(context->NtlmHash,
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
|
||||
(BYTE*) hash);
|
||||
}
|
||||
else if (context->identity.PasswordLength > 0)
|
||||
else if (credentials->identity.PasswordLength > 256)
|
||||
{
|
||||
NTOWFv2W((LPWSTR) context->identity.Password, context->identity.PasswordLength * 2,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2, (BYTE*) hash);
|
||||
/* Special case for WinPR: password hash */
|
||||
|
||||
if (ntlm_convert_password_hash(context, context->NtlmHash) < 0)
|
||||
return -1;
|
||||
|
||||
NTOWFv2FromHashW(context->NtlmHash,
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
|
||||
(BYTE*) hash);
|
||||
}
|
||||
else if (credentials->identity.PasswordLength > 0)
|
||||
{
|
||||
NTOWFv2W((LPWSTR) credentials->identity.Password, credentials->identity.PasswordLength * 2,
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, (BYTE*) hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
ntlm_fetch_ntlm_v2_hash(context, hash);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
char* response;
|
||||
char value[16];
|
||||
char ntlm_v2_hash[16];
|
||||
BYTE* response;
|
||||
BYTE value[16];
|
||||
|
||||
if (context->LmCompatibilityLevel < 2)
|
||||
{
|
||||
sspi_SecBufferAlloc(&context->LmChallengeResponse, 24);
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return -1;
|
||||
|
||||
ZeroMemory(context->LmChallengeResponse.pvBuffer, 24);
|
||||
return;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
ntlm_compute_ntlm_v2_hash(context, ntlm_v2_hash);
|
||||
|
||||
if (ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash) < 0)
|
||||
return -1;
|
||||
|
||||
/* Concatenate the server and client challenges */
|
||||
CopyMemory(value, context->ServerChallenge, 8);
|
||||
CopyMemory(&value[8], context->ClientChallenge, 8);
|
||||
|
||||
sspi_SecBufferAlloc(&context->LmChallengeResponse, 24);
|
||||
response = (char*) context->LmChallengeResponse.pvBuffer;
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return -1;
|
||||
|
||||
response = (BYTE*) context->LmChallengeResponse.pvBuffer;
|
||||
|
||||
/* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */
|
||||
HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, (void*) value, 16, (void*) response, NULL);
|
||||
HMAC(EVP_md5(), (void*) context->NtlmV2Hash, 16, (BYTE*) value, 16, (BYTE*) response, NULL);
|
||||
|
||||
/* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response (24 bytes) */
|
||||
CopyMemory(&response[16], context->ClientChallenge, 8);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -367,10 +381,9 @@ void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
|||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
BYTE* blob;
|
||||
BYTE ntlm_v2_hash[16];
|
||||
BYTE nt_proof_str[16];
|
||||
SecBuffer ntlm_v2_temp;
|
||||
SecBuffer ntlm_v2_temp_chal;
|
||||
|
@ -378,13 +391,16 @@ void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
|||
|
||||
TargetInfo = &context->ChallengeTargetInfo;
|
||||
|
||||
sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28);
|
||||
if (!sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28))
|
||||
return -1;
|
||||
|
||||
ZeroMemory(ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
blob = (BYTE*) ntlm_v2_temp.pvBuffer;
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
ntlm_compute_ntlm_v2_hash(context, (char*) ntlm_v2_hash);
|
||||
|
||||
if (ntlm_compute_ntlm_v2_hash(context, (BYTE*) context->NtlmV2Hash) < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
fprintf(stderr, "Password (length = %d)\n", context->identity.PasswordLength * 2);
|
||||
|
@ -404,7 +420,7 @@ void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
|||
fprintf(stderr, "\n");
|
||||
|
||||
fprintf(stderr, "NTOWFv2, NTLMv2 Hash\n");
|
||||
winpr_HexDump(ntlm_v2_hash, 16);
|
||||
winpr_HexDump(context->NtlmV2Hash, 16);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
|
@ -425,25 +441,33 @@ void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
|||
#endif
|
||||
|
||||
/* Concatenate server challenge with temp */
|
||||
sspi_SecBufferAlloc(&ntlm_v2_temp_chal, ntlm_v2_temp.cbBuffer + 8);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&ntlm_v2_temp_chal, ntlm_v2_temp.cbBuffer + 8))
|
||||
return -1;
|
||||
|
||||
blob = (BYTE*) ntlm_v2_temp_chal.pvBuffer;
|
||||
CopyMemory(blob, context->ServerChallenge, 8);
|
||||
CopyMemory(&blob[8], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
|
||||
HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, ntlm_v2_temp_chal.pvBuffer,
|
||||
ntlm_v2_temp_chal.cbBuffer, (void*) nt_proof_str, NULL);
|
||||
HMAC(EVP_md5(), (BYTE*) context->NtlmV2Hash, 16, (BYTE*) ntlm_v2_temp_chal.pvBuffer,
|
||||
ntlm_v2_temp_chal.cbBuffer, (BYTE*) nt_proof_str, NULL);
|
||||
|
||||
/* NtChallengeResponse, Concatenate NTProofStr with temp */
|
||||
sspi_SecBufferAlloc(&context->NtChallengeResponse, ntlm_v2_temp.cbBuffer + 16);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->NtChallengeResponse, ntlm_v2_temp.cbBuffer + 16))
|
||||
return -1;
|
||||
|
||||
blob = (BYTE*) context->NtChallengeResponse.pvBuffer;
|
||||
CopyMemory(blob, nt_proof_str, 16);
|
||||
CopyMemory(&blob[16], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
|
||||
/* Compute SessionBaseKey, the HMAC-MD5 hash of NTProofStr using the NTLMv2 hash as the key */
|
||||
HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, (void*) nt_proof_str, 16, (void*) context->SessionBaseKey, NULL);
|
||||
HMAC(EVP_md5(), (BYTE*) context->NtlmV2Hash, 16, (BYTE*) nt_proof_str, 16, (BYTE*) context->SessionBaseKey, NULL);
|
||||
|
||||
sspi_SecBufferFree(&ntlm_v2_temp);
|
||||
sspi_SecBufferFree(&ntlm_v2_temp_chal);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -548,7 +572,7 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
|||
* @param signing_key Destination signing key
|
||||
*/
|
||||
|
||||
void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, BYTE* signing_key)
|
||||
int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, BYTE* signing_key)
|
||||
{
|
||||
int length;
|
||||
BYTE* value;
|
||||
|
@ -557,6 +581,9 @@ void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic
|
|||
length = 16 + sign_magic->cbBuffer;
|
||||
value = (BYTE*) malloc(length);
|
||||
|
||||
if (!value)
|
||||
return -1;
|
||||
|
||||
/* Concatenate ExportedSessionKey with sign magic */
|
||||
CopyMemory(value, exported_session_key, 16);
|
||||
CopyMemory(&value[16], sign_magic->pvBuffer, sign_magic->cbBuffer);
|
||||
|
@ -566,6 +593,8 @@ void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic
|
|||
MD5_Final(signing_key, &md5);
|
||||
|
||||
free(value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -576,10 +605,12 @@ void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic
|
|||
|
||||
void ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer sign_magic;
|
||||
sign_magic.pvBuffer = (void*) client_sign_magic;
|
||||
sign_magic.cbBuffer = sizeof(client_sign_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sign_magic, context->ClientSigningKey);
|
||||
SecBuffer signMagic;
|
||||
|
||||
signMagic.pvBuffer = (void*) NTLM_CLIENT_SIGN_MAGIC;
|
||||
signMagic.cbBuffer = sizeof(NTLM_CLIENT_SIGN_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ClientSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -590,10 +621,12 @@ void ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
|||
|
||||
void ntlm_generate_server_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer sign_magic;
|
||||
sign_magic.pvBuffer = (void*) server_sign_magic;
|
||||
sign_magic.cbBuffer = sizeof(server_sign_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sign_magic, context->ServerSigningKey);
|
||||
SecBuffer signMagic;
|
||||
|
||||
signMagic.pvBuffer = (void*) NTLM_SERVER_SIGN_MAGIC;
|
||||
signMagic.cbBuffer = sizeof(NTLM_SERVER_SIGN_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ServerSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -604,13 +637,15 @@ void ntlm_generate_server_signing_key(NTLM_CONTEXT* context)
|
|||
* @param sealing_key Destination sealing key
|
||||
*/
|
||||
|
||||
void ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic, BYTE* sealing_key)
|
||||
int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic, BYTE* sealing_key)
|
||||
{
|
||||
BYTE* p;
|
||||
MD5_CTX md5;
|
||||
SecBuffer buffer;
|
||||
|
||||
sspi_SecBufferAlloc(&buffer, 16 + seal_magic->cbBuffer);
|
||||
if (!sspi_SecBufferAlloc(&buffer, 16 + seal_magic->cbBuffer))
|
||||
return -1;
|
||||
|
||||
p = (BYTE*) buffer.pvBuffer;
|
||||
|
||||
/* Concatenate ExportedSessionKey with seal magic */
|
||||
|
@ -622,6 +657,8 @@ void ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic
|
|||
MD5_Final(sealing_key, &md5);
|
||||
|
||||
sspi_SecBufferFree(&buffer);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -632,10 +669,12 @@ void ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic
|
|||
|
||||
void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer seal_magic;
|
||||
seal_magic.pvBuffer = (void*) client_seal_magic;
|
||||
seal_magic.cbBuffer = sizeof(client_seal_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &seal_magic, context->ClientSealingKey);
|
||||
SecBuffer sealMagic;
|
||||
|
||||
sealMagic.pvBuffer = (void*) NTLM_CLIENT_SEAL_MAGIC;
|
||||
sealMagic.cbBuffer = sizeof(NTLM_CLIENT_SEAL_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ClientSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -646,10 +685,12 @@ void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
|||
|
||||
void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer seal_magic;
|
||||
seal_magic.pvBuffer = (void*) server_seal_magic;
|
||||
seal_magic.cbBuffer = sizeof(server_seal_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &seal_magic, context->ServerSealingKey);
|
||||
SecBuffer sealMagic;
|
||||
|
||||
sealMagic.pvBuffer = (void*) NTLM_SERVER_SEAL_MAGIC;
|
||||
sealMagic.cbBuffer = sizeof(NTLM_SERVER_SEAL_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ServerSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -690,9 +731,9 @@ void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context)
|
|||
|
||||
HMAC_CTX_init(&hmac_ctx);
|
||||
HMAC_Init_ex(&hmac_ctx, context->ExportedSessionKey, 16, EVP_md5(), NULL);
|
||||
HMAC_Update(&hmac_ctx, context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, (BYTE*) context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, (BYTE*) context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, (BYTE*) context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer);
|
||||
HMAC_Final(&hmac_ctx, context->MessageIntegrityCheck, NULL);
|
||||
HMAC_CTX_cleanup(&hmac_ctx);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (Compute)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -25,24 +25,22 @@
|
|||
#include "ntlm_av_pairs.h"
|
||||
|
||||
void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
|
||||
void ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
void ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
|
||||
void ntlm_output_restriction_encoding(NTLM_CONTEXT* context);
|
||||
void ntlm_output_target_name(NTLM_CONTEXT* context);
|
||||
void ntlm_output_channel_bindings(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_current_time(BYTE* timestamp);
|
||||
void ntlm_generate_timestamp(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_compute_ntlm_hash(UINT16* password, UINT32 length, char* hash);
|
||||
void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash);
|
||||
void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
|
||||
void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
|
||||
int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash);
|
||||
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
|
||||
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext);
|
||||
void ntlm_generate_client_challenge(NTLM_CONTEXT* context);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (Message)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -29,4 +29,6 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
|
|||
SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer);
|
||||
SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer);
|
||||
|
||||
SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context);
|
||||
|
||||
#endif /* WINPR_SSPI_NTLM_MESSAGE_H */
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* Negotiate Security Package
|
||||
*
|
||||
* Copyright 2011-2012 Jiten Pathy
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -28,67 +28,27 @@
|
|||
|
||||
#include "../sspi.h"
|
||||
|
||||
extern const SecurityFunctionTableA NTLM_SecurityFunctionTableA;
|
||||
extern const SecurityFunctionTableW NTLM_SecurityFunctionTableW;
|
||||
|
||||
char* NEGOTIATE_PACKAGE_NAME = "Negotiate";
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
SEC_WCHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
SEC_CHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
CREDENTIALS* credentials;
|
||||
PSecBuffer output_SecBuffer;
|
||||
|
||||
context = sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = negotiate_ContextNew();
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
if ((!pInput) && (context->state == NEGOTIATE_STATE_INITIAL))
|
||||
{
|
||||
if (!pOutput)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (pOutput->cBuffers < 1)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
output_SecBuffer = &pOutput->pBuffers[0];
|
||||
|
||||
if (output_SecBuffer->cbBuffer < 1)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
|
||||
}
|
||||
|
||||
NEGOTIATE_CONTEXT* negotiate_ContextNew()
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) calloc(1, sizeof(NEGOTIATE_CONTEXT));
|
||||
|
||||
if (context != NULL)
|
||||
{
|
||||
context->NegotiateFlags = 0;
|
||||
context->state = NEGOTIATE_STATE_INITIAL;
|
||||
}
|
||||
if (!context)
|
||||
return NULL;
|
||||
|
||||
context->NegotiateFlags = 0;
|
||||
context->state = NEGOTIATE_STATE_INITIAL;
|
||||
|
||||
SecInvalidateHandle(&(context->SubContext));
|
||||
|
||||
context->sspiA = (SecurityFunctionTableA*) &NTLM_SecurityFunctionTableA;
|
||||
context->sspiW = (SecurityFunctionTableW*) &NTLM_SecurityFunctionTableW;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
@ -101,21 +61,262 @@ void negotiate_ContextFree(NEGOTIATE_CONTEXT* context)
|
|||
free(context);
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_QueryContextAttributes(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
SEC_WCHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = negotiate_ContextNew();
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
status = context->sspiW->InitializeSecurityContextW(phCredential, &(context->SubContext),
|
||||
pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, &(context->SubContext),
|
||||
pOutput, pfContextAttr, ptsExpiry);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
SEC_CHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = negotiate_ContextNew();
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
status = context->sspiA->InitializeSecurityContextA(phCredential, &(context->SubContext),
|
||||
pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, &(context->SubContext),
|
||||
pOutput, pfContextAttr, ptsExpiry);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
PSecBufferDesc pInput, ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = negotiate_ContextNew();
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
status = context->sspiA->AcceptSecurityContext(phCredential, &(context->SubContext),
|
||||
pInput, fContextReq, TargetDataRep, &(context->SubContext),
|
||||
pOutput, pfContextAttr, ptsTimeStamp);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_CompleteAuthToken(PCtxtHandle phContext, PSecBufferDesc pToken)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (context->sspiW->CompleteAuthToken)
|
||||
status = context->sspiW->CompleteAuthToken(phContext, pToken);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_DeleteSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (context->sspiW->DeleteSecurityContext)
|
||||
status = context->sspiW->DeleteSecurityContext(&(context->SubContext));
|
||||
|
||||
negotiate_ContextFree(context);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_ImpersonateSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (context->sspiW->ImpersonateSecurityContext)
|
||||
status = context->sspiW->ImpersonateSecurityContext(&(context->SubContext));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_RevertSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (context->sspiW->RevertSecurityContext)
|
||||
status = context->sspiW->RevertSecurityContext(&(context->SubContext));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_QueryContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
if (context->sspiW->QueryContextAttributesW)
|
||||
status = context->sspiW->QueryContextAttributesW(&(context->SubContext), ulAttribute, pBuffer);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_QueryContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (context->sspiA->QueryContextAttributesA)
|
||||
status = context->sspiA->QueryContextAttributesA(&(context->SubContext), ulAttribute, pBuffer);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_SetContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (context->sspiW->SetContextAttributesW)
|
||||
status = context->sspiW->SetContextAttributesW(&(context->SubContext), ulAttribute, pBuffer, cbBuffer);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_SetContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (context->sspiA->SetContextAttributesA)
|
||||
status = context->sspiA->SetContextAttributesA(&(context->SubContext), ulAttribute, pBuffer, cbBuffer);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage,
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SEC_WINNT_AUTH_IDENTITY* identity;
|
||||
|
||||
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_INBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_BOTH))
|
||||
{
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
credentials->fCredentialUse = fCredentialUse;
|
||||
credentials->pGetKeyFn = pGetKeyFn;
|
||||
credentials->pvGetKeyArgument = pvGetKeyArgument;
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity)
|
||||
sspi_CopyAuthIdentity(&(credentials->identity), identity);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
|
@ -123,52 +324,54 @@ SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleA(SEC_CHAR* pszPrinc
|
|||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SEC_WINNT_AUTH_IDENTITY* identity;
|
||||
|
||||
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
|
||||
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_INBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_BOTH))
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
memcpy(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
credentials->fCredentialUse = fCredentialUse;
|
||||
credentials->pGetKeyFn = pGetKeyFn;
|
||||
credentials->pvGetKeyArgument = pvGetKeyArgument;
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity)
|
||||
sspi_CopyAuthIdentity(&(credentials->identity), identity);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_QueryCredentialsAttributesW(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_QueryCredentialsAttributesA(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_FreeCredentialsHandle(PCredHandle phCredential)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
if (!phCredential)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
@ -180,22 +383,54 @@ SECURITY_STATUS SEC_ENTRY negotiate_FreeCredentialsHandle(PCredHandle phCredenti
|
|||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_UNSUPPORTED_FUNCTION;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (context->sspiW->EncryptMessage)
|
||||
status = context->sspiW->EncryptMessage(&(context->SubContext), fQOP, pMessage, MessageSeqNo);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_UNSUPPORTED_FUNCTION;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (context->sspiW->DecryptMessage)
|
||||
status = context->sspiW->DecryptMessage(&(context->SubContext), pMessage, MessageSeqNo, pfQOP);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_MakeSignature(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_UNSUPPORTED_FUNCTION;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (context->sspiW->MakeSignature)
|
||||
status = context->sspiW->MakeSignature(&(context->SubContext), fQOP, pMessage, MessageSeqNo);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_UNSUPPORTED_FUNCTION;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (context->sspiW->VerifySignature)
|
||||
status = context->sspiW->VerifySignature(&(context->SubContext), pMessage, MessageSeqNo, pfQOP);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
const SecurityFunctionTableA NEGOTIATE_SecurityFunctionTableA =
|
||||
|
@ -207,13 +442,13 @@ const SecurityFunctionTableA NEGOTIATE_SecurityFunctionTableA =
|
|||
negotiate_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
||||
NULL, /* Reserved2 */
|
||||
negotiate_InitializeSecurityContextA, /* InitializeSecurityContext */
|
||||
NULL, /* AcceptSecurityContext */
|
||||
NULL, /* CompleteAuthToken */
|
||||
NULL, /* DeleteSecurityContext */
|
||||
negotiate_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
negotiate_CompleteAuthToken, /* CompleteAuthToken */
|
||||
negotiate_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
NULL, /* ApplyControlToken */
|
||||
negotiate_QueryContextAttributes, /* QueryContextAttributes */
|
||||
NULL, /* ImpersonateSecurityContext */
|
||||
NULL, /* RevertSecurityContext */
|
||||
negotiate_QueryContextAttributesA, /* QueryContextAttributes */
|
||||
negotiate_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
|
||||
negotiate_RevertSecurityContext, /* RevertSecurityContext */
|
||||
negotiate_MakeSignature, /* MakeSignature */
|
||||
negotiate_VerifySignature, /* VerifySignature */
|
||||
NULL, /* FreeContextBuffer */
|
||||
|
@ -227,7 +462,7 @@ const SecurityFunctionTableA NEGOTIATE_SecurityFunctionTableA =
|
|||
NULL, /* QuerySecurityContextToken */
|
||||
negotiate_EncryptMessage, /* EncryptMessage */
|
||||
negotiate_DecryptMessage, /* DecryptMessage */
|
||||
NULL, /* SetContextAttributes */
|
||||
negotiate_SetContextAttributesA, /* SetContextAttributes */
|
||||
};
|
||||
|
||||
const SecurityFunctionTableW NEGOTIATE_SecurityFunctionTableW =
|
||||
|
@ -239,13 +474,13 @@ const SecurityFunctionTableW NEGOTIATE_SecurityFunctionTableW =
|
|||
negotiate_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
||||
NULL, /* Reserved2 */
|
||||
negotiate_InitializeSecurityContextW, /* InitializeSecurityContext */
|
||||
NULL, /* AcceptSecurityContext */
|
||||
NULL, /* CompleteAuthToken */
|
||||
NULL, /* DeleteSecurityContext */
|
||||
negotiate_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
negotiate_CompleteAuthToken, /* CompleteAuthToken */
|
||||
negotiate_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
NULL, /* ApplyControlToken */
|
||||
negotiate_QueryContextAttributes, /* QueryContextAttributes */
|
||||
NULL, /* ImpersonateSecurityContext */
|
||||
NULL, /* RevertSecurityContext */
|
||||
negotiate_QueryContextAttributesW, /* QueryContextAttributes */
|
||||
negotiate_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
|
||||
negotiate_RevertSecurityContext, /* RevertSecurityContext */
|
||||
negotiate_MakeSignature, /* MakeSignature */
|
||||
negotiate_VerifySignature, /* VerifySignature */
|
||||
NULL, /* FreeContextBuffer */
|
||||
|
@ -259,7 +494,7 @@ const SecurityFunctionTableW NEGOTIATE_SecurityFunctionTableW =
|
|||
NULL, /* QuerySecurityContextToken */
|
||||
negotiate_EncryptMessage, /* EncryptMessage */
|
||||
negotiate_DecryptMessage, /* DecryptMessage */
|
||||
NULL, /* SetContextAttributes */
|
||||
negotiate_SetContextAttributesW, /* SetContextAttributes */
|
||||
};
|
||||
|
||||
const SecPkgInfoA NEGOTIATE_SecPkgInfoA =
|
||||
|
|
|
@ -40,8 +40,12 @@ struct _NEGOTIATE_CONTEXT
|
|||
NEGOTIATE_STATE state;
|
||||
UINT32 NegotiateFlags;
|
||||
PCtxtHandle auth_ctx;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
SecBuffer NegoInitMessage;
|
||||
|
||||
CtxtHandle SubContext;
|
||||
|
||||
SecurityFunctionTableA* sspiA;
|
||||
SecurityFunctionTableW* sspiW;
|
||||
};
|
||||
typedef struct _NEGOTIATE_CONTEXT NEGOTIATE_CONTEXT;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* Schannel Security Package
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* Schannel Security Package (OpenSSL)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -280,7 +280,7 @@ SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context
|
|||
|
||||
if (status > 0)
|
||||
{
|
||||
if (pBuffer->cbBuffer < status)
|
||||
if (pBuffer->cbBuffer < (unsigned long) status)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
CopyMemory(pBuffer->pvBuffer, context->ReadBuffer, status);
|
||||
|
@ -339,7 +339,7 @@ SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context
|
|||
|
||||
if (status > 0)
|
||||
{
|
||||
if (pBuffer->cbBuffer < status)
|
||||
if (pBuffer->cbBuffer < (unsigned long) status)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
CopyMemory(pBuffer->pvBuffer, context->ReadBuffer, status);
|
||||
|
@ -387,17 +387,17 @@ SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSec
|
|||
if (status > 0)
|
||||
{
|
||||
offset = 0;
|
||||
length = (pStreamHeaderBuffer->cbBuffer > status) ? status : pStreamHeaderBuffer->cbBuffer;
|
||||
length = (pStreamHeaderBuffer->cbBuffer > (unsigned long) status) ? status : pStreamHeaderBuffer->cbBuffer;
|
||||
CopyMemory(pStreamHeaderBuffer->pvBuffer, &context->ReadBuffer[offset], length);
|
||||
status -= length;
|
||||
|
||||
offset += length;
|
||||
length = (pStreamBodyBuffer->cbBuffer > status) ? status : pStreamBodyBuffer->cbBuffer;
|
||||
length = (pStreamBodyBuffer->cbBuffer > (unsigned long) status) ? status : pStreamBodyBuffer->cbBuffer;
|
||||
CopyMemory(pStreamBodyBuffer->pvBuffer, &context->ReadBuffer[offset], length);
|
||||
status -= length;
|
||||
|
||||
offset += length;
|
||||
length = (pStreamTrailerBuffer->cbBuffer > status) ? status : pStreamTrailerBuffer->cbBuffer;
|
||||
length = (pStreamTrailerBuffer->cbBuffer > (unsigned long) status) ? status : pStreamTrailerBuffer->cbBuffer;
|
||||
CopyMemory(pStreamTrailerBuffer->pvBuffer, &context->ReadBuffer[offset], length);
|
||||
status -= length;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,34 @@
|
|||
LIBRARY "libwinpr-sspi"
|
||||
EXPORTS
|
||||
|
||||
AcceptSecurityContext
|
||||
AcquireCredentialsHandleA
|
||||
AcquireCredentialsHandleW
|
||||
ApplyControlToken
|
||||
CompleteAuthToken
|
||||
DecryptMessage
|
||||
DeleteSecurityContext
|
||||
EncryptMessage
|
||||
EnumerateSecurityPackagesA
|
||||
EnumerateSecurityPackagesW
|
||||
ExportSecurityContext
|
||||
FreeContextBuffer
|
||||
FreeCredentialsHandle
|
||||
ImpersonateSecurityContext
|
||||
ImportSecurityContextA
|
||||
ImportSecurityContextW
|
||||
InitSecurityInterfaceA
|
||||
InitSecurityInterfaceW
|
||||
InitializeSecurityContextA
|
||||
InitializeSecurityContextW
|
||||
MakeSignature
|
||||
QueryContextAttributesA
|
||||
QueryContextAttributesW
|
||||
QueryCredentialsAttributesA
|
||||
QueryCredentialsAttributesW
|
||||
QuerySecurityContextToken
|
||||
QuerySecurityPackageInfoA
|
||||
QuerySecurityPackageInfoW
|
||||
RevertSecurityContext
|
||||
VerifySignature
|
||||
InitSecurityInterfaceExA
|
||||
InitSecurityInterfaceExW
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@
|
|||
* WinPR: Windows Portable Runtime
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -28,20 +28,22 @@
|
|||
|
||||
#define SSPI_CREDENTIALS_HASH_LENGTH_FACTOR 64
|
||||
|
||||
struct _CREDENTIALS
|
||||
struct _SSPI_CREDENTIALS
|
||||
{
|
||||
DWORD flags;
|
||||
ULONG fCredentialUse;
|
||||
SEC_GET_KEY_FN pGetKeyFn;
|
||||
void* pvGetKeyArgument;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
};
|
||||
typedef struct _CREDENTIALS CREDENTIALS;
|
||||
typedef struct _SSPI_CREDENTIALS SSPI_CREDENTIALS;
|
||||
|
||||
CREDENTIALS* sspi_CredentialsNew(void);
|
||||
void sspi_CredentialsFree(CREDENTIALS* credentials);
|
||||
SSPI_CREDENTIALS* sspi_CredentialsNew(void);
|
||||
void sspi_CredentialsFree(SSPI_CREDENTIALS* credentials);
|
||||
|
||||
PSecBuffer sspi_FindSecBuffer(PSecBufferDesc pMessage, ULONG BufferType);
|
||||
|
||||
SecHandle* sspi_SecureHandleAlloc(void);
|
||||
void sspi_SecureHandleInit(SecHandle* handle);
|
||||
void sspi_SecureHandleInvalidate(SecHandle* handle);
|
||||
void* sspi_SecureHandleGetLowerPointer(SecHandle* handle);
|
||||
void sspi_SecureHandleSetLowerPointer(SecHandle* handle, void* pointer);
|
||||
|
@ -81,4 +83,6 @@ enum SecurityFunctionTableIndex
|
|||
SetContextAttributesIndex = 28
|
||||
};
|
||||
|
||||
#include "sspi_winpr.h"
|
||||
|
||||
#endif /* WINPR_SSPI_PRIVATE_H */
|
||||
|
|
|
@ -0,0 +1,289 @@
|
|||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SEC_ENTRY __stdcall
|
||||
#define SSPI_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define SEC_ENTRY
|
||||
#define SSPI_EXPORT
|
||||
#endif
|
||||
|
||||
typedef long LONG;
|
||||
typedef unsigned long ULONG;
|
||||
typedef LONG SECURITY_STATUS;
|
||||
|
||||
/**
|
||||
* Standard SSPI API
|
||||
*/
|
||||
|
||||
/* Package Management */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_EnumerateSecurityPackagesW(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY EnumerateSecurityPackagesW(void* pcPackages, void* ppPackageInfo)
|
||||
{
|
||||
return sspi_EnumerateSecurityPackagesW(pcPackages, ppPackageInfo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_EnumerateSecurityPackagesA(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY EnumerateSecurityPackagesA(void* pcPackages, void* ppPackageInfo)
|
||||
{
|
||||
return sspi_EnumerateSecurityPackagesA(pcPackages, ppPackageInfo);
|
||||
}
|
||||
|
||||
extern void* SEC_ENTRY sspi_InitSecurityInterfaceW(void);
|
||||
|
||||
SSPI_EXPORT void* SEC_ENTRY InitSecurityInterfaceW(void)
|
||||
{
|
||||
return sspi_InitSecurityInterfaceW();
|
||||
}
|
||||
|
||||
extern void* SEC_ENTRY sspi_InitSecurityInterfaceA(void);
|
||||
|
||||
SSPI_EXPORT void* SEC_ENTRY InitSecurityInterfaceA(void)
|
||||
{
|
||||
return sspi_InitSecurityInterfaceA();
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityPackageInfoW(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QuerySecurityPackageInfoW(void* pszPackageName, void* ppPackageInfo)
|
||||
{
|
||||
return sspi_QuerySecurityPackageInfoW(pszPackageName, ppPackageInfo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityPackageInfoA(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QuerySecurityPackageInfoA(void* pszPackageName, void* ppPackageInfo)
|
||||
{
|
||||
return sspi_QuerySecurityPackageInfoA(pszPackageName, ppPackageInfo);
|
||||
}
|
||||
|
||||
/* Credential Management */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_AcquireCredentialsHandleW(void*, void*, ULONG, void*, void*, void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY AcquireCredentialsHandleW(void* pszPrincipal, void* pszPackage,
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, void* pGetKeyFn,
|
||||
void* pvGetKeyArgument, void* phCredential, void* ptsExpiry)
|
||||
{
|
||||
return sspi_AcquireCredentialsHandleW(pszPrincipal, pszPackage, fCredentialUse,
|
||||
pvLogonID, pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential, ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_AcquireCredentialsHandleA(void*, void*, ULONG, void*, void*, void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY AcquireCredentialsHandleA(void* pszPrincipal, void* pszPackage,
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, void* pGetKeyFn,
|
||||
void* pvGetKeyArgument, void* phCredential, void* ptsExpiry)
|
||||
{
|
||||
return sspi_AcquireCredentialsHandleA(pszPrincipal, pszPackage, fCredentialUse,
|
||||
pvLogonID, pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential, ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ExportSecurityContext(void*, ULONG, void*, void**);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ExportSecurityContext(void* phContext, ULONG fFlags, void* pPackedContext, void** pToken)
|
||||
{
|
||||
return sspi_ExportSecurityContext(phContext, fFlags, pPackedContext, pToken);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_FreeCredentialsHandle(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY FreeCredentialsHandle(void* phCredential)
|
||||
{
|
||||
return sspi_FreeCredentialsHandle(phCredential);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ImportSecurityContextW(void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ImportSecurityContextW(void* pszPackage, void* pPackedContext, void* pToken, void* phContext)
|
||||
{
|
||||
return sspi_ImportSecurityContextW(pszPackage, pPackedContext, pToken, phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ImportSecurityContextA(void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ImportSecurityContextA(void* pszPackage, void* pPackedContext, void* pToken, void* phContext)
|
||||
{
|
||||
return sspi_ImportSecurityContextA(pszPackage, pPackedContext, pToken, phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryCredentialsAttributesW(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryCredentialsAttributesW(void* phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return sspi_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryCredentialsAttributesA(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryCredentialsAttributesA(void* phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return sspi_QueryCredentialsAttributesA(phCredential, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
/* Context Management */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_AcceptSecurityContext(void*, void*, void*, ULONG, ULONG, void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY AcceptSecurityContext(void* phCredential, void* phContext,
|
||||
void* pInput, ULONG fContextReq, ULONG TargetDataRep, void* phNewContext,
|
||||
void* pOutput, void* pfContextAttr, void* ptsTimeStamp)
|
||||
{
|
||||
return sspi_AcceptSecurityContext(phCredential, phContext, pInput, fContextReq,
|
||||
TargetDataRep, phNewContext, pOutput, pfContextAttr, ptsTimeStamp);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ApplyControlToken(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ApplyControlToken(void* phContext, void* pInput)
|
||||
{
|
||||
return sspi_ApplyControlToken(phContext, pInput);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_CompleteAuthToken(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY CompleteAuthToken(void* phContext, void* pToken)
|
||||
{
|
||||
return sspi_CompleteAuthToken(phContext, pToken);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_DeleteSecurityContext(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY DeleteSecurityContext(void* phContext)
|
||||
{
|
||||
return sspi_DeleteSecurityContext(phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_FreeContextBuffer(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY FreeContextBuffer(void* pvContextBuffer)
|
||||
{
|
||||
return sspi_FreeContextBuffer(pvContextBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ImpersonateSecurityContext(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ImpersonateSecurityContext(void* phContext)
|
||||
{
|
||||
return sspi_ImpersonateSecurityContext(phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_InitializeSecurityContextW(void*, void*, void*, ULONG, ULONG, ULONG,
|
||||
void*, ULONG, void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY InitializeSecurityContextW(void* phCredential, void* phContext,
|
||||
void* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
void* pInput, ULONG Reserved2, void* phNewContext,
|
||||
void* pOutput, void* pfContextAttr, void* ptsExpiry)
|
||||
{
|
||||
return sspi_InitializeSecurityContextW(phCredential, phContext, pszTargetName, fContextReq, Reserved1,
|
||||
TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_InitializeSecurityContextA(void*, void*, void*, ULONG, ULONG, ULONG,
|
||||
void*, ULONG, void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY InitializeSecurityContextA(void* phCredential, void* phContext,
|
||||
void* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
void* pInput, ULONG Reserved2, void* phNewContext,
|
||||
void* pOutput, void* pfContextAttr, void* ptsExpiry)
|
||||
{
|
||||
return sspi_InitializeSecurityContextA(phCredential, phContext, pszTargetName, fContextReq, Reserved1,
|
||||
TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryContextAttributesW(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryContextAttributesW(void* phContext, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return sspi_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryContextAttributesA(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryContextAttributesA(void* phContext, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return sspi_QueryContextAttributesA(phContext, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityContextToken(void*, void**);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QuerySecurityContextToken(void* phContext, void** phToken)
|
||||
{
|
||||
return sspi_QuerySecurityContextToken(phContext, phToken);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_SetContextAttributesW(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY SetContextAttributesW(void* phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
return sspi_SetContextAttributesW(phContext, ulAttribute, pBuffer, cbBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_SetContextAttributesA(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY SetContextAttributesA(void* phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
return sspi_SetContextAttributesA(phContext, ulAttribute, pBuffer, cbBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_RevertSecurityContext(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY RevertSecurityContext(void* phContext)
|
||||
{
|
||||
return sspi_RevertSecurityContext(phContext);
|
||||
}
|
||||
|
||||
/* Message Support */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_DecryptMessage(void*, void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY DecryptMessage(void* phContext, void* pMessage, ULONG MessageSeqNo, void* pfQOP)
|
||||
{
|
||||
return sspi_DecryptMessage(phContext, pMessage, MessageSeqNo, pfQOP);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_EncryptMessage(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY EncryptMessage(void* phContext, ULONG fQOP, void* pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return sspi_EncryptMessage(phContext, fQOP, pMessage, MessageSeqNo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_MakeSignature(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY MakeSignature(void* phContext, ULONG fQOP, void* pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return sspi_MakeSignature(phContext, fQOP, pMessage, MessageSeqNo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_VerifySignature(void*, void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY VerifySignature(void* phContext, void* pMessage, ULONG MessageSeqNo, void* pfQOP)
|
||||
{
|
||||
return sspi_VerifySignature(phContext, pMessage, MessageSeqNo, pfQOP);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_SSPI_WINPR_H
|
||||
#define WINPR_SSPI_WINPR_H
|
||||
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
SecurityFunctionTableW* SEC_ENTRY winpr_InitSecurityInterfaceW(void);
|
||||
SecurityFunctionTableA* SEC_ENTRY winpr_InitSecurityInterfaceA(void);
|
||||
|
||||
#endif /* WINPR_SSPI_WINPR_H */
|
|
@ -9,8 +9,9 @@ set(${MODULE_PREFIX}_TESTS
|
|||
TestEnumerateSecurityPackages.c
|
||||
TestInitializeSecurityContext.c
|
||||
TestAcquireCredentialsHandle.c
|
||||
TestNTLM.c
|
||||
)
|
||||
TestCredSSP.c
|
||||
TestSchannel.c
|
||||
TestNTLM.c)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_DRIVER}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
int TestCredSSP(int argc, char* argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
|
@ -1,59 +1,546 @@
|
|||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
BYTE test_Certificate[] =
|
||||
"\x30\x82\x02\x09\x30\x82\x01\x76\xa0\x03\x02\x01\x02\x02\x10\xcb"
|
||||
"\x69\x79\xcd\x51\x75\xc5\xb7\x4b\x67\x30\x83\x6c\x78\x44\x27\x30"
|
||||
"\x09\x06\x05\x2b\x0e\x03\x02\x1d\x05\x00\x30\x16\x31\x14\x30\x12"
|
||||
"\x06\x03\x55\x04\x03\x13\x0b\x44\x43\x2d\x57\x53\x32\x30\x30\x38"
|
||||
"\x52\x32\x30\x1e\x17\x0d\x31\x32\x31\x31\x31\x37\x30\x30\x35\x39"
|
||||
"\x32\x31\x5a\x17\x0d\x33\x39\x31\x32\x33\x31\x32\x33\x35\x39\x35"
|
||||
"\x39\x5a\x30\x16\x31\x14\x30\x12\x06\x03\x55\x04\x03\x13\x0b\x44"
|
||||
"\x43\x2d\x57\x53\x32\x30\x30\x38\x52\x32\x30\x81\x9f\x30\x0d\x06"
|
||||
"\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00"
|
||||
"\x30\x81\x89\x02\x81\x81\x00\x9b\x00\xf8\x1a\x2d\x37\xc6\x8d\xa1"
|
||||
"\x39\x91\x46\xf3\x6a\x1b\xf9\x60\x6c\xb3\x6c\xa0\xac\xed\x85\xe0"
|
||||
"\x3f\xdc\x92\x86\x36\xbd\x64\xbf\x36\x51\xdb\x57\x3a\x8a\x82\x6b"
|
||||
"\xd8\x94\x17\x7b\xd3\x91\x11\x98\xef\x19\x06\x52\x30\x03\x73\x67"
|
||||
"\xc8\xed\x8e\xfa\x0b\x3d\x4c\xc9\x10\x63\x9f\xcf\xb4\xcf\x39\xd8"
|
||||
"\xfe\x99\xeb\x5b\x11\xf2\xfc\xfa\x86\x24\xd9\xff\xd9\x19\xf5\x69"
|
||||
"\xb4\xdf\x5a\x5a\xc4\x94\xb4\xb0\x07\x25\x97\x13\xad\x7e\x38\x14"
|
||||
"\xfb\xd6\x33\x65\x6f\xe6\xf7\x48\x4b\x2d\xb3\x51\x2e\x6d\xc7\xea"
|
||||
"\x11\x76\x9a\x2b\xf0\x00\x4d\x02\x03\x01\x00\x01\xa3\x60\x30\x5e"
|
||||
"\x30\x13\x06\x03\x55\x1d\x25\x04\x0c\x30\x0a\x06\x08\x2b\x06\x01"
|
||||
"\x05\x05\x07\x03\x01\x30\x47\x06\x03\x55\x1d\x01\x04\x40\x30\x3e"
|
||||
"\x80\x10\xeb\x65\x26\x03\x95\x4b\xd6\xc0\x54\x75\x78\x7c\xb6\x2a"
|
||||
"\xa1\xbb\xa1\x18\x30\x16\x31\x14\x30\x12\x06\x03\x55\x04\x03\x13"
|
||||
"\x0b\x44\x43\x2d\x57\x53\x32\x30\x30\x38\x52\x32\x82\x10\xcb\x69"
|
||||
"\x79\xcd\x51\x75\xc5\xb7\x4b\x67\x30\x83\x6c\x78\x44\x27\x30\x09"
|
||||
"\x06\x05\x2b\x0e\x03\x02\x1d\x05\x00\x03\x81\x81\x00\x7b\xfa\xfe"
|
||||
"\xee\x74\x05\xac\xbb\x79\xe9\xda\xca\x00\x44\x96\x94\x71\x92\xb1"
|
||||
"\xdb\xc9\x9b\x71\x29\xc0\xe4\x28\x5e\x6a\x50\x99\xcd\xa8\x17\xe4"
|
||||
"\x56\xb9\xef\x7f\x02\x7d\x96\xa3\x48\x14\x72\x75\x2f\xb0\xb5\x87"
|
||||
"\xee\x55\xe9\x6a\x6d\x28\x3c\xc1\xfd\x00\xe4\x76\xe3\x80\x88\x78"
|
||||
"\x26\x0d\x6c\x8c\xb8\x64\x61\x63\xb7\x13\x3a\xab\xc7\xdd\x1d\x0a"
|
||||
"\xd7\x15\x45\xa1\xd6\xd9\x34\xc7\x21\x48\xfb\x43\x87\x38\xda\x1f"
|
||||
"\x50\x47\xb1\xa5\x5c\x47\xed\x04\x44\x97\xd3\xac\x74\x2d\xeb\x09"
|
||||
"\x77\x59\xbf\xa3\x54\x5b\xde\x42\xd5\x23\x5a\x71\x9f";
|
||||
#define TEST_SSPI_INTERFACE SSPI_INTERFACE_WINPR
|
||||
|
||||
BYTE test_Certificate_SHA256Hash[] =
|
||||
"\xea\x05\xfe\xfe\xcc\x6b\x0b\xd5\x71\xdb\xbc\x5b\xaa\x3e\xd4\x53"
|
||||
"\x86\xd0\x44\x68\x35\xf7\xb7\x4c\x85\x62\x1b\x99\x83\x47\x5f\x95";
|
||||
static const char* TEST_NTLM_USER = "Username";
|
||||
static const char* TEST_NTLM_DOMAIN = "Domain";
|
||||
static const char* TEST_NTLM_PASSWORD = "P4ss123!";
|
||||
|
||||
BYTE test_ChannelBindings_MD5Hash[] =
|
||||
"\x65\x86\xE9\x9D\x81\xC2\xFC\x98\x4E\x47\x17\x2F\xD4\xDD\x03\x10";
|
||||
//static const char* TEST_NTLM_HASH_STRING = "d5922a65c4d5c082ca444af1be0001db";
|
||||
|
||||
int test_ntlm_channel_binding_token()
|
||||
static const BYTE TEST_NTLM_HASH[16] =
|
||||
{ 0xd5, 0x92, 0x2a, 0x65, 0xc4, 0xd5, 0xc0, 0x82, 0xca, 0x44, 0x4a, 0xf1, 0xbe, 0x00, 0x01, 0xdb };
|
||||
|
||||
//#define NTLM_PACKAGE_NAME NEGOSSP_NAME
|
||||
#define NTLM_PACKAGE_NAME NTLMSP_NAME
|
||||
|
||||
struct _TEST_NTLM_CLIENT
|
||||
{
|
||||
CtxtHandle context;
|
||||
ULONG cbMaxToken;
|
||||
ULONG fContextReq;
|
||||
ULONG pfContextAttr;
|
||||
TimeStamp expiration;
|
||||
PSecBuffer pBuffer;
|
||||
SecBuffer inputBuffer[2];
|
||||
SecBuffer outputBuffer[2];
|
||||
BOOL haveContext;
|
||||
BOOL haveInputBuffer;
|
||||
LPTSTR ServicePrincipalName;
|
||||
SecBufferDesc inputBufferDesc;
|
||||
SecBufferDesc outputBufferDesc;
|
||||
CredHandle credentials;
|
||||
BOOL confidentiality;
|
||||
SecPkgInfo* pPackageInfo;
|
||||
SecurityFunctionTable* table;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
};
|
||||
typedef struct _TEST_NTLM_CLIENT TEST_NTLM_CLIENT;
|
||||
|
||||
return 0;
|
||||
int test_ntlm_client_init(TEST_NTLM_CLIENT* ntlm, const char* user, const char* domain, const char* password)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
|
||||
SecInvalidateHandle(&(ntlm->context));
|
||||
|
||||
ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
|
||||
|
||||
sspi_SetAuthIdentity(&(ntlm->identity), user, domain, password);
|
||||
|
||||
status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
fprintf(stderr, "QuerySecurityPackageInfo status: %s (0x%04X)\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
|
||||
|
||||
status = ntlm->table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME,
|
||||
SECPKG_CRED_OUTBOUND, NULL, &ntlm->identity, NULL, NULL, &ntlm->credentials, &ntlm->expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
fprintf(stderr, "AcquireCredentialsHandle status: %s (0x%04X)\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->haveContext = FALSE;
|
||||
ntlm->haveInputBuffer = FALSE;
|
||||
ZeroMemory(&ntlm->inputBuffer, sizeof(SecBuffer));
|
||||
ZeroMemory(&ntlm->outputBuffer, sizeof(SecBuffer));
|
||||
|
||||
ntlm->fContextReq = 0;
|
||||
|
||||
#if 0
|
||||
/* HTTP authentication flags */
|
||||
ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY;
|
||||
#endif
|
||||
|
||||
/* NLA authentication flags */
|
||||
ntlm->fContextReq |= ISC_REQ_MUTUAL_AUTH;
|
||||
ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY;
|
||||
ntlm->fContextReq |= ISC_REQ_USE_SESSION_KEY;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void test_ntlm_client_uninit(TEST_NTLM_CLIENT* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
if (ntlm->outputBuffer[0].pvBuffer)
|
||||
{
|
||||
free(ntlm->outputBuffer[0].pvBuffer);
|
||||
ntlm->outputBuffer[0].pvBuffer = NULL;
|
||||
}
|
||||
|
||||
free(ntlm->identity.User);
|
||||
free(ntlm->identity.Domain);
|
||||
free(ntlm->identity.Password);
|
||||
free(ntlm->ServicePrincipalName);
|
||||
|
||||
if (ntlm->table)
|
||||
{
|
||||
ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
|
||||
ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
|
||||
ntlm->table->DeleteSecurityContext(&ntlm->context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SSPI Client Ceremony
|
||||
*
|
||||
* --------------
|
||||
* ( Client Begin )
|
||||
* --------------
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* -----------+--------------
|
||||
* | AcquireCredentialsHandle |
|
||||
* --------------------------
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* -------------+--------------
|
||||
* +---------------> / InitializeSecurityContext /
|
||||
* | ----------------------------
|
||||
* | |
|
||||
* | |
|
||||
* | \|/
|
||||
* --------------------------- ---------+------------- ----------------------
|
||||
* / Receive blob from server / < Received security blob? > --Yes-> / Send blob to server /
|
||||
* -------------+------------- ----------------------- ----------------------
|
||||
* /|\ | |
|
||||
* | No |
|
||||
* Yes \|/ |
|
||||
* | ------------+----------- |
|
||||
* +---------------- < Received Continue Needed > <-----------------+
|
||||
* ------------------------
|
||||
* |
|
||||
* No
|
||||
* \|/
|
||||
* ------+-------
|
||||
* ( Client End )
|
||||
* --------------
|
||||
*/
|
||||
|
||||
int test_ntlm_client_authenticate(TEST_NTLM_CLIENT* ntlm)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
|
||||
if (ntlm->outputBuffer[0].pvBuffer)
|
||||
{
|
||||
free(ntlm->outputBuffer[0].pvBuffer);
|
||||
ntlm->outputBuffer[0].pvBuffer = NULL;
|
||||
}
|
||||
|
||||
ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->outputBufferDesc.cBuffers = 1;
|
||||
ntlm->outputBufferDesc.pBuffers = ntlm->outputBuffer;
|
||||
ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
|
||||
ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
|
||||
|
||||
if (!ntlm->outputBuffer[0].pvBuffer)
|
||||
return -1;
|
||||
|
||||
if (ntlm->haveInputBuffer)
|
||||
{
|
||||
ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->inputBufferDesc.cBuffers = 1;
|
||||
ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
|
||||
ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
}
|
||||
|
||||
if ((!ntlm) || (!ntlm->table))
|
||||
{
|
||||
fprintf(stderr, "ntlm_authenticate: invalid ntlm context\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = ntlm->table->InitializeSecurityContext(&ntlm->credentials,
|
||||
(ntlm->haveContext) ? &ntlm->context : NULL,
|
||||
(ntlm->ServicePrincipalName) ? ntlm->ServicePrincipalName : NULL,
|
||||
ntlm->fContextReq, 0, SECURITY_NATIVE_DREP,
|
||||
(ntlm->haveInputBuffer) ? &ntlm->inputBufferDesc : NULL,
|
||||
0, &ntlm->context, &ntlm->outputBufferDesc,
|
||||
&ntlm->pfContextAttr, &ntlm->expiration);
|
||||
|
||||
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
|
||||
{
|
||||
if (ntlm->table->CompleteAuthToken)
|
||||
ntlm->table->CompleteAuthToken(&ntlm->context, &ntlm->outputBufferDesc);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
status = SEC_E_OK;
|
||||
else if (status == SEC_I_COMPLETE_AND_CONTINUE)
|
||||
status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
if (ntlm->haveInputBuffer)
|
||||
{
|
||||
free(ntlm->inputBuffer[0].pvBuffer);
|
||||
}
|
||||
|
||||
ntlm->haveInputBuffer = TRUE;
|
||||
ntlm->haveContext = TRUE;
|
||||
|
||||
return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
|
||||
}
|
||||
|
||||
TEST_NTLM_CLIENT* test_ntlm_client_new()
|
||||
{
|
||||
TEST_NTLM_CLIENT* ntlm;
|
||||
|
||||
ntlm = (TEST_NTLM_CLIENT*) calloc(1, sizeof(TEST_NTLM_CLIENT));
|
||||
|
||||
if (!ntlm)
|
||||
return NULL;
|
||||
|
||||
return ntlm;
|
||||
}
|
||||
|
||||
void test_ntlm_client_free(TEST_NTLM_CLIENT* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
test_ntlm_client_uninit(ntlm);
|
||||
|
||||
free(ntlm);
|
||||
}
|
||||
|
||||
struct _TEST_NTLM_SERVER
|
||||
{
|
||||
CtxtHandle context;
|
||||
ULONG cbMaxToken;
|
||||
ULONG fContextReq;
|
||||
ULONG pfContextAttr;
|
||||
TimeStamp expiration;
|
||||
PSecBuffer pBuffer;
|
||||
SecBuffer inputBuffer[2];
|
||||
SecBuffer outputBuffer[2];
|
||||
BOOL haveContext;
|
||||
BOOL haveInputBuffer;
|
||||
LPTSTR ServicePrincipalName;
|
||||
SecBufferDesc inputBufferDesc;
|
||||
SecBufferDesc outputBufferDesc;
|
||||
CredHandle credentials;
|
||||
BOOL confidentiality;
|
||||
SecPkgInfo* pPackageInfo;
|
||||
SecurityFunctionTable* table;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
};
|
||||
typedef struct _TEST_NTLM_SERVER TEST_NTLM_SERVER;
|
||||
|
||||
int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
|
||||
SecInvalidateHandle(&(ntlm->context));
|
||||
|
||||
ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
|
||||
|
||||
status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
fprintf(stderr, "QuerySecurityPackageInfo status: %s (0x%04X)\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
|
||||
|
||||
status = ntlm->table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME,
|
||||
SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL,
|
||||
&ntlm->credentials, &ntlm->expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
fprintf(stderr, "AcquireCredentialsHandle status: %s (0x%04X)\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->haveContext = FALSE;
|
||||
ntlm->haveInputBuffer = FALSE;
|
||||
ZeroMemory(&ntlm->inputBuffer, sizeof(SecBuffer));
|
||||
ZeroMemory(&ntlm->outputBuffer, sizeof(SecBuffer));
|
||||
|
||||
ntlm->fContextReq = 0;
|
||||
|
||||
/* NLA authentication flags */
|
||||
ntlm->fContextReq |= ASC_REQ_MUTUAL_AUTH;
|
||||
ntlm->fContextReq |= ASC_REQ_CONFIDENTIALITY;
|
||||
ntlm->fContextReq |= ASC_REQ_CONNECTION;
|
||||
ntlm->fContextReq |= ASC_REQ_USE_SESSION_KEY;
|
||||
ntlm->fContextReq |= ASC_REQ_REPLAY_DETECT;
|
||||
ntlm->fContextReq |= ASC_REQ_SEQUENCE_DETECT;
|
||||
ntlm->fContextReq |= ASC_REQ_EXTENDED_ERROR;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void test_ntlm_server_uninit(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
if (ntlm->outputBuffer[0].pvBuffer)
|
||||
{
|
||||
free(ntlm->outputBuffer[0].pvBuffer);
|
||||
ntlm->outputBuffer[0].pvBuffer = NULL;
|
||||
}
|
||||
|
||||
free(ntlm->identity.User);
|
||||
free(ntlm->identity.Domain);
|
||||
free(ntlm->identity.Password);
|
||||
free(ntlm->ServicePrincipalName);
|
||||
|
||||
if (ntlm->table)
|
||||
{
|
||||
ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
|
||||
ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
|
||||
ntlm->table->DeleteSecurityContext(&ntlm->context);
|
||||
}
|
||||
}
|
||||
|
||||
int test_ntlm_server_authenticate(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
|
||||
ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->inputBufferDesc.cBuffers = 1;
|
||||
ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
|
||||
ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
|
||||
ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->outputBufferDesc.cBuffers = 1;
|
||||
ntlm->outputBufferDesc.pBuffers = &ntlm->outputBuffer[0];
|
||||
ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
|
||||
ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
|
||||
|
||||
status = ntlm->table->AcceptSecurityContext(&ntlm->credentials,
|
||||
ntlm->haveContext? &ntlm->context: NULL,
|
||||
&ntlm->inputBufferDesc, ntlm->fContextReq, SECURITY_NATIVE_DREP, &ntlm->context,
|
||||
&ntlm->outputBufferDesc, &ntlm->pfContextAttr, &ntlm->expiration);
|
||||
|
||||
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
|
||||
{
|
||||
SecPkgContext_AuthIdentity AuthIdentity;
|
||||
SecPkgContext_AuthNtlmHash AuthNtlmHash;
|
||||
|
||||
ZeroMemory(&AuthIdentity, sizeof(SecPkgContext_AuthIdentity));
|
||||
ZeroMemory(&AuthNtlmHash, sizeof(SecPkgContext_AuthNtlmHash));
|
||||
|
||||
status = ntlm->table->QueryContextAttributes(&ntlm->context, SECPKG_ATTR_AUTH_IDENTITY, &AuthIdentity);
|
||||
|
||||
if (status == SEC_E_OK)
|
||||
{
|
||||
if (strcmp(AuthIdentity.User, TEST_NTLM_USER) == 0)
|
||||
{
|
||||
CopyMemory(AuthNtlmHash.NtlmHash, TEST_NTLM_HASH, 16);
|
||||
|
||||
status = ntlm->table->SetContextAttributes(&ntlm->context,
|
||||
SECPKG_ATTR_AUTH_NTLM_HASH, &AuthNtlmHash, sizeof(SecPkgContext_AuthNtlmHash));
|
||||
}
|
||||
}
|
||||
|
||||
if (ntlm->table->CompleteAuthToken)
|
||||
status = ntlm->table->CompleteAuthToken(&ntlm->context, &ntlm->outputBufferDesc);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
status = SEC_E_OK;
|
||||
else if (status == SEC_I_COMPLETE_AND_CONTINUE)
|
||||
status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
|
||||
{
|
||||
fprintf(stderr, "AcceptSecurityContext status: %s (0x%04X)\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1; /* Access Denied */
|
||||
}
|
||||
|
||||
ntlm->haveContext = TRUE;
|
||||
|
||||
return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
|
||||
}
|
||||
|
||||
TEST_NTLM_SERVER* test_ntlm_server_new()
|
||||
{
|
||||
TEST_NTLM_SERVER* ntlm;
|
||||
|
||||
ntlm = (TEST_NTLM_SERVER*) calloc(1, sizeof(TEST_NTLM_SERVER));
|
||||
|
||||
if (!ntlm)
|
||||
return NULL;
|
||||
|
||||
return ntlm;
|
||||
}
|
||||
|
||||
void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
test_ntlm_server_uninit(ntlm);
|
||||
|
||||
free(ntlm);
|
||||
}
|
||||
|
||||
int TestNTLM(int argc, char* argv[])
|
||||
{
|
||||
if (test_ntlm_channel_binding_token() < 0)
|
||||
int status;
|
||||
PSecBuffer pSecBuffer;
|
||||
TEST_NTLM_CLIENT* client;
|
||||
TEST_NTLM_SERVER* server;
|
||||
|
||||
/**
|
||||
* Client Initialization
|
||||
*/
|
||||
|
||||
client = test_ntlm_client_new();
|
||||
|
||||
status = test_ntlm_client_init(client, TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_client_init failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server Initialization
|
||||
*/
|
||||
|
||||
server = test_ntlm_server_new();
|
||||
|
||||
status = test_ntlm_server_init(server);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_server_init failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client -> Negotiate Message
|
||||
*/
|
||||
|
||||
status = test_ntlm_client_authenticate(client);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_client_authenticate failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pSecBuffer = &(client->outputBuffer[0]);
|
||||
|
||||
fprintf(stderr, "NTLM_NEGOTIATE (length = %d):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
/**
|
||||
* Server <- Negotiate Message
|
||||
* Server -> Challenge Message
|
||||
*/
|
||||
|
||||
server->haveInputBuffer = TRUE;
|
||||
server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
|
||||
server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
|
||||
|
||||
status = test_ntlm_server_authenticate(server);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_server_authenticate failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pSecBuffer = &(server->outputBuffer[0]);
|
||||
|
||||
fprintf(stderr, "NTLM_CHALLENGE (length = %d):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
/**
|
||||
* Client <- Challenge Message
|
||||
* Client -> Authenticate Message
|
||||
*/
|
||||
|
||||
client->haveInputBuffer = TRUE;
|
||||
client->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
client->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
|
||||
client->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
|
||||
|
||||
status = test_ntlm_client_authenticate(client);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_client_authenticate failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pSecBuffer = &(client->outputBuffer[0]);
|
||||
|
||||
fprintf(stderr, "NTLM_AUTHENTICATE (length = %d):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
/**
|
||||
* Server <- Authenticate Message
|
||||
*/
|
||||
|
||||
server->haveInputBuffer = TRUE;
|
||||
server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
|
||||
server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
|
||||
|
||||
status = test_ntlm_server_authenticate(server);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_server_authenticate failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup & Termination
|
||||
*/
|
||||
|
||||
test_ntlm_client_free(client);
|
||||
test_ntlm_server_free(server);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -273,7 +273,7 @@ int schannel_send(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phCont
|
|||
|
||||
printf("EncryptMessage status: 0x%08X\n", status);
|
||||
|
||||
printf("EncryptMessage output: cBuffers: %ld [0]: %lu / %lu [1]: %lu / %lu [2]: %lu / %lu [3]: %lu / %lu\n", Message.cBuffers,
|
||||
printf("EncryptMessage output: cBuffers: %d [0]: %u / %u [1]: %u / %u [2]: %u / %u [3]: %u / %u\n", Message.cBuffers,
|
||||
Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType,
|
||||
Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType,
|
||||
Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType,
|
||||
|
@ -342,7 +342,7 @@ int schannel_recv(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phCont
|
|||
|
||||
printf("DecryptMessage status: 0x%08X\n", status);
|
||||
|
||||
printf("DecryptMessage output: cBuffers: %ld [0]: %lu / %lu [1]: %lu / %lu [2]: %lu / %lu [3]: %lu / %lu\n", Message.cBuffers,
|
||||
printf("DecryptMessage output: cBuffers: %d [0]: %u / %u [1]: %u / %u [2]: %u / %u [3]: %u / %u\n", Message.cBuffers,
|
||||
Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType,
|
||||
Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType,
|
||||
Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType,
|
||||
|
@ -351,7 +351,7 @@ int schannel_recv(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phCont
|
|||
if (status != SEC_E_OK)
|
||||
return -1;
|
||||
|
||||
printf("Decrypted Message (%ld)\n", Message.pBuffers[1].cbBuffer);
|
||||
printf("Decrypted Message (%d)\n", Message.pBuffers[1].cbBuffer);
|
||||
winpr_HexDump((BYTE*) Message.pBuffers[1].pvBuffer, Message.pBuffers[1].cbBuffer);
|
||||
|
||||
if (memcmp(Message.pBuffers[1].pvBuffer, test_LastDummyMessage, sizeof(test_LastDummyMessage)) == 0)
|
||||
|
@ -522,9 +522,9 @@ static void* schannel_test_server_thread(void* arg)
|
|||
else if (status == SEC_E_INCOMPLETE_MESSAGE)
|
||||
printf("AcceptSecurityContext status: SEC_E_INCOMPLETE_MESSAGE\n");
|
||||
|
||||
printf("Server cBuffers: %lu pBuffers[0]: %lu type: %lu\n",
|
||||
printf("Server cBuffers: %u pBuffers[0]: %u type: %u\n",
|
||||
SecBufferDesc_out.cBuffers, SecBufferDesc_out.pBuffers[0].cbBuffer, SecBufferDesc_out.pBuffers[0].BufferType);
|
||||
printf("Server Input cBuffers: %ld pBuffers[0]: %lu type: %lu pBuffers[1]: %lu type: %lu\n", SecBufferDesc_in.cBuffers,
|
||||
printf("Server Input cBuffers: %d pBuffers[0]: %u type: %u pBuffers[1]: %u type: %u\n", SecBufferDesc_in.cBuffers,
|
||||
SecBufferDesc_in.pBuffers[0].cbBuffer, SecBufferDesc_in.pBuffers[0].BufferType,
|
||||
SecBufferDesc_in.pBuffers[1].cbBuffer, SecBufferDesc_in.pBuffers[1].BufferType);
|
||||
|
||||
|
@ -543,7 +543,7 @@ static void* schannel_test_server_thread(void* arg)
|
|||
|
||||
if (pSecBuffer->cbBuffer > 0)
|
||||
{
|
||||
printf("Server > Client (%ld)\n", pSecBuffer->cbBuffer);
|
||||
printf("Server > Client (%d)\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
if (!WriteFile(g_ClientWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer, &NumberOfBytesWritten, NULL))
|
||||
|
@ -615,7 +615,7 @@ int dump_test_certificate_files()
|
|||
int TestSchannel(int argc, char* argv[])
|
||||
{
|
||||
int count;
|
||||
int index;
|
||||
DWORD index;
|
||||
ALG_ID algId;
|
||||
HANDLE thread;
|
||||
BYTE* lpTokenIn;
|
||||
|
@ -641,6 +641,8 @@ int TestSchannel(int argc, char* argv[])
|
|||
SecPkgCred_CipherStrengths CipherStrengths;
|
||||
SecPkgCred_SupportedProtocols SupportedProtocols;
|
||||
|
||||
return 0; /* disable by default - causes crash */
|
||||
|
||||
sspi_GlobalInit();
|
||||
|
||||
dump_test_certificate_files();
|
||||
|
@ -713,7 +715,7 @@ int TestSchannel(int argc, char* argv[])
|
|||
* 0x800C 0x800D 0x800E 0x2400 0xAA02 0xAE06 0x2200 0x2203
|
||||
*/
|
||||
|
||||
printf("SupportedAlgs: %ld\n", SupportedAlgs.cSupportedAlgs);
|
||||
printf("SupportedAlgs: %d\n", SupportedAlgs.cSupportedAlgs);
|
||||
|
||||
for (index = 0; index < SupportedAlgs.cSupportedAlgs; index++)
|
||||
{
|
||||
|
@ -734,7 +736,7 @@ int TestSchannel(int argc, char* argv[])
|
|||
|
||||
/* CipherStrengths: Minimum: 40 Maximum: 256 */
|
||||
|
||||
printf("CipherStrengths: Minimum: %ld Maximum: %ld\n",
|
||||
printf("CipherStrengths: Minimum: %d Maximum: %d\n",
|
||||
CipherStrengths.dwMinimumCipherStrength, CipherStrengths.dwMaximumCipherStrength);
|
||||
|
||||
ZeroMemory(&SupportedProtocols, sizeof(SecPkgCred_SupportedProtocols));
|
||||
|
@ -748,7 +750,7 @@ int TestSchannel(int argc, char* argv[])
|
|||
|
||||
/* SupportedProtocols: 0x208A0 */
|
||||
|
||||
printf("SupportedProtocols: 0x%04lX\n", SupportedProtocols.grbitProtocol);
|
||||
printf("SupportedProtocols: 0x%04X\n", SupportedProtocols.grbitProtocol);
|
||||
|
||||
fContextReq = ISC_REQ_STREAM |
|
||||
ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
||||
|
@ -781,7 +783,7 @@ int TestSchannel(int argc, char* argv[])
|
|||
}
|
||||
|
||||
g_ClientWait = TRUE;
|
||||
printf("NumberOfBytesRead: %ld\n", NumberOfBytesRead);
|
||||
printf("NumberOfBytesRead: %d\n", NumberOfBytesRead);
|
||||
|
||||
SecBuffer_in[0].BufferType = SECBUFFER_TOKEN;
|
||||
SecBuffer_in[0].pvBuffer = lpTokenIn;
|
||||
|
@ -821,9 +823,9 @@ int TestSchannel(int argc, char* argv[])
|
|||
else if (status == SEC_E_INCOMPLETE_MESSAGE)
|
||||
printf("InitializeSecurityContext status: SEC_E_INCOMPLETE_MESSAGE\n");
|
||||
|
||||
printf("Client Output cBuffers: %ld pBuffers[0]: %ld type: %ld\n",
|
||||
printf("Client Output cBuffers: %d pBuffers[0]: %d type: %d\n",
|
||||
SecBufferDesc_out.cBuffers, SecBufferDesc_out.pBuffers[0].cbBuffer, SecBufferDesc_out.pBuffers[0].BufferType);
|
||||
printf("Client Input cBuffers: %ld pBuffers[0]: %ld type: %ld pBuffers[1]: %ld type: %ld\n", SecBufferDesc_in.cBuffers,
|
||||
printf("Client Input cBuffers: %d pBuffers[0]: %d type: %d pBuffers[1]: %d type: %d\n", SecBufferDesc_in.cBuffers,
|
||||
SecBufferDesc_in.pBuffers[0].cbBuffer, SecBufferDesc_in.pBuffers[0].BufferType,
|
||||
SecBufferDesc_in.pBuffers[1].cbBuffer, SecBufferDesc_in.pBuffers[1].BufferType);
|
||||
|
||||
|
@ -833,7 +835,7 @@ int TestSchannel(int argc, char* argv[])
|
|||
|
||||
if (pSecBuffer->cbBuffer > 0)
|
||||
{
|
||||
printf("Client > Server (%ld)\n", pSecBuffer->cbBuffer);
|
||||
printf("Client > Server (%d)\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
if (!WriteFile(g_ServerWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer, &NumberOfBytesWritten, NULL))
|
||||
|
|
|
@ -271,8 +271,11 @@ int GetEventFileDescriptor(HANDLE hEvent)
|
|||
if (Type == HANDLE_TYPE_NAMED_PIPE)
|
||||
{
|
||||
WINPR_NAMED_PIPE *named = (WINPR_NAMED_PIPE *)hEvent;
|
||||
if (named->ServerMode)
|
||||
if (named->ServerMode) {
|
||||
return named->serverfd;
|
||||
} else {
|
||||
return named->clientfd;
|
||||
}
|
||||
}
|
||||
|
||||
return event->pipe_fd[0];
|
||||
|
|
|
@ -35,41 +35,19 @@
|
|||
* api-ms-win-core-sysinfo-l1-1-1.dll:
|
||||
*
|
||||
* EnumSystemFirmwareTables
|
||||
* GetComputerNameExA
|
||||
* GetComputerNameExW
|
||||
* GetDynamicTimeZoneInformation
|
||||
* GetLocalTime
|
||||
* GetSystemFirmwareTable
|
||||
* GetLogicalProcessorInformation
|
||||
* GetLogicalProcessorInformationEx
|
||||
* GetSystemInfo
|
||||
* GetNativeSystemInfo
|
||||
* GetProductInfo
|
||||
* GetSystemDirectoryA
|
||||
* GetSystemDirectoryW
|
||||
* GetSystemFirmwareTable
|
||||
* GetSystemTime
|
||||
* GetSystemTimeAdjustment
|
||||
* GetSystemTimeAsFileTime
|
||||
* GetSystemWindowsDirectoryA
|
||||
* GetSystemWindowsDirectoryW
|
||||
* GetTickCount
|
||||
* GetTickCount64
|
||||
* GetTimeZoneInformation
|
||||
* GetTimeZoneInformationForYear
|
||||
* GetVersion
|
||||
* GetVersionExA
|
||||
* GetVersionExW
|
||||
* GetWindowsDirectoryA
|
||||
* GetWindowsDirectoryW
|
||||
* GlobalMemoryStatusEx
|
||||
* SetComputerNameExW
|
||||
* SetDynamicTimeZoneInformation
|
||||
* SetLocalTime
|
||||
* SetSystemTime
|
||||
* SetTimeZoneInformation
|
||||
* SystemTimeToFileTime
|
||||
* SystemTimeToTzSpecificLocalTime
|
||||
* TzSpecificLocalTimeToSystemTime
|
||||
* VerSetConditionMask
|
||||
*/
|
||||
|
||||
|
@ -296,6 +274,68 @@ BOOL GetVersionExW(LPOSVERSIONINFOW lpVersionInformation)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void GetSystemTime(LPSYSTEMTIME lpSystemTime)
|
||||
{
|
||||
time_t ct = 0;
|
||||
struct tm* stm = NULL;
|
||||
WORD wMilliseconds = 0;
|
||||
|
||||
ct = time(NULL);
|
||||
wMilliseconds = (WORD) (GetTickCount() % 1000);
|
||||
|
||||
stm = gmtime(&ct);
|
||||
|
||||
ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
|
||||
|
||||
if (stm)
|
||||
{
|
||||
lpSystemTime->wYear = (WORD) (stm->tm_year + 1900);
|
||||
lpSystemTime->wMonth = (WORD) (stm->tm_mon + 1);
|
||||
lpSystemTime->wDayOfWeek = (WORD) stm->tm_wday;
|
||||
lpSystemTime->wDay = (WORD) stm->tm_mday;
|
||||
lpSystemTime->wHour = (WORD) stm->tm_hour;
|
||||
lpSystemTime->wMinute = (WORD) stm->tm_min;
|
||||
lpSystemTime->wSecond = (WORD) stm->tm_sec;
|
||||
lpSystemTime->wMilliseconds = wMilliseconds;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL SetSystemTime(CONST SYSTEMTIME* lpSystemTime)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID GetLocalTime(LPSYSTEMTIME lpSystemTime)
|
||||
{
|
||||
time_t ct = 0;
|
||||
struct tm* ltm = NULL;
|
||||
WORD wMilliseconds = 0;
|
||||
|
||||
ct = time(NULL);
|
||||
wMilliseconds = (WORD) (GetTickCount() % 1000);
|
||||
|
||||
ltm = localtime(&ct);
|
||||
|
||||
ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
|
||||
|
||||
if (ltm)
|
||||
{
|
||||
lpSystemTime->wYear = (WORD) (ltm->tm_year + 1900);
|
||||
lpSystemTime->wMonth = (WORD) (ltm->tm_mon + 1);
|
||||
lpSystemTime->wDayOfWeek = (WORD) ltm->tm_wday;
|
||||
lpSystemTime->wDay = (WORD) ltm->tm_mday;
|
||||
lpSystemTime->wHour = (WORD) ltm->tm_hour;
|
||||
lpSystemTime->wMinute = (WORD) ltm->tm_min;
|
||||
lpSystemTime->wSecond = (WORD) ltm->tm_sec;
|
||||
lpSystemTime->wMilliseconds = wMilliseconds;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL SetLocalTime(CONST SYSTEMTIME* lpSystemTime)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
|
||||
{
|
||||
ULARGE_INTEGER time64;
|
||||
|
@ -311,6 +351,11 @@ VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
|
|||
lpSystemTimeAsFileTime->dwHighDateTime = time64.HighPart;
|
||||
}
|
||||
|
||||
BOOL GetSystemTimeAdjustment(PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement, PBOOL lpTimeAdjustmentDisabled)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifndef CLOCK_MONOTONIC_RAW
|
||||
#define CLOCK_MONOTONIC_RAW 4
|
||||
#endif
|
||||
|
@ -606,6 +651,7 @@ BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature)
|
|||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif //_WIN32
|
||||
|
||||
BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue