Merge remote-tracking branch 'origin/master' into tsmf-gstreamer-1.0

Conflicts:
	client/X11/xf_client.c
This commit is contained in:
Armin Novak 2014-06-11 11:27:08 +02:00
commit 4325741583
111 changed files with 9780 additions and 2439 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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, "}");
}

View File

@ -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)

View File

@ -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);

View File

@ -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))

View File

@ -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})

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 */

40
include/freerdp/metrics.h Normal file
View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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
*/

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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>

59
libfreerdp/core/metrics.c Normal file
View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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) */

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;
{
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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:

View File

@ -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;
}

View File

@ -1 +1 @@
TestFreeRDPutils.c
TestFreeRDPUtils.c

View File

@ -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 */

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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 */

View File

@ -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
}

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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
*/

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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 */

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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 =

View File

@ -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 =

View File

@ -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;

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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

View File

@ -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 */

View File

@ -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 =

View File

@ -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;

View File

@ -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.

View File

@ -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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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}

View File

@ -0,0 +1,8 @@
#include <winpr/crt.h>
#include <winpr/sspi.h>
int TestCredSSP(int argc, char* argv[])
{
return 0;
}

View File

@ -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;
}

View File

@ -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))

View File

@ -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];

View File

@ -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