diff --git a/include/freerdp/codec/nsc.h b/include/freerdp/codec/nsc.h index 21e575ad2..cb16570db 100644 --- a/include/freerdp/codec/nsc.h +++ b/include/freerdp/codec/nsc.h @@ -77,8 +77,8 @@ struct _NSC_CONTEXT /* color palette allocated by the application */ const BYTE* palette; - void (*decode)(NSC_CONTEXT* context); - void (*encode)(NSC_CONTEXT* context, const BYTE* BitmapData, + BOOL (*decode)(NSC_CONTEXT* context); + BOOL (*encode)(NSC_CONTEXT* context, const BYTE* BitmapData, UINT32 rowstride); NSC_CONTEXT_PRIV* priv; diff --git a/include/freerdp/codec/zgfx.h b/include/freerdp/codec/zgfx.h index b5c65319c..b0faf6e0d 100644 --- a/include/freerdp/codec/zgfx.h +++ b/include/freerdp/codec/zgfx.h @@ -32,34 +32,18 @@ #define ZGFX_SEGMENTED_MAXSIZE 65535 -struct _ZGFX_CONTEXT -{ - BOOL Compressor; - - const BYTE* pbInputCurrent; - const BYTE* pbInputEnd; - - UINT32 bits; - UINT32 cBitsRemaining; - UINT32 BitsCurrent; - UINT32 cBitsCurrent; - - BYTE OutputBuffer[65536]; - UINT32 OutputCount; - - BYTE HistoryBuffer[2500000]; - UINT32 HistoryIndex; - UINT32 HistoryBufferSize; -}; typedef struct _ZGFX_CONTEXT ZGFX_CONTEXT; #ifdef __cplusplus extern "C" { #endif -FREERDP_API int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags); -FREERDP_API int zgfx_compress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags); -FREERDP_API int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, const BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags); +FREERDP_API int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, UINT32* pDstSize, UINT32 flags); +FREERDP_API int zgfx_compress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags); +FREERDP_API int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, + const BYTE* pUncompressed, UINT32 uncompressedSize, UINT32* pFlags); FREERDP_API void zgfx_context_reset(ZGFX_CONTEXT* zgfx, BOOL flush); @@ -71,4 +55,4 @@ FREERDP_API void zgfx_context_free(ZGFX_CONTEXT* zgfx); #endif #endif /* FREERDP_CODEC_ZGFX_H */ - + diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index d0547cd33..bad0aec1c 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -42,13 +42,24 @@ #define NSC_INIT_SIMD(_nsc_context) do { } while (0) #endif -static void nsc_decode(NSC_CONTEXT* context) +static BOOL nsc_decode(NSC_CONTEXT* context) { UINT16 x; UINT16 y; - UINT16 rw = ROUND_UP_TO(context->width, 8); - BYTE shift = context->ColorLossLevel - 1; /* colorloss recovery + YCoCg shift */ - BYTE* bmpdata = context->BitmapData; + UINT16 rw; + BYTE shift; + BYTE* bmpdata; + size_t pos = 0; + + if (!context) + return FALSE; + + rw = ROUND_UP_TO(context->width, 8); + shift = context->ColorLossLevel - 1; /* colorloss recovery + YCoCg shift */ + bmpdata = context->BitmapData; + + if (!bmpdata) + return FALSE; for (y = 0; y < context->height; y++) { @@ -80,6 +91,11 @@ static void nsc_decode(NSC_CONTEXT* context) INT16 r_val = y_val + co_val - cg_val; INT16 g_val = y_val + cg_val; INT16 b_val = y_val - co_val - cg_val; + + if (pos + 4 > context->BitmapDataLength) + return FALSE; + + pos += 4; *bmpdata++ = MINMAX(b_val, 0, 0xFF); *bmpdata++ = MINMAX(g_val, 0, 0xFF); *bmpdata++ = MINMAX(r_val, 0, 0xFF); @@ -90,9 +106,11 @@ static void nsc_decode(NSC_CONTEXT* context) aplane++; } } + + return TRUE; } -static void nsc_rle_decode(BYTE* in, BYTE* out, UINT32 originalSize) +static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalSize) { UINT32 len; UINT32 left; @@ -105,6 +123,10 @@ static void nsc_rle_decode(BYTE* in, BYTE* out, UINT32 originalSize) if (left == 5) { + if (outSize < 1) + return FALSE; + + outSize--; *out++ = value; left--; } @@ -124,26 +146,42 @@ static void nsc_rle_decode(BYTE* in, BYTE* out, UINT32 originalSize) in += 4; } + if (outSize < len) + return FALSE; + + outSize -= len; FillMemory(out, len, value); out += len; left -= len; } else { + if (outSize < 1) + return FALSE; + + outSize--; *out++ = value; left--; } } - *((UINT32*)out) = *((UINT32*)in); + if ((outSize < 4) || (left < 4)) + return FALSE; + + memcpy(out, in, 4); + return TRUE; } -static void nsc_rle_decompress_data(NSC_CONTEXT* context) +static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context) { UINT16 i; BYTE* rle; UINT32 planeSize; UINT32 originalSize; + + if (!context) + return FALSE; + rle = context->Planes; for (i = 0; i < 4; i++) @@ -152,14 +190,30 @@ static void nsc_rle_decompress_data(NSC_CONTEXT* context) planeSize = context->PlaneByteCount[i]; if (planeSize == 0) + { + if (context->priv->PlaneBuffersLength < originalSize) + return FALSE; + FillMemory(context->priv->PlaneBuffers[i], originalSize, 0xFF); + } else if (planeSize < originalSize) - nsc_rle_decode(rle, context->priv->PlaneBuffers[i], originalSize); + { + if (!nsc_rle_decode(rle, context->priv->PlaneBuffers[i], context->priv->PlaneBuffersLength, + originalSize)) + return FALSE; + } else + { + if (context->priv->PlaneBuffersLength < originalSize) + return FALSE; + CopyMemory(context->priv->PlaneBuffers[i], rle, originalSize); + } rle += planeSize; } + + return TRUE; } static BOOL nsc_stream_initialize(NSC_CONTEXT* context, wStream* s) @@ -396,13 +450,25 @@ BOOL nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, return FALSE; /* RLE decode */ - PROFILER_ENTER(context->priv->prof_nsc_rle_decompress_data) - nsc_rle_decompress_data(context); - PROFILER_EXIT(context->priv->prof_nsc_rle_decompress_data) + { + BOOL rc; + PROFILER_ENTER(context->priv->prof_nsc_rle_decompress_data) + rc = nsc_rle_decompress_data(context); + PROFILER_EXIT(context->priv->prof_nsc_rle_decompress_data) + + if (!rc) + return FALSE; + } /* Colorloss recover, Chroma supersample and AYCoCg to ARGB Conversion in one step */ - PROFILER_ENTER(context->priv->prof_nsc_decode) - context->decode(context); - PROFILER_EXIT(context->priv->prof_nsc_decode) + { + BOOL rc; + PROFILER_ENTER(context->priv->prof_nsc_decode) + rc = context->decode(context); + PROFILER_EXIT(context->priv->prof_nsc_decode) + + if (!rc) + return FALSE; + } if (!freerdp_image_copy(pDstData, DstFormat, nDstStride, nXDst, nYDst, width, height, context->BitmapData, diff --git a/libfreerdp/codec/nsc_encode.c b/libfreerdp/codec/nsc_encode.c index 492f170dc..d2456fb93 100644 --- a/libfreerdp/codec/nsc_encode.c +++ b/libfreerdp/codec/nsc_encode.c @@ -51,6 +51,7 @@ static BOOL nsc_context_initialize_encode(NSC_CONTEXT* context) for (i = 0; i < 5; i++) { BYTE* tmp = (BYTE*) realloc(context->priv->PlaneBuffers[i], length); + if (!tmp) goto fail; @@ -87,7 +88,7 @@ fail: return FALSE; } -static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, const BYTE* data, +static BOOL nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, const BYTE* data, UINT32 scanline) { UINT16 x; @@ -104,10 +105,20 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, const BYTE* data, INT16 b_val; BYTE a_val; UINT32 tempWidth; + + if (!context || data || (scanline == 0)) + return FALSE; + tempWidth = ROUND_UP_TO(context->width, 8); rw = (context->ChromaSubsamplingLevel ? tempWidth : context->width); ccl = context->ColorLossLevel; + if (context->priv->PlaneBuffersLength < rw * scanline) + return FALSE; + + if (rw < scanline * 2) + return FALSE; + for (y = 0; y < context->height; y++) { src = data + (context->height - 1 - y) * scanline; @@ -242,31 +253,37 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, const BYTE* data, CopyMemory(coplane, coplane - rw, rw); CopyMemory(cgplane, cgplane - rw, rw); } + + return TRUE; } -static void nsc_encode_subsampling(NSC_CONTEXT* context) +static BOOL nsc_encode_subsampling(NSC_CONTEXT* context) { UINT16 x; UINT16 y; - BYTE* co_dst; - BYTE* cg_dst; - INT8* co_src0; - INT8* co_src1; - INT8* cg_src0; - INT8* cg_src1; UINT32 tempWidth; UINT32 tempHeight; + + if (!context) + return FALSE; + tempWidth = ROUND_UP_TO(context->width, 8); tempHeight = ROUND_UP_TO(context->height, 2); + if (tempHeight == 0) + return FALSE; + + if (tempWidth > context->priv->PlaneBuffersLength / tempHeight) + return FALSE; + for (y = 0; y < tempHeight >> 1; y++) { - co_dst = context->priv->PlaneBuffers[1] + y * (tempWidth >> 1); - cg_dst = context->priv->PlaneBuffers[2] + y * (tempWidth >> 1); - co_src0 = (INT8*) context->priv->PlaneBuffers[1] + (y << 1) * tempWidth; - co_src1 = co_src0 + tempWidth; - cg_src0 = (INT8*) context->priv->PlaneBuffers[2] + (y << 1) * tempWidth; - cg_src1 = cg_src0 + tempWidth; + BYTE* co_dst = context->priv->PlaneBuffers[1] + y * (tempWidth >> 1); + BYTE* cg_dst = context->priv->PlaneBuffers[2] + y * (tempWidth >> 1); + const INT8* co_src0 = (INT8*) context->priv->PlaneBuffers[1] + (y << 1) * tempWidth; + const INT8* co_src1 = co_src0 + tempWidth; + const INT8* cg_src0 = (INT8*) context->priv->PlaneBuffers[2] + (y << 1) * tempWidth; + const INT8* cg_src1 = cg_src0 + tempWidth; for (x = 0; x < tempWidth >> 1; x++) { @@ -280,19 +297,28 @@ static void nsc_encode_subsampling(NSC_CONTEXT* context) cg_src1 += 2; } } + + return TRUE; } -void nsc_encode(NSC_CONTEXT* context, const BYTE* bmpdata, UINT32 rowstride) +BOOL nsc_encode(NSC_CONTEXT* context, const BYTE* bmpdata, UINT32 rowstride) { - nsc_encode_argb_to_aycocg(context, bmpdata, rowstride); + if (!context || !bmpdata || (rowstride == 0)) + return FALSE; + + if (!nsc_encode_argb_to_aycocg(context, bmpdata, rowstride)) + return FALSE; if (context->ChromaSubsamplingLevel) { - nsc_encode_subsampling(context); + if (!nsc_encode_subsampling(context)) + return FALSE; } + + return TRUE; } -static UINT32 nsc_rle_encode(BYTE* in, BYTE* out, UINT32 originalSize) +static UINT32 nsc_rle_encode(const BYTE* in, BYTE* out, UINT32 originalSize) { UINT32 left; UINT32 runlength = 1; diff --git a/libfreerdp/codec/nsc_encode.h b/libfreerdp/codec/nsc_encode.h index e220de407..784ccb6e3 100644 --- a/libfreerdp/codec/nsc_encode.h +++ b/libfreerdp/codec/nsc_encode.h @@ -24,7 +24,7 @@ #include -FREERDP_LOCAL void nsc_encode(NSC_CONTEXT* context, const BYTE* bmpdata, +FREERDP_LOCAL BOOL nsc_encode(NSC_CONTEXT* context, const BYTE* bmpdata, UINT32 rowstride); #endif /* FREERDP_LIB_CODEC_NSC_ENCODE_H */ diff --git a/libfreerdp/codec/nsc_sse2.c b/libfreerdp/codec/nsc_sse2.c index 149e80a83..966525f16 100644 --- a/libfreerdp/codec/nsc_sse2.c +++ b/libfreerdp/codec/nsc_sse2.c @@ -385,7 +385,7 @@ static void nsc_encode_subsampling_sse2(NSC_CONTEXT* context) } } -static void nsc_encode_sse2(NSC_CONTEXT* context, const BYTE* data, +static BOOL nsc_encode_sse2(NSC_CONTEXT* context, const BYTE* data, UINT32 scanline) { nsc_encode_argb_to_aycocg_sse2(context, data, scanline); @@ -394,6 +394,8 @@ static void nsc_encode_sse2(NSC_CONTEXT* context, const BYTE* data, { nsc_encode_subsampling_sse2(context); } + + return TRUE; } void nsc_init_sse2(NSC_CONTEXT* context) diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c index 41bcb8498..551fffc83 100644 --- a/libfreerdp/codec/zgfx.c +++ b/libfreerdp/codec/zgfx.c @@ -44,14 +44,34 @@ struct _ZGFX_TOKEN { - int prefixLength; - int prefixCode; - int valueBits; - int tokenType; + UINT32 prefixLength; + UINT32 prefixCode; + UINT32 valueBits; + UINT32 tokenType; UINT32 valueBase; }; typedef struct _ZGFX_TOKEN ZGFX_TOKEN; +struct _ZGFX_CONTEXT +{ + BOOL Compressor; + + const BYTE* pbInputCurrent; + const BYTE* pbInputEnd; + + UINT32 bits; + UINT32 cBitsRemaining; + UINT32 BitsCurrent; + UINT32 cBitsCurrent; + + BYTE OutputBuffer[65536]; + UINT32 OutputCount; + + BYTE HistoryBuffer[2500000]; + UINT32 HistoryIndex; + UINT32 HistoryBufferSize; +}; + static const ZGFX_TOKEN ZGFX_TOKEN_TABLE[] = { // len code vbits type vbase @@ -98,17 +118,27 @@ static const ZGFX_TOKEN ZGFX_TOKEN_TABLE[] = { 0 } }; -#define zgfx_GetBits(_zgfx, _nbits) \ - while (_zgfx->cBitsCurrent < _nbits) { \ - _zgfx->BitsCurrent <<= 8; \ - if (_zgfx->pbInputCurrent < _zgfx->pbInputEnd) \ - _zgfx->BitsCurrent += *(_zgfx->pbInputCurrent)++; \ - _zgfx->cBitsCurrent += 8; \ - } \ - _zgfx->cBitsRemaining -= _nbits; \ - _zgfx->cBitsCurrent -= _nbits; \ - _zgfx->bits = _zgfx->BitsCurrent >> _zgfx->cBitsCurrent; \ +static INLINE BOOL zgfx_GetBits(ZGFX_CONTEXT* _zgfx, UINT32 _nbits) +{ + if (!_zgfx) + return FALSE; + + while (_zgfx->cBitsCurrent < _nbits) + { + _zgfx->BitsCurrent <<= 8; + + if (_zgfx->pbInputCurrent < _zgfx->pbInputEnd) + _zgfx->BitsCurrent += *(_zgfx->pbInputCurrent)++; + + _zgfx->cBitsCurrent += 8; + } + + _zgfx->cBitsRemaining -= _nbits; + _zgfx->cBitsCurrent -= _nbits; + _zgfx->bits = _zgfx->BitsCurrent >> _zgfx->cBitsCurrent; _zgfx->BitsCurrent &= ((1 << _zgfx->cBitsCurrent) - 1); + return TRUE; +} static void zgfx_history_buffer_ring_write(ZGFX_CONTEXT* zgfx, const BYTE* src, size_t count) { @@ -193,16 +223,22 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t { BYTE c; BYTE flags; - int extra; + UINT32 extra = 0; int opIndex; int haveBits; int inPrefix; UINT32 count; UINT32 distance; BYTE* pbSegment; - size_t cbSegment = segmentSize - 1; + size_t cbSegment; - if ((Stream_GetRemainingLength(stream) < segmentSize) || (segmentSize < 1)) + if (!zgfx || !stream) + return FALSE; + + cbSegment = segmentSize - 1; + + if ((Stream_GetRemainingLength(stream) < segmentSize) || (segmentSize < 1) || + (segmentSize > UINT32_MAX)) return FALSE; Stream_Read_UINT8(stream, flags); /* header (1 byte) */ @@ -213,6 +249,10 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t if (!(flags & PACKET_COMPRESSED)) { zgfx_history_buffer_ring_write(zgfx, pbSegment, cbSegment); + + if (cbSegment > sizeof(zgfx->OutputBuffer)) + return FALSE; + CopyMemory(zgfx->OutputBuffer, pbSegment, cbSegment); zgfx->OutputCount = cbSegment; return TRUE; @@ -251,6 +291,9 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t if (++zgfx->HistoryIndex == zgfx->HistoryBufferSize) zgfx->HistoryIndex = 0; + if (zgfx->OutputCount >= sizeof(zgfx->OutputBuffer)) + return FALSE; + zgfx->OutputBuffer[zgfx->OutputCount++] = c; } else @@ -284,6 +327,9 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t count += zgfx->bits; } + if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount) + return FALSE; + zgfx_history_buffer_ring_read(zgfx, distance, &(zgfx->OutputBuffer[zgfx->OutputCount]), count); zgfx_history_buffer_ring_write(zgfx, &(zgfx->OutputBuffer[zgfx->OutputCount]), count); zgfx->OutputCount += count; @@ -296,6 +342,10 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t zgfx->cBitsRemaining -= zgfx->cBitsCurrent; zgfx->cBitsCurrent = 0; zgfx->BitsCurrent = 0; + + if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount) + return FALSE; + CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent, count); zgfx_history_buffer_ring_write(zgfx, zgfx->pbInputCurrent, count); zgfx->pbInputCurrent += count; @@ -317,8 +367,8 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY { int status = -1; BYTE descriptor; - wStream* stream = Stream_New((BYTE*)pSrcData, SrcSize); + if (!stream) return -1; @@ -333,6 +383,7 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY goto fail; *ppDstData = NULL; + if (zgfx->OutputCount > 0) *ppDstData = (BYTE*) malloc(zgfx->OutputCount); @@ -349,6 +400,7 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY UINT16 segmentCount; UINT32 uncompressedSize; BYTE* pConcatenated; + size_t used = 0; if (Stream_GetRemainingLength(stream) < 6) goto fail; @@ -377,8 +429,15 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY if (!zgfx_decompress_segment(zgfx, stream, segmentSize)) goto fail; + if (zgfx->OutputCount > UINT32_MAX - used) + goto fail; + + if (used + zgfx->OutputCount > uncompressedSize) + goto fail; + CopyMemory(pConcatenated, zgfx->OutputBuffer, zgfx->OutputCount); pConcatenated += zgfx->OutputCount; + used += zgfx->OutputCount; } } else diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index 5e0757dcb..c2ca42cc4 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -208,11 +208,9 @@ BITMAP_UPDATE* update_read_bitmap_update(rdpUpdate* update, wStream* s) if (bitmapUpdate->number > bitmapUpdate->count) { - UINT16 count; - BITMAP_DATA* newdata; - count = bitmapUpdate->number * 2; - newdata = (BITMAP_DATA*) realloc(bitmapUpdate->rectangles, - sizeof(BITMAP_DATA) * count); + UINT32 count = bitmapUpdate->number * 2; + BITMAP_DATA* newdata = (BITMAP_DATA*) realloc(bitmapUpdate->rectangles, + sizeof(BITMAP_DATA) * count); if (!newdata) goto fail; diff --git a/libfreerdp/gdi/graphics.c b/libfreerdp/gdi/graphics.c index 4afae48d1..159198756 100644 --- a/libfreerdp/gdi/graphics.c +++ b/libfreerdp/gdi/graphics.c @@ -141,9 +141,17 @@ static BOOL gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, { UINT32 SrcSize = length; rdpGdi* gdi = context->gdi; + UINT32 size = DstWidth * DstHeight; bitmap->compressed = FALSE; bitmap->format = gdi->dstFormat; - bitmap->length = DstWidth * DstHeight * GetBytesPerPixel(bitmap->format); + + if ((GetBytesPerPixel(bitmap->format) == 0) || + (DstWidth == 0) || (DstHeight == 0) || (DstWidth > UINT32_MAX / DstHeight) || + (size > (UINT32_MAX / GetBytesPerPixel(bitmap->format)))) + return FALSE; + + size *= GetBytesPerPixel(bitmap->format); + bitmap->length = size; bitmap->data = (BYTE*) _aligned_malloc(bitmap->length, 16); if (!bitmap->data) diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.h b/winpr/libwinpr/sspi/NTLM/ntlm.h index d4c2404a0..4f0024880 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm.h @@ -147,6 +147,7 @@ struct _NTLMv2_CLIENT_CHALLENGE BYTE ClientChallenge[8]; UINT32 Reserved3; NTLM_AV_PAIR* AvPairs; + UINT32 cbAvPairs; }; typedef struct _NTLMv2_CLIENT_CHALLENGE NTLMv2_CLIENT_CHALLENGE; diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c index d593a0e9c..2c587e275 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c @@ -39,7 +39,7 @@ #include "../../log.h" #define TAG WINPR_TAG("sspi.NTLM") -const char* const AV_PAIR_STRINGS[] = +static const char* const AV_PAIR_STRINGS[] = { "MsvAvEOL", "MsvAvNbComputerName", @@ -54,14 +54,42 @@ const char* const AV_PAIR_STRINGS[] = "MsvChannelBindings" }; -void ntlm_av_pair_list_init(NTLM_AV_PAIR* pAvPairList) +static NTLM_AV_PAIR* ntlm_av_pair_get_next_pointer(NTLM_AV_PAIR* pAvPair, size_t* pcbAvPair); + +static void ntlm_av_pair_set_id(NTLM_AV_PAIR* pAvPair, UINT16 id) { - NTLM_AV_PAIR* pAvPair = pAvPairList; - ntlm_av_pair_set_id(pAvPair, MsvAvEOL); - ntlm_av_pair_set_len(pAvPair, 0); + Data_Write_UINT16(&pAvPair->AvId, id); } -ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList) +static void ntlm_av_pair_set_len(NTLM_AV_PAIR* pAvPair, UINT16 len) +{ + Data_Write_UINT16(&pAvPair->AvLen, len); +} + +static BOOL ntlm_av_pair_list_init(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) +{ + NTLM_AV_PAIR* pAvPair = pAvPairList; + + if (!pAvPair || (cbAvPairList < sizeof(NTLM_AV_PAIR))) + return FALSE; + + ntlm_av_pair_set_id(pAvPair, MsvAvEOL); + ntlm_av_pair_set_len(pAvPair, 0); + return TRUE; +} + +static INLINE UINT16 ntlm_av_pair_get_id(const NTLM_AV_PAIR* pAvPair) +{ + UINT16 AvId; + + if (!pAvPair) + return MsvAvEOL; + + Data_Read_UINT16(&pAvPair->AvId, AvId); + return AvId; +} + +ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairListMaxLength) { ULONG length; NTLM_AV_PAIR* pAvPair = pAvPairList; @@ -71,14 +99,29 @@ ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList) while (ntlm_av_pair_get_id(pAvPair) != MsvAvEOL) { - pAvPair = ntlm_av_pair_get_next_pointer(pAvPair); + pAvPair = ntlm_av_pair_get_next_pointer(pAvPair, &cbAvPairListMaxLength); } length = (pAvPair - pAvPairList) + sizeof(NTLM_AV_PAIR); return length; } -void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList) +static INLINE SSIZE_T ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair) +{ + UINT16 AvLen; + + if (!pAvPair || (cbAvPair < sizeof(NTLM_AV_PAIR))) + return -1; + + Data_Read_UINT16(&pAvPair->AvLen, AvLen); + + if (cbAvPair < sizeof(NTLM_AV_PAIR) + pAvPair->AvLen) + return -1; + + return AvLen; +} + +void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) { NTLM_AV_PAIR* pAvPair = pAvPairList; @@ -92,60 +135,84 @@ void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList) WLog_INFO(TAG, "\t%s AvId: %"PRIu16" AvLen: %"PRIu16"", AV_PAIR_STRINGS[ntlm_av_pair_get_id(pAvPair)], ntlm_av_pair_get_id(pAvPair), - ntlm_av_pair_get_len(pAvPair)); - winpr_HexDump(TAG, WLOG_INFO, ntlm_av_pair_get_value_pointer(pAvPair), - ntlm_av_pair_get_len(pAvPair)); - pAvPair = ntlm_av_pair_get_next_pointer(pAvPair); + ntlm_av_pair_get_len(pAvPair, cbAvPairList)); + winpr_HexDump(TAG, WLOG_INFO, ntlm_av_pair_get_value_pointer(pAvPair, cbAvPairList), + ntlm_av_pair_get_len(pAvPair, cbAvPairList)); + pAvPair = ntlm_av_pair_get_next_pointer(pAvPair, &cbAvPairList); } } -ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength) +static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength) { /* size of headers + value lengths + terminating MsvAvEOL AV_PAIR */ return ((AvPairsCount + 1) * 4) + AvPairsValueLength; } -PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair) +PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair, size_t cbAvPairListMaxLength) { + if (cbAvPairListMaxLength < 2 * sizeof(NTLM_AV_PAIR)) + return NULL; + return &((PBYTE) pAvPair)[sizeof(NTLM_AV_PAIR)]; } -int ntlm_av_pair_get_next_offset(NTLM_AV_PAIR* pAvPair) +static SSIZE_T ntlm_av_pair_get_next_offset(NTLM_AV_PAIR* pAvPair, size_t cbAvPairListMaxLength) { - return ntlm_av_pair_get_len(pAvPair) + sizeof(NTLM_AV_PAIR); + return ntlm_av_pair_get_len(pAvPair, cbAvPairListMaxLength) + sizeof(NTLM_AV_PAIR); } -NTLM_AV_PAIR* ntlm_av_pair_get_next_pointer(NTLM_AV_PAIR* pAvPair) +NTLM_AV_PAIR* ntlm_av_pair_get_next_pointer(NTLM_AV_PAIR* pAvPair, size_t* pcbAvPair) { - return (NTLM_AV_PAIR*)((PBYTE) pAvPair + ntlm_av_pair_get_next_offset(pAvPair)); + SSIZE_T offset; + + if (!pAvPair || !pcbAvPair) + return NULL; + + offset = ntlm_av_pair_get_next_offset(pAvPair, *pcbAvPair); + + if ((offset <= 0) || (offset > *pcbAvPair)) + return NULL; + + *pcbAvPair -= offset; + return (NTLM_AV_PAIR*)((PBYTE) pAvPair + offset); } -NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId) +NTLM_AV_PAIR* ntlm_av_pair_get(void* pAvPairList, + size_t avPairListLength, + NTLM_AV_ID AvId, + size_t* pcbAvPairListRemainingLength) { NTLM_AV_PAIR* pAvPair = pAvPairList; - if (!pAvPair) - return NULL; + if (pcbAvPairListRemainingLength) + *pcbAvPairListRemainingLength = 0; - while (1) + while (pAvPair) { if (ntlm_av_pair_get_id(pAvPair) == AvId) + { + if (pcbAvPairListRemainingLength) + *pcbAvPairListRemainingLength = avPairListLength; + return pAvPair; + } if (ntlm_av_pair_get_id(pAvPair) == MsvAvEOL) return NULL; - pAvPair = ntlm_av_pair_get_next_pointer(pAvPair); + pAvPair = ntlm_av_pair_get_next_pointer(pAvPair, &avPairListLength); } return NULL; } -NTLM_AV_PAIR* ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId, PBYTE Value, - UINT16 AvLen) +static NTLM_AV_PAIR* ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairListLength, + NTLM_AV_ID AvId, PBYTE Value, + UINT16 AvLen) { + size_t cbAvPair; NTLM_AV_PAIR* pAvPair; - pAvPair = ntlm_av_pair_get(pAvPairList, MsvAvEOL); + pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairListLength, MsvAvEOL, &cbAvPair); if (!pAvPair) return NULL; @@ -153,27 +220,29 @@ NTLM_AV_PAIR* ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId, PBYTE assert(Value != NULL); ntlm_av_pair_set_id(pAvPair, AvId); ntlm_av_pair_set_len(pAvPair, AvLen); - CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen); + CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair, cbAvPair), Value, AvLen); return pAvPair; } -NTLM_AV_PAIR* ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, NTLM_AV_PAIR* pAvPair) +static NTLM_AV_PAIR* ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairListLength, + NTLM_AV_PAIR* pAvPair, size_t cbAvPair) { NTLM_AV_PAIR* pAvPairCopy; - pAvPairCopy = ntlm_av_pair_get(pAvPairList, MsvAvEOL); + size_t cbAvPairCopy; + pAvPairCopy = ntlm_av_pair_get(pAvPairList, cbAvPairListLength, MsvAvEOL, &cbAvPairCopy); if (!pAvPairCopy) return NULL; CopyMemory(&pAvPairCopy->AvId, &pAvPair->AvId, 2); CopyMemory(&pAvPairCopy->AvLen, &pAvPair->AvLen, 2); - CopyMemory(ntlm_av_pair_get_value_pointer(pAvPairCopy), - ntlm_av_pair_get_value_pointer(pAvPair), - ntlm_av_pair_get_len(pAvPair)); + CopyMemory(ntlm_av_pair_get_value_pointer(pAvPairCopy, cbAvPairCopy), + ntlm_av_pair_get_value_pointer(pAvPair, cbAvPair), + ntlm_av_pair_get_len(pAvPair, cbAvPair)); return pAvPairCopy; } -int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type) +static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type) { char* name; int status; @@ -219,7 +288,7 @@ int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT ty return 1; } -void ntlm_free_unicode_string(PUNICODE_STRING string) +static void ntlm_free_unicode_string(PUNICODE_STRING string) { if (string) { @@ -271,7 +340,7 @@ static BOOL ntlm_md5_update_uint32_be(WINPR_DIGEST_CTX* md5, UINT32 num) return winpr_Digest_Update(md5, be32, 4); } -void ntlm_compute_channel_bindings(NTLM_CONTEXT* context) +static void ntlm_compute_channel_bindings(NTLM_CONTEXT* context) { WINPR_DIGEST_CTX* md5; BYTE* ChannelBindingToken; @@ -317,7 +386,7 @@ out: winpr_Digest_Free(md5); } -void ntlm_compute_single_host_data(NTLM_CONTEXT* context) +static void ntlm_compute_single_host_data(NTLM_CONTEXT* context) { /** * The Single_Host_Data structure allows a client to send machine-specific information @@ -336,33 +405,34 @@ void ntlm_compute_single_host_data(NTLM_CONTEXT* context) int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) { + int rc = -1; int length; ULONG AvPairsCount; ULONG AvPairsLength; NTLM_AV_PAIR* pAvPairList; - UNICODE_STRING NbDomainName; - UNICODE_STRING NbComputerName; - UNICODE_STRING DnsDomainName; - UNICODE_STRING DnsComputerName; - NbDomainName.Buffer = NULL; + size_t cbAvPairList; + UNICODE_STRING NbDomainName = { 0 }; + UNICODE_STRING NbComputerName = { 0 }; + UNICODE_STRING DnsDomainName = { 0 }; + UNICODE_STRING DnsComputerName = { 0 }; if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0) - return -1; + goto fail; NbComputerName.Buffer = NULL; if (ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS) < 0) - return -1; + goto fail; DnsDomainName.Buffer = NULL; if (ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain) < 0) - return -1; + goto fail; DnsComputerName.Buffer = NULL; if (ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname) < 0) - return -1; + goto fail; AvPairsCount = 5; AvPairsLength = NbDomainName.Length + NbComputerName.Length + @@ -370,23 +440,42 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength); if (!sspi_SecBufferAlloc(&context->ChallengeTargetInfo, length)) - return -1; + goto fail; pAvPairList = (NTLM_AV_PAIR*) context->ChallengeTargetInfo.pvBuffer; - ntlm_av_pair_list_init(pAvPairList); - ntlm_av_pair_add(pAvPairList, MsvAvNbDomainName, (PBYTE) NbDomainName.Buffer, NbDomainName.Length); - ntlm_av_pair_add(pAvPairList, MsvAvNbComputerName, (PBYTE) NbComputerName.Buffer, - NbComputerName.Length); - ntlm_av_pair_add(pAvPairList, MsvAvDnsDomainName, (PBYTE) DnsDomainName.Buffer, - DnsDomainName.Length); - ntlm_av_pair_add(pAvPairList, MsvAvDnsComputerName, (PBYTE) DnsComputerName.Buffer, - DnsComputerName.Length); - ntlm_av_pair_add(pAvPairList, MsvAvTimestamp, context->Timestamp, sizeof(context->Timestamp)); + cbAvPairList = context->ChallengeTargetInfo.cbBuffer; + + if (!ntlm_av_pair_list_init(pAvPairList, cbAvPairList)) + goto fail; + + if (ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbDomainName, (PBYTE) NbDomainName.Buffer, + NbDomainName.Length) == NULL) + goto fail; + + if (ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvNbComputerName, (PBYTE) NbComputerName.Buffer, + NbComputerName.Length) == NULL) + goto fail; + + if (ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsDomainName, (PBYTE) DnsDomainName.Buffer, + DnsDomainName.Length) == NULL) + goto fail; + + if (ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvDnsComputerName, + (PBYTE) DnsComputerName.Buffer, + DnsComputerName.Length) == NULL) + goto fail; + + if (ntlm_av_pair_add(pAvPairList, cbAvPairList, MsvAvTimestamp, context->Timestamp, + sizeof(context->Timestamp)) == NULL) + goto fail; + + rc = 1; +fail: ntlm_free_unicode_string(&NbDomainName); ntlm_free_unicode_string(&NbComputerName); ntlm_free_unicode_string(&DnsDomainName); ntlm_free_unicode_string(&DnsComputerName); - return 1; + return rc; } int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) @@ -402,44 +491,60 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) NTLM_AV_PAIR* AvDnsTreeName; NTLM_AV_PAIR* ChallengeTargetInfo; NTLM_AV_PAIR* AuthenticateTargetInfo; + size_t cbAvTimestamp; + size_t cbAvNbDomainName; + size_t cbAvNbComputerName; + size_t cbAvDnsDomainName; + size_t cbAvDnsComputerName; + size_t cbAvDnsTreeName; + size_t cbChallengeTargetInfo; + size_t cbAuthenticateTargetInfo; AvPairsCount = 1; AvPairsValueLength = 0; ChallengeTargetInfo = (NTLM_AV_PAIR*) context->ChallengeTargetInfo.pvBuffer; - AvNbDomainName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvNbDomainName); - AvNbComputerName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvNbComputerName); - AvDnsDomainName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvDnsDomainName); - AvDnsComputerName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvDnsComputerName); - AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvDnsTreeName); - AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvTimestamp); + cbChallengeTargetInfo = context->ChallengeTargetInfo.cbBuffer; + AvNbDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvNbDomainName, + &cbAvNbDomainName); + AvNbComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvNbComputerName, + &cbAvNbComputerName); + AvDnsDomainName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvDnsDomainName, + &cbAvDnsDomainName); + AvDnsComputerName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, + MsvAvDnsComputerName, + &cbAvDnsComputerName); + AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvDnsTreeName, + &cbAvDnsTreeName); + AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvTimestamp, + &cbAvTimestamp); if (AvNbDomainName) { AvPairsCount++; /* MsvAvNbDomainName */ - AvPairsValueLength += ntlm_av_pair_get_len(AvNbDomainName); + AvPairsValueLength += ntlm_av_pair_get_len(AvNbDomainName, cbAvNbDomainName); } if (AvNbComputerName) { AvPairsCount++; /* MsvAvNbComputerName */ - AvPairsValueLength += ntlm_av_pair_get_len(AvNbComputerName); + AvPairsValueLength += ntlm_av_pair_get_len(AvNbComputerName, cbAvNbComputerName); } if (AvDnsDomainName) { AvPairsCount++; /* MsvAvDnsDomainName */ - AvPairsValueLength += ntlm_av_pair_get_len(AvDnsDomainName); + AvPairsValueLength += ntlm_av_pair_get_len(AvDnsDomainName, cbAvDnsDomainName); } if (AvDnsComputerName) { AvPairsCount++; /* MsvAvDnsComputerName */ - AvPairsValueLength += ntlm_av_pair_get_len(AvDnsComputerName); + AvPairsValueLength += ntlm_av_pair_get_len(AvDnsComputerName, cbAvDnsComputerName); } if (AvDnsTreeName) { AvPairsCount++; /* MsvAvDnsTreeName */ - AvPairsValueLength += ntlm_av_pair_get_len(AvDnsTreeName); + AvPairsValueLength += ntlm_av_pair_get_len(AvDnsTreeName, cbAvDnsTreeName); } AvPairsCount++; /* MsvAvTimestamp */ @@ -489,56 +594,96 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) return -1; AuthenticateTargetInfo = (NTLM_AV_PAIR*) context->AuthenticateTargetInfo.pvBuffer; - ntlm_av_pair_list_init(AuthenticateTargetInfo); + cbAuthenticateTargetInfo = context->AuthenticateTargetInfo.cbBuffer; + + if (!ntlm_av_pair_list_init(AuthenticateTargetInfo, cbAuthenticateTargetInfo)) + return -1; if (AvNbDomainName) - ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvNbDomainName); + { + if (ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvNbDomainName, + cbAvNbDomainName) == NULL) + return -1; + } if (AvNbComputerName) - ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvNbComputerName); + { + if (ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, + AvNbComputerName, cbAvNbComputerName) == NULL) + return -1; + } if (AvDnsDomainName) - ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsDomainName); + { + if (ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, + AvDnsDomainName, cbAvDnsDomainName) == NULL) + return -1; + } if (AvDnsComputerName) - ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsComputerName); + { + if (ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, + AvDnsComputerName, cbAvDnsComputerName) == NULL) + return -1; + } if (AvDnsTreeName) - ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsTreeName); + { + if (ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvDnsTreeName, + cbAvDnsTreeName) == NULL) + return -1; + } if (AvTimestamp) - ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvTimestamp); + { + if (ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvTimestamp, + cbAvTimestamp) == NULL) + return -1; + } if (context->UseMIC) { UINT32 flags; Data_Write_UINT32(&flags, MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK); - ntlm_av_pair_add(AuthenticateTargetInfo, MsvAvFlags, (PBYTE) &flags, 4); + + if (ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvFlags, (PBYTE) &flags, + 4) == NULL) + return -1; } if (context->SendSingleHostData) { - ntlm_av_pair_add(AuthenticateTargetInfo, MsvAvSingleHost, - (PBYTE) &context->SingleHostData, context->SingleHostData.Size); + if (ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost, + (PBYTE) &context->SingleHostData, context->SingleHostData.Size) == NULL) + return -1; } if (!context->SuppressExtendedProtection) { - ntlm_av_pair_add(AuthenticateTargetInfo, MsvChannelBindings, context->ChannelBindingsHash, 16); + if (ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvChannelBindings, + context->ChannelBindingsHash, 16) == NULL) + return -1; if (context->ServicePrincipalName.Length > 0) { - ntlm_av_pair_add(AuthenticateTargetInfo, MsvAvTargetName, - (PBYTE) context->ServicePrincipalName.Buffer, - context->ServicePrincipalName.Length); + if (ntlm_av_pair_add(AuthenticateTargetInfo, + cbAuthenticateTargetInfo, + MsvAvTargetName, + (PBYTE) context->ServicePrincipalName.Buffer, + context->ServicePrincipalName.Length) == NULL) + return -1; } } if (context->NTLMv2) { NTLM_AV_PAIR* AvEOL; - AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvEOL); - ZeroMemory((void*) AvEOL, 4); + AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvEOL, NULL); + + if (!AvEOL) + return -1; + + ZeroMemory(AvEOL, sizeof(NTLM_AV_PAIR)); } return 1; diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h index d62d3d43a..17962b483 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h @@ -24,33 +24,11 @@ #include -void ntlm_av_pair_list_init(NTLM_AV_PAIR* pAvPairList); -ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList); -void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList); -ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength); -PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair); -int ntlm_av_pair_get_next_offset(NTLM_AV_PAIR* pAvPair); -NTLM_AV_PAIR* ntlm_av_pair_get_next_pointer(NTLM_AV_PAIR* pAvPair); -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); - -static INLINE UINT16 ntlm_av_pair_get_id(NTLM_AV_PAIR* pAvPair) -{ - UINT16 AvId; - Data_Read_UINT16(&pAvPair->AvId, AvId); - return AvId; -} - -static INLINE UINT16 ntlm_av_pair_get_len(NTLM_AV_PAIR* pAvPair) -{ - UINT16 AvLen; - Data_Read_UINT16(&pAvPair->AvLen, AvLen); - return AvLen; -} - -#define ntlm_av_pair_set_id(pAvPair, id) Data_Write_UINT16(&pAvPair->AvId, id) -#define ntlm_av_pair_set_len(pAvPair, len) Data_Write_UINT16(&pAvPair->AvLen, len) +ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairListMaxLength); +void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList); +PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair, size_t cbAvPairListMaxLength); +NTLM_AV_PAIR* ntlm_av_pair_get(void* pAvPairList, size_t avPairListLength, NTLM_AV_ID AvId, + size_t* pcbAvPairListRemainingLength); int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context); int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context); diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c index fc5fcaf18..e9e2e5b4e 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c @@ -132,7 +132,12 @@ int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* chal Stream_Read(s, challenge->ClientChallenge, 8); Stream_Read_UINT32(s, challenge->Reserved3); size = Stream_Length(s) - Stream_GetPosition(s); - challenge->AvPairs = (NTLM_AV_PAIR*) malloc(size); + + if (size > UINT32_MAX) + return -1; + + challenge->cbAvPairs = size; + challenge->AvPairs = (NTLM_AV_PAIR*) malloc(challenge->cbAvPairs); if (!challenge->AvPairs) return -1; @@ -151,7 +156,7 @@ int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* cha Stream_Write(s, challenge->Timestamp, 8); Stream_Write(s, challenge->ClientChallenge, 8); Stream_Write_UINT32(s, challenge->Reserved3); - length = ntlm_av_pair_list_length(challenge->AvPairs); + length = ntlm_av_pair_list_length(challenge->AvPairs, challenge->cbAvPairs); Stream_Write(s, challenge->AvPairs, length); return 1; } diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c index d78560497..fe28fac0f 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c @@ -74,7 +74,7 @@ static const char* const NTLM_NEGOTIATE_STRINGS[] = "NTLMSSP_NEGOTIATE_UNICODE" }; -void ntlm_print_negotiate_flags(UINT32 flags) +static void ntlm_print_negotiate_flags(UINT32 flags) { int i; const char* str; @@ -90,7 +90,7 @@ void ntlm_print_negotiate_flags(UINT32 flags) } } -int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) +static int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) { if (Stream_GetRemainingLength(s) < 12) return -1; @@ -104,19 +104,19 @@ int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) return 1; } -void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) +static void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) { Stream_Write(s, header->Signature, sizeof(NTLM_SIGNATURE)); Stream_Write_UINT32(s, header->MessageType); } -void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType) +static void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType) { CopyMemory(header->Signature, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)); header->MessageType = MessageType; } -int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) { if (Stream_GetRemainingLength(s) < 8) return -1; @@ -127,7 +127,7 @@ int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) return 1; } -void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) { if (fields->MaxLen < 1) fields->MaxLen = fields->Len; @@ -137,11 +137,16 @@ void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) Stream_Write_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ } -int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) { if (fields->Len > 0) { - if ((fields->BufferOffset + fields->Len) > Stream_Length(s)) + const UINT32 offset = fields->BufferOffset + fields->Len; + + if (fields->BufferOffset > UINT32_MAX - fields->Len) + return -1; + + if (offset > Stream_Length(s)) return -1; fields->Buffer = (PBYTE) malloc(fields->Len); @@ -156,7 +161,7 @@ int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) return 1; } -void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) { if (fields->Len > 0) { @@ -165,7 +170,7 @@ void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) } } -void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) +static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) { if (fields) { @@ -180,7 +185,7 @@ void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) } } -void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name) +static void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name) { WLog_DBG(TAG, "%s (Len: %"PRIu16" MaxLen: %"PRIu16" BufferOffset: %"PRIu32")", name, fields->Len, fields->MaxLen, fields->BufferOffset); @@ -445,6 +450,8 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf if (message->TargetInfo.Len > 0) { + size_t cbAvTimestamp; + if (ntlm_read_message_fields_buffer(s, &(message->TargetInfo)) < 0) { Stream_Free(s, FALSE); @@ -453,14 +460,21 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf context->ChallengeTargetInfo.pvBuffer = message->TargetInfo.Buffer; context->ChallengeTargetInfo.cbBuffer = message->TargetInfo.Len; - AvTimestamp = ntlm_av_pair_get((NTLM_AV_PAIR*) message->TargetInfo.Buffer, MsvAvTimestamp); + AvTimestamp = ntlm_av_pair_get(message->TargetInfo.Buffer, + message->TargetInfo.Len, + MsvAvTimestamp, &cbAvTimestamp); if (AvTimestamp) { + PBYTE ptr = ntlm_av_pair_get_value_pointer(AvTimestamp, cbAvTimestamp); + + if (!ptr) + return SEC_E_INTERNAL_ERROR; + if (context->NTLMv2) context->UseMIC = TRUE; - CopyMemory(context->ChallengeTimestamp, ntlm_av_pair_get_value_pointer(AvTimestamp), 8); + CopyMemory(context->ChallengeTimestamp, ptr, 8); } } @@ -784,6 +798,7 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer if (message->NtChallengeResponse.Len > 0) { + size_t cbAvFlags; wStream* snt = Stream_New(message->NtChallengeResponse.Buffer, message->NtChallengeResponse.Len); if (!snt) @@ -806,10 +821,12 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer context->ChallengeTargetInfo.pvBuffer = (void*) context->NTLMv2Response.Challenge.AvPairs; context->ChallengeTargetInfo.cbBuffer = message->NtChallengeResponse.Len - (28 + 16); CopyMemory(context->ClientChallenge, context->NTLMv2Response.Challenge.ClientChallenge, 8); - AvFlags = ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs, MsvAvFlags); + AvFlags = ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs, + context->NTLMv2Response.Challenge.cbAvPairs, + MsvAvFlags, &cbAvFlags); if (AvFlags) - Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags); + Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags, cbAvFlags), flags); } if (ntlm_read_message_fields_buffer(s, @@ -1101,18 +1118,24 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) { UINT32 flags = 0; + size_t cbAvFlags; NTLM_AV_PAIR* AvFlags = NULL; NTLM_AUTHENTICATE_MESSAGE* message; BYTE messageIntegrityCheck[16]; + if (!context) + return SEC_E_INVALID_PARAMETER; + if (context->state != NTLM_STATE_COMPLETION) return SEC_E_OUT_OF_SEQUENCE; message = &context->AUTHENTICATE_MESSAGE; - AvFlags = ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs, MsvAvFlags); + AvFlags = ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs, + context->NTLMv2Response.Challenge.cbAvPairs, + MsvAvFlags, &cbAvFlags); if (AvFlags) - Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags); + Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags, cbAvFlags), flags); if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */ return SEC_E_INTERNAL_ERROR;