Merge branch 'master' into spikes/hyperv
This commit is contained in:
commit
2068263193
@ -4,6 +4,7 @@
|
||||
# Copyright 2011 O.S. Systems Software Ltda.
|
||||
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
|
||||
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
# Copyright 2012 HP Development Company, LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -107,6 +108,7 @@ if(APPLE)
|
||||
include_directories(/opt/local/include)
|
||||
link_directories(/opt/local/lib)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -mmacosx-version-min=10.4")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -framework CoreFoundation")
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
@ -117,6 +119,8 @@ if(NOT WIN32)
|
||||
|
||||
if(NOT APPLE)
|
||||
find_suggested_package(FFmpeg)
|
||||
find_suggested_package(XRandR)
|
||||
find_suggested_package(Gstreamer)
|
||||
find_suggested_package(ALSA)
|
||||
else(NOT APPLE)
|
||||
find_optional_package(FFmpeg)
|
||||
@ -130,6 +134,9 @@ set(FREERDP_KEYMAP_PATH "${FREERDP_DATA_PATH}/keymaps")
|
||||
# Path to put plugins
|
||||
set(FREERDP_PLUGIN_PATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/freerdp")
|
||||
|
||||
# Path to put extensions
|
||||
set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/freerdp/extensions")
|
||||
|
||||
# Include directories
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
|
@ -23,4 +23,5 @@ add_subdirectory(rdpdbg)
|
||||
add_subdirectory(rdpdr)
|
||||
add_subdirectory(rail)
|
||||
add_subdirectory(rdpsnd)
|
||||
add_subdirectory(skel)
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
# Copyright 2011 O.S. Systems Software Ltda.
|
||||
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
|
||||
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
# Copyright 2012 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -47,6 +48,12 @@ if(WITH_FFMPEG)
|
||||
add_subdirectory(ffmpeg)
|
||||
endif()
|
||||
|
||||
if(WITH_XRANDR)
|
||||
if(GSTREAMER_FOUND)
|
||||
add_subdirectory(gstreamer)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_ALSA)
|
||||
add_subdirectory(alsa)
|
||||
endif()
|
||||
|
@ -499,7 +499,6 @@ TSMFDecoderEntry(void)
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
avcodec_init();
|
||||
avcodec_register_all();
|
||||
initialized = true;
|
||||
}
|
||||
|
34
channels/drdynvc/tsmf/gstreamer/CMakeLists.txt
Normal file
34
channels/drdynvc/tsmf/gstreamer/CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Client
|
||||
# FreeRDP cmake build script for gstreamer plugin
|
||||
#
|
||||
# (C) Copyright 2012 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
|
||||
set(TSMF_GSTREAMER_SRCS
|
||||
tsmf_gstreamer.c
|
||||
)
|
||||
|
||||
include_directories(..)
|
||||
include_directories(${GSTREAMER_INCLUDE_DIRS})
|
||||
|
||||
add_library(tsmf_gstreamer ${TSMF_GSTREAMER_SRCS})
|
||||
set_target_properties(tsmf_gstreamer PROPERTIES PREFIX "")
|
||||
|
||||
target_link_libraries(tsmf_gstreamer freerdp-utils)
|
||||
target_link_libraries(tsmf_gstreamer ${GSTREAMER_LIBRARIES} gstapp-0.10 gstinterfaces-0.10 Xrandr X11 Xext)
|
||||
|
||||
install(TARGETS tsmf_gstreamer DESTINATION ${FREERDP_PLUGIN_PATH})
|
||||
|
1598
channels/drdynvc/tsmf/gstreamer/tsmf_gstreamer.c
Normal file
1598
channels/drdynvc/tsmf/gstreamer/tsmf_gstreamer.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
||||
* Video Redirection Virtual Channel - Codec
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
* Copyright 2012 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -103,6 +104,20 @@ static const TSMFMediaTypeMap tsmf_sub_type_map[] =
|
||||
TSMF_SUB_TYPE_MP2V
|
||||
},
|
||||
|
||||
/* 31564D57-0000-0010-8000-00AA00389B71 */
|
||||
{
|
||||
{ 0x57, 0x4D, 0x56, 0x31, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
|
||||
"MEDIASUBTYPE_WMV1",
|
||||
TSMF_SUB_TYPE_WMV1
|
||||
},
|
||||
|
||||
/* 32564D57-0000-0010-8000-00AA00389B71 */
|
||||
{
|
||||
{ 0x57, 0x4D, 0x56, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
|
||||
"MEDIASUBTYPE_WMV2",
|
||||
TSMF_SUB_TYPE_WMV2
|
||||
},
|
||||
|
||||
/* 33564D57-0000-0010-8000-00AA00389B71 */
|
||||
{
|
||||
{ 0x57, 0x4D, 0x56, 0x33, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
|
||||
@ -131,12 +146,62 @@ static const TSMFMediaTypeMap tsmf_sub_type_map[] =
|
||||
TSMF_SUB_TYPE_AVC1
|
||||
},
|
||||
|
||||
/* 3334504D-0000-0010-8000-00AA00389B71 */
|
||||
{
|
||||
{ 0x4D, 0x50, 0x34, 0x33, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
|
||||
"MEDIASUBTYPE_MP43",
|
||||
TSMF_SUB_TYPE_MP43
|
||||
},
|
||||
|
||||
/* 5634504D-0000-0010-8000-00AA00389B71 */
|
||||
{
|
||||
{ 0x4D, 0x50, 0x34, 0x56, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
|
||||
"MEDIASUBTYPE_MP4S",
|
||||
TSMF_SUB_TYPE_MP4S
|
||||
},
|
||||
|
||||
/* 3234504D-0000-0010-8000-00AA00389B71 */
|
||||
{
|
||||
{ 0x4D, 0x50, 0x34, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
|
||||
"MEDIASUBTYPE_MP42",
|
||||
TSMF_SUB_TYPE_MP42
|
||||
},
|
||||
|
||||
/* E436EB81-524F-11CE-9F53-0020AF0BA770 */
|
||||
/*
|
||||
{
|
||||
{ 0x81, 0xEB, 0x36, 0xE4, 0x4F, 0x52, 0xCE, 0x11, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 },
|
||||
"MEDIASUBTYPE_MP1V",
|
||||
TSMF_SUB_TYPE_MP1V
|
||||
},
|
||||
*/
|
||||
|
||||
/* 00000050-0000-0010-8000-00AA00389B71 */
|
||||
/*
|
||||
{
|
||||
{ 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
|
||||
"MEDIASUBTYPE_MP1A",
|
||||
TSMF_SUB_TYPE_MP1A
|
||||
},
|
||||
*/
|
||||
|
||||
/* E06D802C-DB46-11CF-B4D1-00805F6CBBEA */
|
||||
/*
|
||||
{
|
||||
{ 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA },
|
||||
"MEDIASUBTYPE_DOLBY_AC3",
|
||||
TSMF_SUB_TYPE_AC3
|
||||
},
|
||||
*/
|
||||
|
||||
/* 32595559-0000-0010-8000-00AA00389B71 */
|
||||
/*
|
||||
{
|
||||
{ 0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 },
|
||||
"MEDIASUBTYPE_YUY2",
|
||||
TSMF_SUB_TYPE_YUY2
|
||||
},
|
||||
*/
|
||||
|
||||
{
|
||||
{ 0 },
|
||||
@ -176,6 +241,13 @@ static const TSMFMediaTypeMap tsmf_format_type_map[] =
|
||||
TSMF_FORMAT_TYPE_VIDEOINFO2
|
||||
},
|
||||
|
||||
/* 05589F82-C356-11CE-BF01-00AA0055595A */
|
||||
{
|
||||
{ 0x82, 0x9F, 0x58, 0x05, 0x56, 0xC3, 0xCE, 0x11, 0xBF, 0x01, 0x00, 0xAA, 0x00, 0x55, 0x59, 0x5A },
|
||||
"FORMAT_MPEG1_VIDEO",
|
||||
TSMF_FORMAT_TYPE_MPEG1VIDEOINFO
|
||||
},
|
||||
|
||||
{
|
||||
{ 0 },
|
||||
"Unknown",
|
||||
@ -257,6 +329,40 @@ static uint32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE* mediatype, STR
|
||||
return 72;
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/dd390700.aspx */
|
||||
static uint32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, STREAM* s)
|
||||
{
|
||||
/*
|
||||
typedef struct tagVIDEOINFOHEADER {
|
||||
RECT rcSource; //16
|
||||
RECT rcTarget; //16 32
|
||||
DWORD dwBitRate; //4 36
|
||||
DWORD dwBitErrorRate; //4 40
|
||||
REFERENCE_TIME AvgTimePerFrame; //8 48
|
||||
BITMAPINFOHEADER bmiHeader;
|
||||
} VIDEOINFOHEADER;
|
||||
*/
|
||||
uint64 AvgTimePerFrame;
|
||||
|
||||
/* VIDEOINFOHEADER.rcSource, RECT(LONG left, LONG top, LONG right, LONG bottom) */
|
||||
stream_seek_uint32(s);
|
||||
stream_seek_uint32(s);
|
||||
stream_read_uint32(s, mediatype->Width);
|
||||
stream_read_uint32(s, mediatype->Height);
|
||||
/* VIDEOINFOHEADER.rcTarget */
|
||||
stream_seek(s, 16);
|
||||
/* VIDEOINFOHEADER.dwBitRate */
|
||||
stream_read_uint32(s, mediatype->BitRate);
|
||||
/* VIDEOINFOHEADER.dwBitErrorRate */
|
||||
stream_seek_uint32(s);
|
||||
/* VIDEOINFOHEADER.AvgTimePerFrame */
|
||||
stream_read_uint64(s, AvgTimePerFrame);
|
||||
mediatype->SamplesPerSecond.Numerator = 1000000;
|
||||
mediatype->SamplesPerSecond.Denominator = (int)(AvgTimePerFrame / 10LL);
|
||||
|
||||
return 48;
|
||||
}
|
||||
|
||||
boolean tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, STREAM* s)
|
||||
{
|
||||
int i;
|
||||
@ -358,6 +464,18 @@ boolean tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, STREAM* s)
|
||||
|
||||
break;
|
||||
|
||||
case TSMF_FORMAT_TYPE_MPEG1VIDEOINFO:
|
||||
/* http://msdn.microsoft.com/en-us/library/dd390700.aspx */
|
||||
|
||||
i = tsmf_codec_parse_VIDEOINFOHEADER(mediatype, s);
|
||||
i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, true);
|
||||
if (cbFormat > i)
|
||||
{
|
||||
mediatype->ExtraDataSize = cbFormat - i;
|
||||
mediatype->ExtraData = stream_get_tail(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case TSMF_FORMAT_TYPE_MPEG2VIDEOINFO:
|
||||
/* http://msdn.microsoft.com/en-us/library/dd390707.aspx */
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Video Redirection Virtual Channel - Constants
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
* Copyright 2012 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -108,6 +109,14 @@
|
||||
#define TSMF_SUB_TYPE_H264 9
|
||||
#define TSMF_SUB_TYPE_AVC1 10
|
||||
#define TSMF_SUB_TYPE_AC3 11
|
||||
#define TSMF_SUB_TYPE_WMV2 12
|
||||
#define TSMF_SUB_TYPE_WMV1 13
|
||||
#define TSMF_SUB_TYPE_MP1V 14
|
||||
#define TSMF_SUB_TYPE_MP1A 15
|
||||
#define TSMF_SUB_TYPE_YUY2 16
|
||||
#define TSMF_SUB_TYPE_MP43 17
|
||||
#define TSMF_SUB_TYPE_MP4S 18
|
||||
#define TSMF_SUB_TYPE_MP42 19
|
||||
|
||||
/* FormatType */
|
||||
#define TSMF_FORMAT_TYPE_UNKNOWN 0
|
||||
@ -115,6 +124,7 @@
|
||||
#define TSMF_FORMAT_TYPE_WAVEFORMATEX 2
|
||||
#define TSMF_FORMAT_TYPE_MPEG2VIDEOINFO 3
|
||||
#define TSMF_FORMAT_TYPE_VIDEOINFO2 4
|
||||
#define TSMF_FORMAT_TYPE_MPEG1VIDEOINFO 5
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Video Redirection Virtual Channel - Decoder
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
* Copyright 2012 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -23,6 +24,14 @@
|
||||
#include "drdynvc_types.h"
|
||||
#include "tsmf_types.h"
|
||||
|
||||
typedef enum _ITSMFControlMsg
|
||||
{
|
||||
Control_Pause,
|
||||
Control_Restart,
|
||||
Control_Flush,
|
||||
Control_EndOfStream
|
||||
} ITSMFControlMsg;
|
||||
|
||||
typedef struct _ITSMFDecoder ITSMFDecoder;
|
||||
|
||||
struct _ITSMFDecoder
|
||||
@ -38,7 +47,20 @@ struct _ITSMFDecoder
|
||||
/* Get the width and height of decoded video frame */
|
||||
boolean (*GetDecodedDimension) (ITSMFDecoder* decoder, uint32* width, uint32* height);
|
||||
/* Free the decoder */
|
||||
void (*Free) (ITSMFDecoder* decoder);
|
||||
void (*Free) (ITSMFDecoder * decoder);
|
||||
/* Optional Contol function */
|
||||
void (*Control) (ITSMFDecoder * decoder, ITSMFControlMsg control_msg, uint32 *arg);
|
||||
/* Decode a sample with extended interface. */
|
||||
int (*DecodeEx) (ITSMFDecoder * decoder, const uint8 * data, uint32 data_size, uint32 extensions,
|
||||
uint64 start_time, uint64 end_time, uint64 duration);
|
||||
/* Get current play time */
|
||||
uint64 (*GetRunningTime) (ITSMFDecoder * decoder);
|
||||
/* Update Gstreamer Rendering Area */
|
||||
void (*UpdateRenderingArea) (ITSMFDecoder * decoder, int newX, int newY, int newWidth, int newHeight, int numRectangles, RDP_RECT *rectangles);
|
||||
/* Change Gstreamer Audio Volume */
|
||||
void (*ChangeVolume) (ITSMFDecoder * decoder, uint32 newVolume, uint32 muted);
|
||||
/* Check buffer level */
|
||||
uint32 (*BufferLevel) (ITSMFDecoder * decoder);
|
||||
};
|
||||
|
||||
#define TSMF_DECODER_EXPORT_FUNC_NAME "TSMFDecoderEntry"
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Video Redirection Virtual Channel - Interface Manipulation
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
* Copyright 2012 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -118,14 +119,23 @@ int tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TSMF_PRESENTATION* pexisted = 0;
|
||||
|
||||
int tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
|
||||
{
|
||||
int error = 0;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
if (pexisted)
|
||||
{
|
||||
ifman->output_pending = false;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
presentation = tsmf_presentation_new(stream_get_tail(ifman->input), ifman->channel_callback);
|
||||
pexisted = presentation;
|
||||
if (presentation == NULL)
|
||||
error = 1;
|
||||
else
|
||||
@ -208,6 +218,8 @@ int tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
|
||||
if (presentation)
|
||||
tsmf_presentation_free(presentation);
|
||||
|
||||
pexisted = 0;
|
||||
|
||||
stream_check_size(ifman->output, 4);
|
||||
stream_write_uint32(ifman->output, 0); /* Result */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
@ -216,14 +228,42 @@ int tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
|
||||
|
||||
int tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
DEBUG_DVC("on stream volume");
|
||||
TSMF_PRESENTATION* presentation;
|
||||
presentation = tsmf_presentation_find_by_id(stream_get_tail(ifman->input));
|
||||
if (presentation)
|
||||
{
|
||||
stream_seek(ifman->input, 16);
|
||||
uint32 newVolume;
|
||||
uint32 muted;
|
||||
stream_read_uint32(ifman->input, newVolume);
|
||||
DEBUG_DVC("on stream volume: new volume=[%d]", newVolume);
|
||||
stream_read_uint32(ifman->input, muted);
|
||||
DEBUG_DVC("on stream volume: muted=[%d]", muted);
|
||||
tsmf_presentation_volume_changed(presentation, newVolume, muted);
|
||||
}
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
|
||||
ifman->output_pending = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
DEBUG_DVC("on channel volume");
|
||||
TSMF_PRESENTATION* presentation;
|
||||
presentation = tsmf_presentation_find_by_id(stream_get_tail(ifman->input));
|
||||
if (presentation)
|
||||
{
|
||||
stream_seek(ifman->input, 16);
|
||||
uint32 channelVolume;
|
||||
uint32 changedChannel;
|
||||
stream_read_uint32(ifman->input, channelVolume);
|
||||
DEBUG_DVC("on channel volume: channel volume=[%d]", channelVolume);
|
||||
stream_read_uint32(ifman->input, changedChannel);
|
||||
DEBUG_DVC("on stream volume: changed channel=[%d]", changedChannel);
|
||||
}
|
||||
ifman->output_pending = true;
|
||||
return 0;
|
||||
}
|
||||
@ -434,6 +474,14 @@ int tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
ifman->output_pending = true;
|
||||
|
||||
/* Added pause control so gstreamer pipeline can be paused accordingly */
|
||||
TSMF_PRESENTATION* presentation;
|
||||
presentation = tsmf_presentation_find_by_id(stream_get_tail(ifman->input));
|
||||
if (presentation)
|
||||
tsmf_presentation_paused(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -441,6 +489,14 @@ int tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
ifman->output_pending = true;
|
||||
|
||||
/* Added restart control so gstreamer pipeline can be resumed accordingly */
|
||||
TSMF_PRESENTATION* presentation;
|
||||
presentation = tsmf_presentation_find_by_id(stream_get_tail(ifman->input));
|
||||
if (presentation)
|
||||
tsmf_presentation_restarted(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Video Redirection Virtual Channel - Media Container
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
* Copyright 2012 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -20,6 +21,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
#include <freerdp/utils/stream.h>
|
||||
@ -123,6 +126,9 @@ struct _TSMF_SAMPLE
|
||||
};
|
||||
|
||||
static LIST* presentation_list = NULL;
|
||||
static uint64 last_played_audio_time = 0;
|
||||
static pthread_mutex_t tsmf_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int TERMINATING = 0;
|
||||
|
||||
static uint64 get_current_time(void)
|
||||
{
|
||||
@ -145,33 +151,41 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync)
|
||||
|
||||
if (sync)
|
||||
{
|
||||
if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO)
|
||||
if (stream->decoder)
|
||||
{
|
||||
/* Check if some other stream has earlier sample that needs to be played first */
|
||||
if (stream->last_end_time > AUDIO_TOLERANCE)
|
||||
if (stream->decoder->GetDecodedData)
|
||||
{
|
||||
freerdp_mutex_lock(presentation->mutex);
|
||||
for (item = presentation->stream_list->head; item; item = item->next)
|
||||
if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO)
|
||||
{
|
||||
s = (TSMF_STREAM*) item->data;
|
||||
if (s != stream && !s->eos && s->last_end_time &&
|
||||
s->last_end_time < stream->last_end_time - AUDIO_TOLERANCE)
|
||||
/* Check if some other stream has earlier sample that needs to be played first */
|
||||
if (stream->last_end_time > AUDIO_TOLERANCE)
|
||||
{
|
||||
pending = true;
|
||||
break;
|
||||
freerdp_mutex_lock(presentation->mutex);
|
||||
for (item = presentation->stream_list->head; item; item = item->next)
|
||||
{
|
||||
s = (TSMF_STREAM*) item->data;
|
||||
if (s != stream && !s->eos && s->last_end_time &&
|
||||
s->last_end_time < stream->last_end_time - AUDIO_TOLERANCE)
|
||||
{
|
||||
pending = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
freerdp_mutex_unlock(presentation->mutex);
|
||||
}
|
||||
}
|
||||
freerdp_mutex_unlock(presentation->mutex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stream->last_end_time > presentation->audio_end_time)
|
||||
{
|
||||
pending = true;
|
||||
else
|
||||
{
|
||||
if (stream->last_end_time > presentation->audio_end_time)
|
||||
{
|
||||
pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pending)
|
||||
return NULL;
|
||||
|
||||
@ -224,6 +238,15 @@ static void tsmf_stream_process_ack(TSMF_STREAM* stream)
|
||||
|
||||
TSMF_PRESENTATION* tsmf_presentation_new(const uint8* guid, IWTSVirtualChannelCallback* pChannelCallback)
|
||||
{
|
||||
pthread_t thid = pthread_self();
|
||||
FILE* fout = NULL;
|
||||
fout = fopen("/tmp/tsmf.tid", "wt");
|
||||
if (fout)
|
||||
{
|
||||
fprintf(fout, "%d\n", (int) thid);
|
||||
fclose(fout);
|
||||
}
|
||||
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(guid);
|
||||
@ -423,7 +446,14 @@ static void tsmf_sample_playback(TSMF_SAMPLE* sample)
|
||||
TSMF_STREAM* stream = sample->stream;
|
||||
|
||||
if (stream->decoder)
|
||||
ret = stream->decoder->Decode(stream->decoder, sample->data, sample->data_size, sample->extensions);
|
||||
{
|
||||
if (stream->decoder->DecodeEx)
|
||||
ret = stream->decoder->DecodeEx(stream->decoder, sample->data, sample->data_size, sample->extensions,
|
||||
sample->start_time, sample->end_time, sample->duration);
|
||||
else
|
||||
ret = stream->decoder->Decode(stream->decoder, sample->data, sample->data_size, sample->extensions);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
tsmf_sample_ack(sample);
|
||||
@ -450,32 +480,139 @@ static void tsmf_sample_playback(TSMF_SAMPLE* sample)
|
||||
|
||||
ret = false ;
|
||||
if (stream->decoder->GetDecodedDimension)
|
||||
ret = stream->decoder->GetDecodedDimension(stream->decoder, &width, &height);
|
||||
if (ret && (width != stream->width || height != stream->height))
|
||||
{
|
||||
DEBUG_DVC("video dimension changed to %d x %d", width, height);
|
||||
stream->width = width;
|
||||
stream->height = height;
|
||||
ret = stream->decoder->GetDecodedDimension(stream->decoder, &width, &height);
|
||||
if (ret && (width != stream->width || height != stream->height))
|
||||
{
|
||||
DEBUG_DVC("video dimension changed to %d x %d", width, height);
|
||||
stream->width = width;
|
||||
stream->height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stream->decoder->GetDecodedData)
|
||||
{
|
||||
sample->data = stream->decoder->GetDecodedData(stream->decoder, &sample->decoded_size);
|
||||
switch (sample->stream->major_type)
|
||||
{
|
||||
case TSMF_MAJOR_TYPE_VIDEO:
|
||||
tsmf_sample_playback_video(sample);
|
||||
tsmf_sample_ack(sample);
|
||||
tsmf_sample_free(sample);
|
||||
break;
|
||||
case TSMF_MAJOR_TYPE_AUDIO:
|
||||
tsmf_sample_playback_audio(sample);
|
||||
tsmf_sample_queue_ack(sample);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (sample->stream->major_type)
|
||||
else
|
||||
{
|
||||
case TSMF_MAJOR_TYPE_VIDEO:
|
||||
tsmf_sample_playback_video(sample);
|
||||
tsmf_sample_ack(sample);
|
||||
tsmf_sample_free(sample);
|
||||
break;
|
||||
case TSMF_MAJOR_TYPE_AUDIO:
|
||||
tsmf_sample_playback_audio(sample);
|
||||
tsmf_sample_queue_ack(sample);
|
||||
break;
|
||||
}
|
||||
TSMF_STREAM * stream = sample->stream;
|
||||
uint64 ack_anticipation_time = get_current_time();
|
||||
uint64 currentRunningTime = sample->start_time;
|
||||
uint32 bufferLevel = 0;
|
||||
if (stream->decoder->GetRunningTime)
|
||||
{
|
||||
currentRunningTime = stream->decoder->GetRunningTime(stream->decoder);
|
||||
}
|
||||
if (stream->decoder->BufferLevel)
|
||||
{
|
||||
bufferLevel = stream->decoder->BufferLevel(stream->decoder);
|
||||
}
|
||||
switch (sample->stream->major_type)
|
||||
{
|
||||
case TSMF_MAJOR_TYPE_VIDEO:
|
||||
{
|
||||
TSMF_PRESENTATION * presentation = sample->stream->presentation;
|
||||
/*
|
||||
* Tell gstreamer that presentation screen area has moved.
|
||||
* So it can render on the new area.
|
||||
*/
|
||||
if (presentation->last_x != presentation->output_x || presentation->last_y != presentation->output_y ||
|
||||
presentation->last_width != presentation->output_width || presentation->last_height != presentation->output_height)
|
||||
{
|
||||
presentation->last_x = presentation->output_x;
|
||||
presentation->last_y = presentation->output_y;
|
||||
presentation->last_width = presentation->output_width;
|
||||
presentation->last_height = presentation->output_height;
|
||||
if(stream->decoder->UpdateRenderingArea)
|
||||
{
|
||||
stream->decoder->UpdateRenderingArea(stream->decoder, presentation->output_x, presentation->output_y,
|
||||
presentation->output_width, presentation->output_height, presentation->output_num_rects, presentation->output_rects);
|
||||
}
|
||||
}
|
||||
if ( presentation->last_num_rects != presentation->output_num_rects || (presentation->last_rects && presentation->output_rects &&
|
||||
memcmp(presentation->last_rects, presentation->output_rects, presentation->last_num_rects * sizeof(RDP_RECT)) != 0))
|
||||
{
|
||||
if (presentation->last_rects)
|
||||
{
|
||||
xfree(presentation->last_rects);
|
||||
presentation->last_rects = NULL;
|
||||
}
|
||||
presentation->last_num_rects = presentation->output_num_rects;
|
||||
if (presentation->last_num_rects > 0)
|
||||
{
|
||||
presentation->last_rects = xzalloc(presentation->last_num_rects * sizeof(RDP_RECT));
|
||||
memcpy(presentation->last_rects, presentation->output_rects, presentation->last_num_rects * sizeof(RDP_RECT));
|
||||
}
|
||||
if(stream->decoder->UpdateRenderingArea)
|
||||
{
|
||||
stream->decoder->UpdateRenderingArea(stream->decoder, presentation->output_x, presentation->output_y,
|
||||
presentation->output_width, presentation->output_height, presentation->output_num_rects, presentation->output_rects);
|
||||
}
|
||||
}
|
||||
|
||||
if (bufferLevel < 24)
|
||||
{
|
||||
ack_anticipation_time += sample->duration;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentRunningTime > sample->start_time)
|
||||
{
|
||||
ack_anticipation_time += sample->duration;
|
||||
}
|
||||
else if(currentRunningTime == 0)
|
||||
{
|
||||
ack_anticipation_time += sample->duration;
|
||||
}
|
||||
else
|
||||
{
|
||||
ack_anticipation_time += (sample->start_time - currentRunningTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TSMF_MAJOR_TYPE_AUDIO:
|
||||
{
|
||||
last_played_audio_time = currentRunningTime;
|
||||
if (bufferLevel < 2)
|
||||
{
|
||||
ack_anticipation_time += sample->duration;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentRunningTime > sample->start_time)
|
||||
{
|
||||
ack_anticipation_time += sample->duration;
|
||||
}
|
||||
else if(currentRunningTime == 0)
|
||||
{
|
||||
ack_anticipation_time += sample->duration;
|
||||
}
|
||||
else
|
||||
{
|
||||
ack_anticipation_time += (sample->start_time - currentRunningTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
sample->ack_time = ack_anticipation_time;
|
||||
tsmf_sample_queue_ack(sample);
|
||||
}
|
||||
}
|
||||
|
||||
static void* tsmf_stream_playback_func(void* arg)
|
||||
@ -489,13 +626,19 @@ static void* tsmf_stream_playback_func(void* arg)
|
||||
if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO &&
|
||||
stream->sample_rate && stream->channels && stream->bits_per_sample)
|
||||
{
|
||||
stream->audio = tsmf_load_audio_device(
|
||||
presentation->audio_name && presentation->audio_name[0] ? presentation->audio_name : NULL,
|
||||
presentation->audio_device && presentation->audio_device[0] ? presentation->audio_device : NULL);
|
||||
if (stream->audio)
|
||||
if (stream->decoder)
|
||||
{
|
||||
stream->audio->SetFormat(stream->audio,
|
||||
stream->sample_rate, stream->channels, stream->bits_per_sample);
|
||||
if (stream->decoder->GetDecodedData)
|
||||
{
|
||||
stream->audio = tsmf_load_audio_device(
|
||||
presentation->audio_name && presentation->audio_name[0] ? presentation->audio_name : NULL,
|
||||
presentation->audio_device && presentation->audio_device[0] ? presentation->audio_device : NULL);
|
||||
if (stream->audio)
|
||||
{
|
||||
stream->audio->SetFormat(stream->audio,
|
||||
stream->sample_rate, stream->channels, stream->bits_per_sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!freerdp_thread_is_stopped(stream->thread))
|
||||
@ -535,10 +678,99 @@ static void tsmf_stream_start(TSMF_STREAM* stream)
|
||||
|
||||
static void tsmf_stream_stop(TSMF_STREAM* stream)
|
||||
{
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
if (!stream->decoder)
|
||||
return;
|
||||
|
||||
if (freerdp_thread_is_running(stream->thread))
|
||||
{
|
||||
freerdp_thread_stop(stream->thread);
|
||||
}
|
||||
if (stream->decoder->Control)
|
||||
{
|
||||
stream->decoder->Control(stream->decoder, Control_Flush, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_stream_pause(TSMF_STREAM* stream)
|
||||
{
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
if (!stream->decoder)
|
||||
return;
|
||||
|
||||
if (stream->decoder->Control)
|
||||
{
|
||||
stream->decoder->Control(stream->decoder, Control_Pause, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_stream_restart(TSMF_STREAM* stream)
|
||||
{
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
if (!stream->decoder)
|
||||
return;
|
||||
|
||||
if (stream->decoder->Control)
|
||||
{
|
||||
stream->decoder->Control(stream->decoder, Control_Restart, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_stream_change_volume(TSMF_STREAM* stream, uint32 newVolume, uint32 muted)
|
||||
{
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
if (!stream->decoder)
|
||||
return;
|
||||
|
||||
if (stream->decoder->ChangeVolume)
|
||||
{
|
||||
stream->decoder->ChangeVolume(stream->decoder, newVolume, muted);
|
||||
}
|
||||
}
|
||||
|
||||
void tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, uint32 newVolume, uint32 muted)
|
||||
{
|
||||
LIST_ITEM* item;
|
||||
TSMF_STREAM* stream;
|
||||
|
||||
for (item = presentation->stream_list->head; item; item = item->next)
|
||||
{
|
||||
stream = (TSMF_STREAM*) item->data;
|
||||
tsmf_stream_change_volume(stream, newVolume, muted);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void tsmf_presentation_paused(TSMF_PRESENTATION* presentation)
|
||||
{
|
||||
LIST_ITEM* item;
|
||||
TSMF_STREAM* stream;
|
||||
|
||||
for (item = presentation->stream_list->head; item; item = item->next)
|
||||
{
|
||||
stream = (TSMF_STREAM*) item->data;
|
||||
tsmf_stream_pause(stream);
|
||||
}
|
||||
}
|
||||
|
||||
void tsmf_presentation_restarted(TSMF_PRESENTATION* presentation)
|
||||
{
|
||||
LIST_ITEM* item;
|
||||
TSMF_STREAM* stream;
|
||||
|
||||
for (item = presentation->stream_list->head; item; item = item->next)
|
||||
{
|
||||
stream = (TSMF_STREAM*) item->data;
|
||||
tsmf_stream_restart(stream);
|
||||
}
|
||||
}
|
||||
|
||||
void tsmf_presentation_start(TSMF_PRESENTATION* presentation)
|
||||
@ -645,7 +877,9 @@ void tsmf_presentation_free(TSMF_PRESENTATION* presentation)
|
||||
TSMF_STREAM* stream;
|
||||
|
||||
tsmf_presentation_stop(presentation);
|
||||
freerdp_mutex_lock(presentation->mutex);
|
||||
list_remove(presentation_list, presentation);
|
||||
freerdp_mutex_unlock(presentation->mutex);
|
||||
|
||||
while (list_size(presentation->stream_list) > 0)
|
||||
{
|
||||
@ -757,17 +991,28 @@ void tsmf_stream_free(TSMF_STREAM* stream)
|
||||
list_free(stream->sample_ack_list);
|
||||
|
||||
if (stream->decoder)
|
||||
{
|
||||
stream->decoder->Free(stream->decoder);
|
||||
stream->decoder = 0;
|
||||
}
|
||||
|
||||
freerdp_thread_free(stream->thread);
|
||||
|
||||
xfree(stream);
|
||||
stream = 0;
|
||||
}
|
||||
|
||||
void tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pChannelCallback,
|
||||
uint32 sample_id, uint64 start_time, uint64 end_time, uint64 duration, uint32 extensions,
|
||||
uint32 data_size, uint8* data)
|
||||
{
|
||||
pthread_mutex_lock(&tsmf_mutex);
|
||||
if (TERMINATING)
|
||||
{
|
||||
pthread_mutex_unlock(&tsmf_mutex);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_unlock(&tsmf_mutex);
|
||||
TSMF_SAMPLE* sample;
|
||||
|
||||
sample = xnew(TSMF_SAMPLE);
|
||||
@ -788,8 +1033,51 @@ void tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pC
|
||||
freerdp_thread_unlock(stream->thread);
|
||||
}
|
||||
|
||||
static void tsmf_signal_handler(int s)
|
||||
{
|
||||
pthread_mutex_lock(&tsmf_mutex);
|
||||
TERMINATING = 1;
|
||||
pthread_mutex_unlock(&tsmf_mutex);
|
||||
LIST_ITEM* p_item;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
LIST_ITEM* s_item;
|
||||
TSMF_STREAM* _stream;
|
||||
if (presentation_list)
|
||||
{
|
||||
for (p_item = presentation_list->head; p_item; p_item = p_item->next)
|
||||
{
|
||||
presentation = (TSMF_PRESENTATION*) p_item->data;
|
||||
for (s_item = presentation->stream_list->head; s_item; s_item = s_item->next)
|
||||
{
|
||||
_stream = (TSMF_STREAM*) s_item->data;
|
||||
tsmf_stream_free(_stream);
|
||||
}
|
||||
tsmf_presentation_free(presentation);
|
||||
}
|
||||
}
|
||||
|
||||
unlink("/tmp/tsmf.tid");
|
||||
|
||||
if (s == SIGINT)
|
||||
{
|
||||
signal(s, SIG_DFL);
|
||||
kill(getpid(), s);
|
||||
}
|
||||
else if (s == SIGUSR1)
|
||||
{
|
||||
signal(s, SIG_DFL);
|
||||
}
|
||||
}
|
||||
|
||||
void tsmf_media_init(void)
|
||||
{
|
||||
struct sigaction sigtrap;
|
||||
sigtrap.sa_handler = tsmf_signal_handler;
|
||||
sigemptyset(&sigtrap.sa_mask);
|
||||
sigtrap.sa_flags = 0;
|
||||
sigaction(SIGINT, &sigtrap, 0);
|
||||
sigaction(SIGUSR1, &sigtrap, 0);
|
||||
|
||||
if (presentation_list == NULL)
|
||||
presentation_list = list_new();
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Video Redirection Virtual Channel - Media Container
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
* Copyright 2012 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -35,6 +36,9 @@ TSMF_PRESENTATION* tsmf_presentation_new(const uint8* guid, IWTSVirtualChannelCa
|
||||
TSMF_PRESENTATION* tsmf_presentation_find_by_id(const uint8* guid);
|
||||
void tsmf_presentation_start(TSMF_PRESENTATION* presentation);
|
||||
void tsmf_presentation_stop(TSMF_PRESENTATION* presentation);
|
||||
void tsmf_presentation_paused(TSMF_PRESENTATION* presentation);
|
||||
void tsmf_presentation_restarted(TSMF_PRESENTATION* presentation);
|
||||
void tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, uint32 newVolume, uint32 muted);
|
||||
void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation,
|
||||
uint32 x, uint32 y, uint32 width, uint32 height,
|
||||
int num_rects, RDP_RECT* rects);
|
||||
|
@ -60,7 +60,7 @@ static const char* const RAIL_ORDER_TYPE_STRINGS[] =
|
||||
"Execute Result"
|
||||
};
|
||||
|
||||
void rail_string_to_unicode_string(rdpRailOrder* rail_order, char* string, UNICODE_STRING* unicode_string)
|
||||
void rail_string_to_unicode_string(rdpRailOrder* rail_order, char* string, RAIL_UNICODE_STRING* unicode_string)
|
||||
{
|
||||
char* buffer;
|
||||
size_t length = 0;
|
||||
|
@ -54,7 +54,7 @@
|
||||
#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */
|
||||
#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */
|
||||
|
||||
void rail_string_to_unicode_string(rdpRailOrder* rail_order, char* string, UNICODE_STRING* unicode_string);
|
||||
void rail_string_to_unicode_string(rdpRailOrder* rail_order, char* string, RAIL_UNICODE_STRING* unicode_string);
|
||||
|
||||
void rail_read_handshake_order(STREAM* s, RAIL_HANDSHAKE_ORDER* handshake);
|
||||
void rail_read_server_exec_result_order(STREAM* s, RAIL_EXEC_RESULT_ORDER* exec_result);
|
||||
|
30
channels/skel/CMakeLists.txt
Normal file
30
channels/skel/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Client
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2011 O.S. Systems Software Ltda.
|
||||
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
|
||||
# Copyright 2011 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.
|
||||
|
||||
set(SKEL_SRCS
|
||||
skel_main.c
|
||||
skel_main.h
|
||||
)
|
||||
|
||||
add_library(skel ${SKEL_SRCS})
|
||||
set_target_properties(skel PROPERTIES PREFIX "")
|
||||
|
||||
target_link_libraries(skel freerdp-utils)
|
||||
|
||||
install(TARGETS skel DESTINATION ${FREERDP_PLUGIN_PATH})
|
7
channels/skel/readme.txt
Normal file
7
channels/skel/readme.txt
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
This is a skeleton virtual channel plugin for freerdp
|
||||
To create your own virtual channel plugin, copy this directory
|
||||
then change all references of "skel" to your plugin name
|
||||
remember, plugin name are 7 chars or less, no spaces or funny chars
|
||||
|
||||
Jay
|
125
channels/skel/skel_main.c
Normal file
125
channels/skel/skel_main.c
Normal file
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* Audio Output Virtual Channel
|
||||
*
|
||||
* Copyright 2009-2012 Jay Sorg
|
||||
* Copyright 2010-2012 Vic Lee
|
||||
*
|
||||
* 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 _WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
#include <freerdp/utils/stream.h>
|
||||
#include <freerdp/utils/list.h>
|
||||
#include <freerdp/utils/load_plugin.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#include "skel_main.h"
|
||||
|
||||
struct skel_plugin
|
||||
{
|
||||
rdpSvcPlugin plugin;
|
||||
|
||||
/* put your private data here */
|
||||
|
||||
};
|
||||
|
||||
static void skel_process_interval(rdpSvcPlugin* plugin)
|
||||
{
|
||||
printf("skel_process_interval:\n");
|
||||
}
|
||||
|
||||
static void skel_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
|
||||
{
|
||||
skelPlugin* skel = (skelPlugin*)plugin;
|
||||
STREAM* data_out;
|
||||
int bytes;
|
||||
|
||||
printf("skel_process_receive:\n");
|
||||
|
||||
if (skel == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* process data in(from server) here */
|
||||
/* here we just send the same data back */
|
||||
|
||||
bytes = stream_get_length(data_in);
|
||||
if (bytes > 0)
|
||||
{
|
||||
data_out = stream_new(bytes);
|
||||
stream_copy(data_out, data_in, bytes);
|
||||
/* svc_plugin_send takes ownership of data_out, that is why
|
||||
we do not free it */
|
||||
svc_plugin_send(plugin, data_out);
|
||||
}
|
||||
|
||||
stream_free(data_in);
|
||||
}
|
||||
|
||||
static void skel_process_connect(rdpSvcPlugin* plugin)
|
||||
{
|
||||
skelPlugin* skel = (skelPlugin*)plugin;
|
||||
DEBUG_SVC("connecting");
|
||||
|
||||
printf("skel_process_connect:\n");
|
||||
|
||||
if (skel == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* if you want a call from channel thread once is a while do this */
|
||||
plugin->interval_ms = 1000;
|
||||
plugin->interval_callback = skel_process_interval;
|
||||
|
||||
}
|
||||
|
||||
static void skel_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event)
|
||||
{
|
||||
printf("skel_process_event:\n");
|
||||
|
||||
/* events comming from main freerdp window to plugin */
|
||||
/* send them back with svc_plugin_send_event */
|
||||
|
||||
freerdp_event_free(event);
|
||||
}
|
||||
|
||||
static void skel_process_terminate(rdpSvcPlugin* plugin)
|
||||
{
|
||||
skelPlugin* skel = (skelPlugin*)plugin;
|
||||
|
||||
printf("skel_process_terminate:\n");
|
||||
|
||||
if (skel == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* put your cleanup here */
|
||||
|
||||
xfree(plugin);
|
||||
}
|
||||
|
||||
DEFINE_SVC_PLUGIN(skel, "skel",
|
||||
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP)
|
26
channels/skel/skel_main.h
Normal file
26
channels/skel/skel_main.h
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* Audio Output Virtual Channel
|
||||
*
|
||||
* Copyright 2012 Jay Sorg
|
||||
* Copyright 2010-2012 Vic Lee
|
||||
*
|
||||
* 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 __SKEL_MAIN_H
|
||||
#define __SKEL_MAIN_H
|
||||
|
||||
typedef struct skel_plugin skelPlugin;
|
||||
|
||||
#endif /* __SKEL_MAIN_H */
|
@ -3,6 +3,7 @@
|
||||
* X11 Windows
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012 HP Development Company, LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -18,9 +19,14 @@
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/ipc.h>
|
||||
|
||||
#include <freerdp/rail.h>
|
||||
#include <freerdp/utils/rail.h>
|
||||
@ -61,6 +67,9 @@
|
||||
|
||||
#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
|
||||
|
||||
/*to be accessed by gstreamer plugin*/
|
||||
#define SHARED_MEM_KEY 7777
|
||||
|
||||
struct _PropMotifWmHints
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -269,6 +278,19 @@ void xf_SetWindowText(xfInfo *xfi, xfWindow* window, char *name)
|
||||
XStoreName(xfi->display, window->handle, name);
|
||||
}
|
||||
|
||||
static void xf_SetWindowPID(xfInfo* xfi, xfWindow* window, pid_t pid)
|
||||
{
|
||||
Atom am_wm_pid;
|
||||
|
||||
if (pid == 0)
|
||||
pid = getpid();
|
||||
|
||||
am_wm_pid = XInternAtom(xfi->display, "_NET_WM_PID", False);
|
||||
|
||||
XChangeProperty(xfi->display, window->handle, am_wm_pid, XA_CARDINAL,
|
||||
32, PropModeReplace, (unsigned char *)&pid, 1);
|
||||
}
|
||||
|
||||
xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height, boolean decorations)
|
||||
{
|
||||
xfWindow* window;
|
||||
@ -294,6 +316,24 @@ xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height,
|
||||
CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
|
||||
CWBorderPixel | CWWinGravity | CWBitGravity, &xfi->attribs);
|
||||
|
||||
int shmid = shmget(SHARED_MEM_KEY, sizeof(int), IPC_CREAT | 0666);
|
||||
if (shmid < 0)
|
||||
{
|
||||
DEBUG_X11("xf_CreateDesktopWindow: failed to get access to shared memory - shmget()\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int *xfwin = shmat(shmid, NULL, 0);
|
||||
if (xfwin == (int *) -1)
|
||||
{
|
||||
DEBUG_X11("xf_CreateDesktopWindow: failed to assign pointer to the memory address - shmat()\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
*xfwin = (int)window->handle;
|
||||
}
|
||||
}
|
||||
|
||||
class_hints = XAllocClassHint();
|
||||
|
||||
if (class_hints != NULL)
|
||||
@ -306,6 +346,7 @@ xfWindow* xf_CreateDesktopWindow(xfInfo* xfi, char* name, int width, int height,
|
||||
|
||||
xf_ResizeDesktopWindow(xfi, window, width, height);
|
||||
xf_SetWindowDecorations(xfi, window, decorations);
|
||||
xf_SetWindowPID(xfi, window, 0);
|
||||
|
||||
input_mask =
|
||||
KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
|
||||
@ -463,6 +504,7 @@ xfWindow* xf_CreateWindow(xfInfo* xfi, rdpWindow* wnd, int x, int y, int width,
|
||||
|
||||
xf_SetWindowDecorations(xfi, window, window->decorations);
|
||||
xf_SetWindowStyle(xfi, window, wnd->style, wnd->extendedStyle);
|
||||
xf_SetWindowPID(xfi, window, 0);
|
||||
xf_ShowWindow(xfi, window, WINDOW_SHOW);
|
||||
|
||||
XMapWindow(xfi->display, window->handle);
|
||||
|
@ -288,6 +288,26 @@
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>--authonly</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Only authenticates. This is useful to test your credentials (username and password).
|
||||
Returns status code 0 if the client can connect, 1 otherwise. Requires a username,
|
||||
password and connection host at the command line.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>--from-stdin</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Prompts for unspecified arguments -u username, -p password, -d domain and connection host.
|
||||
This is useful to hide arguments from ps. Also useful for scripts that will feed these arguments
|
||||
to the client via (what else?) stdin.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>--no-fastpath</term>
|
||||
<listitem>
|
||||
|
@ -3,6 +3,7 @@
|
||||
* X11 Client
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012 HP Development Company, LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -245,6 +246,14 @@ void xf_hw_desktop_resize(rdpContext* context)
|
||||
xfi->drawing = xfi->primary;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XSetFunction(xfi->display, xfi->gc, GXcopy);
|
||||
XSetFillStyle(xfi->display, xfi->gc, FillSolid);
|
||||
XSetForeground(xfi->display, xfi->gc, 0);
|
||||
XFillRectangle(xfi->display, xfi->drawable, xfi->gc,
|
||||
0, 0, xfi->width, xfi->height);
|
||||
}
|
||||
}
|
||||
|
||||
boolean xf_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount)
|
||||
@ -280,6 +289,8 @@ void xf_create_window(xfInfo* xfi)
|
||||
char* win_title;
|
||||
int width, height;
|
||||
|
||||
memset(&xevent, 0x00, sizeof(xevent));
|
||||
|
||||
width = xfi->width;
|
||||
height = xfi->height;
|
||||
|
||||
@ -479,7 +490,7 @@ boolean xf_pre_connect(freerdp* instance)
|
||||
if (arg_parse_result < 0)
|
||||
{
|
||||
if (arg_parse_result == FREERDP_ARGS_PARSE_FAILURE)
|
||||
printf("failed to parse arguments.\n");
|
||||
fprintf(stderr, "%s:%d: failed to parse arguments.\n", __FILE__, __LINE__);
|
||||
|
||||
exit(XF_EXIT_PARSE_ARGUMENTS);
|
||||
}
|
||||
@ -521,6 +532,21 @@ boolean xf_pre_connect(freerdp* instance)
|
||||
|
||||
freerdp_channels_pre_connect(xfi->_context->channels, instance);
|
||||
|
||||
if (settings->authentication_only) {
|
||||
/* Check --authonly has a username and password. */
|
||||
if (settings->username == NULL ) {
|
||||
fprintf(stderr, "--authonly, but no -u username. Please provide one.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (settings->password == NULL ) {
|
||||
fprintf(stderr, "--authonly, but no -p password. Please provide one.\n");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "%s:%d: Authenication only. Don't connect to X.\n", __FILE__, __LINE__);
|
||||
// Avoid XWindows initialization and configuration below.
|
||||
return true;
|
||||
}
|
||||
|
||||
xfi->display = XOpenDisplay(NULL);
|
||||
|
||||
if (xfi->display == NULL)
|
||||
@ -775,7 +801,7 @@ boolean xf_authenticate(freerdp* instance, char** username, char** password, cha
|
||||
// But it doesn't do anything to fix it...
|
||||
*password = xmalloc(password_size * sizeof(char));
|
||||
|
||||
if (freerdp_passphrase_read("Password: ", *password, password_size) == NULL)
|
||||
if (freerdp_passphrase_read("Password: ", *password, password_size, instance->settings->from_stdin) == NULL)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -1067,7 +1093,15 @@ int xfreerdp_run(freerdp* instance)
|
||||
memset(wfds, 0, sizeof(wfds));
|
||||
memset(&timeout, 0, sizeof(struct timeval));
|
||||
|
||||
if (!freerdp_connect(instance))
|
||||
boolean status = freerdp_connect(instance);
|
||||
/* Connection succeeded. --authonly ? */
|
||||
if (instance->settings->authentication_only) {
|
||||
freerdp_disconnect(instance);
|
||||
fprintf(stderr, "%s:%d: Authentication only, exit status %d\n", __FILE__, __LINE__, !status);
|
||||
exit(!status);
|
||||
}
|
||||
|
||||
if (!status)
|
||||
{
|
||||
xf_free(((xfContext*) instance->context)->xfi);
|
||||
return XF_EXIT_CONN_FAILED;
|
||||
@ -1156,6 +1190,31 @@ int xfreerdp_run(freerdp* instance)
|
||||
xf_process_channel_event(channels, instance);
|
||||
}
|
||||
|
||||
FILE *fin = fopen("/tmp/tsmf.tid", "rt");
|
||||
if(fin)
|
||||
{
|
||||
int thid = 0;
|
||||
fscanf(fin, "%d", &thid);
|
||||
fclose(fin);
|
||||
pthread_kill((pthread_t) thid, SIGUSR1);
|
||||
|
||||
FILE *fin1 = fopen("/tmp/tsmf.tid", "rt");
|
||||
int timeout = 5;
|
||||
while (fin1)
|
||||
{
|
||||
fclose(fin1);
|
||||
sleep(1);
|
||||
timeout--;
|
||||
if (timeout <= 0)
|
||||
{
|
||||
unlink("/tmp/tsmf.tid");
|
||||
pthread_kill((pthread_t) thid, SIGKILL);
|
||||
break;
|
||||
}
|
||||
fin1 = fopen("/tmp/tsmf.tid", "rt");
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = freerdp_error_info(instance);
|
||||
|
||||
|
@ -24,3 +24,4 @@ target_link_libraries(freerdp-test freerdp-core)
|
||||
target_link_libraries(freerdp-test freerdp-gdi)
|
||||
target_link_libraries(freerdp-test freerdp-utils)
|
||||
target_link_libraries(freerdp-test freerdp-channels ${CMAKE_DL_LIBS})
|
||||
|
||||
|
@ -231,6 +231,7 @@ int tfreerdp_run(freerdp* instance)
|
||||
|
||||
max_fds = 0;
|
||||
FD_ZERO(&rfds_set);
|
||||
FD_ZERO(&wfds_set);
|
||||
|
||||
for (i = 0; i < rcount; i++)
|
||||
{
|
||||
|
2
cmake/FindGstreamer.cmake
Normal file
2
cmake/FindGstreamer.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
pkg_check_modules(GSTREAMER gstreamer-plugins-base-0.10 gstreamer-0.10)
|
||||
|
47
cmake/FindXRandR.cmake
Normal file
47
cmake/FindXRandR.cmake
Normal file
@ -0,0 +1,47 @@
|
||||
# - Find XRANDR
|
||||
# Find the XRANDR libraries
|
||||
#
|
||||
# This module defines the following variables:
|
||||
# XRANDR_FOUND - true if XRANDR_INCLUDE_DIR & XRANDR_LIBRARY are found
|
||||
# XRANDR_LIBRARIES - Set when XRANDR_LIBRARY is found
|
||||
# XRANDR_INCLUDE_DIRS - Set when XRANDR_INCLUDE_DIR is found
|
||||
#
|
||||
# XRANDR_INCLUDE_DIR - where to find Xrandr.h, etc.
|
||||
# XRANDR_LIBRARY - the XRANDR library
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2012 Alam Arias <Alam.GBC@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.
|
||||
#=============================================================================
|
||||
|
||||
find_path(XRANDR_INCLUDE_DIR NAMES X11/extensions/Xrandr.h
|
||||
PATH_SUFFIXES X11/extensions
|
||||
DOC "The XRANDR include directory"
|
||||
)
|
||||
|
||||
find_library(XRANDR_LIBRARY NAMES Xrandr
|
||||
DOC "The XRANDR library"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(XRANDR DEFAULT_MSG XRANDR_LIBRARY XRANDR_INCLUDE_DIR)
|
||||
|
||||
if(XRANDR_FOUND)
|
||||
set( XRANDR_LIBRARIES ${XRANDR_LIBRARY} )
|
||||
set( XRANDR_INCLUDE_DIRS ${XRANDR_INCLUDE_DIR} )
|
||||
endif()
|
||||
|
||||
mark_as_advanced(XRANDR_INCLUDE_DIR XRANDR_LIBRARY)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#cmakedefine WITH_PROFILER
|
||||
#cmakedefine WITH_SSE2
|
||||
#cmakedefine WITH_NEON
|
||||
#cmakedefine WITH_NATIVE_SSPI
|
||||
|
||||
/* Debug */
|
||||
#cmakedefine WITH_DEBUG_CERTIFICATE
|
||||
|
@ -133,7 +133,7 @@ void test_InitializeSecurityContext(void)
|
||||
uint32 fContextReq;
|
||||
void* output_buffer;
|
||||
CtxtHandle context;
|
||||
uint32 pfContextAttr;
|
||||
ULONG pfContextAttr;
|
||||
SECURITY_STATUS status;
|
||||
CredHandle credentials;
|
||||
TimeStamp expiration;
|
||||
@ -194,11 +194,11 @@ void test_InitializeSecurityContext(void)
|
||||
return;
|
||||
}
|
||||
|
||||
printf("cBuffers: %d ulVersion: %d\n", output_SecBuffer_desc.cBuffers, output_SecBuffer_desc.ulVersion);
|
||||
printf("cBuffers: %ld ulVersion: %ld\n", output_SecBuffer_desc.cBuffers, output_SecBuffer_desc.ulVersion);
|
||||
|
||||
p_SecBuffer = &output_SecBuffer_desc.pBuffers[0];
|
||||
|
||||
printf("BufferType: 0x%04X cbBuffer:%d\n", p_SecBuffer->BufferType, p_SecBuffer->cbBuffer);
|
||||
printf("BufferType: 0x%04lX cbBuffer:%ld\n", p_SecBuffer->BufferType, p_SecBuffer->cbBuffer);
|
||||
|
||||
freerdp_hexdump((uint8*) p_SecBuffer->pvBuffer, p_SecBuffer->cbBuffer);
|
||||
|
||||
|
@ -177,7 +177,7 @@ void passphrase_read_prompts_to_tty()
|
||||
{
|
||||
static const int read_nbyte = 11;
|
||||
int masterfd;
|
||||
char* slavedevice;
|
||||
char* slavedevice = NULL;
|
||||
char read_buf[read_nbyte];
|
||||
fd_set fd_set_write;
|
||||
|
||||
@ -207,7 +207,7 @@ void passphrase_read_prompts_to_tty()
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
close(masterfd);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size, 0);
|
||||
close(slavefd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@ -233,7 +233,7 @@ void passphrase_read_reads_from_tty()
|
||||
static const int read_nbyte = 11;
|
||||
int masterfd;
|
||||
int pipe_ends[2];
|
||||
char* slavedevice;
|
||||
char* slavedevice = NULL;
|
||||
char read_buf[read_nbyte];
|
||||
fd_set fd_set_write;
|
||||
|
||||
@ -267,7 +267,7 @@ void passphrase_read_reads_from_tty()
|
||||
close(STDERR_FILENO);
|
||||
close(masterfd);
|
||||
close(pipe_ends[0]);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size, 0);
|
||||
write(pipe_ends[1], buffer, password_size);
|
||||
close(slavefd);
|
||||
close(pipe_ends[1]);
|
||||
@ -298,7 +298,7 @@ void passphrase_read_turns_off_echo_during_read()
|
||||
{
|
||||
static const int read_nbyte = 11;
|
||||
int masterfd, slavefd;
|
||||
char* slavedevice;
|
||||
char* slavedevice = NULL;
|
||||
char read_buf[read_nbyte];
|
||||
fd_set fd_set_write;
|
||||
struct termios term_flags;
|
||||
@ -343,7 +343,7 @@ void passphrase_read_turns_off_echo_during_read()
|
||||
close(STDERR_FILENO);
|
||||
close(masterfd);
|
||||
close(slavefd);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size, 0);
|
||||
close(child_slavefd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@ -371,7 +371,7 @@ void passphrase_read_resets_terminal_after_read()
|
||||
{
|
||||
static const int read_nbyte = 11;
|
||||
int masterfd, slavefd, status;
|
||||
char* slavedevice;
|
||||
char* slavedevice = NULL;
|
||||
char read_buf[read_nbyte];
|
||||
fd_set fd_set_write;
|
||||
struct termios term_flags;
|
||||
@ -417,7 +417,7 @@ void passphrase_read_resets_terminal_after_read()
|
||||
close(STDERR_FILENO);
|
||||
close(masterfd);
|
||||
close(slavefd);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size, 0);
|
||||
close(child_slavefd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@ -446,7 +446,7 @@ void passphrase_read_turns_on_newline_echo_during_read()
|
||||
{
|
||||
static const int read_nbyte = 11;
|
||||
int masterfd, slavefd;
|
||||
char* slavedevice;
|
||||
char* slavedevice = NULL;
|
||||
char read_buf[read_nbyte];
|
||||
fd_set fd_set_write;
|
||||
struct termios term_flags;
|
||||
@ -491,7 +491,7 @@ void passphrase_read_turns_on_newline_echo_during_read()
|
||||
close(STDERR_FILENO);
|
||||
close(masterfd);
|
||||
close(slavefd);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size, 0);
|
||||
close(child_slavefd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@ -543,7 +543,7 @@ void passphrase_read_prompts_to_stderr_when_no_tty()
|
||||
|
||||
dup2(stdin_pipe[0], STDIN_FILENO);
|
||||
dup2(stderr_pipe[1], STDERR_FILENO);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size, 0);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
@ -595,7 +595,7 @@ void passphrase_read_reads_from_stdin_when_no_tty()
|
||||
|
||||
dup2(stdin_pipe[0], STDIN_FILENO);
|
||||
dup2(stderr_pipe[1], STDERR_FILENO);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size);
|
||||
freerdp_passphrase_read("Password: ", buffer, password_size, 0);
|
||||
write(result_pipe[1], buffer, strlen(buffer) + (size_t) 1);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@ -636,7 +636,7 @@ void test_passphrase_read(void)
|
||||
void handle_signals_resets_terminal(void)
|
||||
{
|
||||
int status, masterfd;
|
||||
char* slavedevice;
|
||||
char* slavedevice = NULL;
|
||||
struct termios test_flags;
|
||||
pid_t child_pid;
|
||||
|
||||
|
@ -42,7 +42,8 @@ typedef struct WTSVirtualChannelManager WTSVirtualChannelManager;
|
||||
typedef enum _WTS_VIRTUAL_CLASS
|
||||
{
|
||||
WTSVirtualClientData,
|
||||
WTSVirtualFileHandle
|
||||
WTSVirtualFileHandle,
|
||||
WTSVirtualChannelReady
|
||||
} WTS_VIRTUAL_CLASS;
|
||||
|
||||
/**
|
||||
@ -61,7 +62,8 @@ FREERDP_API boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChanne
|
||||
* The original MS API has 'DWORD SessionId' as the first argument, while we
|
||||
* use our WTSVirtualChannelManager object instead.
|
||||
*
|
||||
* This functions should be called only from the main thread.
|
||||
* Static virtual channels must be opened from the main thread. Dynamic virtual channels
|
||||
* can be opened from any thread.
|
||||
*/
|
||||
FREERDP_API void* WTSVirtualChannelOpenEx(
|
||||
/* __in */ WTSVirtualChannelManager* vcm,
|
||||
|
@ -50,6 +50,7 @@ struct rdp_certificate_store
|
||||
FREERDP_API rdpCertificateData* certificate_data_new(char* hostname, char* fingerprint);
|
||||
FREERDP_API void certificate_data_free(rdpCertificateData* certificate_data);
|
||||
FREERDP_API rdpCertificateStore* certificate_store_new(rdpSettings* settings);
|
||||
FREERDP_API void certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data);
|
||||
FREERDP_API void certificate_store_free(rdpCertificateStore* certificate_store);
|
||||
FREERDP_API int certificate_data_match(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data);
|
||||
FREERDP_API void certificate_data_print(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data);
|
||||
|
@ -23,41 +23,14 @@
|
||||
#include <freerdp/crypto/er.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
|
||||
#define der_read_length er_read_length
|
||||
#define _der_skip_length _er_skip_length
|
||||
#define der_get_content_length er_get_content_length
|
||||
#define der_read_universal_tag er_read_universal_tag
|
||||
#define der_write_universal_tag er_write_universal_tag
|
||||
#define der_read_application_tag er_read_application_tag
|
||||
#define der_read_enumerated er_read_enumerated
|
||||
#define der_read_contextual_tag er_read_contextual_tag
|
||||
#define der_skip_contextual_tag er_skip_contextual_tag
|
||||
#define der_read_sequence_tag er_read_sequence_tag
|
||||
#define der_skip_sequence er_skip_sequence
|
||||
#define der_skip_sequence_tag er_skip_sequence_tag
|
||||
#define der_read_bit_string er_read_bit_string
|
||||
#define der_read_octet_string er_read_octet_string
|
||||
#define der_skip_octet_string er_skip_octet_string
|
||||
#define der_read_boolean er_read_boolean
|
||||
#define der_write_boolean er_write_boolean
|
||||
#define der_read_integer er_read_integer
|
||||
#define der_write_integer er_write_integer
|
||||
#define der_read_integer_length er_read_integer_length
|
||||
#define der_skip_integer er_skip_integer
|
||||
#define der_write_sequence_tag(_a, _b) er_write_sequence_tag(_a, _b, true)
|
||||
#define der_write_octet_string_tag(_a, _b) er_write_octet_string_tag(_a, _b, true)
|
||||
#define der_write_octet_string(_a, _b, _c) er_write_octet_string(_a, _b, _c, true)
|
||||
#define der_write_bit_string_tag(_a, _b, _c) er_write_bit_string_tag(_a, _b, _c, true);
|
||||
#define der_write_contextual_tag(_a, _b, _c, _d) er_write_contextual_tag(_a, _b, _c, _d, true);
|
||||
#define der_write_enumerated(_a, _b, _c) er_write_enumerated(_a, _b, _c, true)
|
||||
#define der_write_application_tag(_a, _b, _c) er_write_application_tag(_a, _b, _c, true)
|
||||
|
||||
FREERDP_API int _der_skip_length(int length);
|
||||
FREERDP_API int der_write_length(STREAM* s, int length);
|
||||
FREERDP_API boolean der_write_bit_string(STREAM* s, uint32 length, uint8 padding);
|
||||
FREERDP_API boolean der_write_general_string(STREAM* s, char* str);
|
||||
FREERDP_API char* der_read_general_string(STREAM* s, int *length);
|
||||
FREERDP_API int der_write_principal_name(STREAM* s, uint8 ntype, char** name);
|
||||
FREERDP_API int der_write_generalized_time(STREAM* s, char* tstr);
|
||||
FREERDP_API boolean der_read_generalized_time(STREAM* s, char** tstr);
|
||||
FREERDP_API int der_get_content_length(int length);
|
||||
FREERDP_API int der_skip_octet_string(int length);
|
||||
FREERDP_API int der_skip_sequence_tag(int length);
|
||||
FREERDP_API int der_write_sequence_tag(STREAM* s, int length);
|
||||
FREERDP_API int der_skip_contextual_tag(int length);
|
||||
FREERDP_API int der_write_contextual_tag(STREAM* s, uint8 tag, int length, boolean pc);
|
||||
FREERDP_API void der_write_octet_string(STREAM* s, uint8* oct_str, int length);
|
||||
|
||||
#endif /* FREERDP_CRYPTO_DER_H */
|
||||
|
@ -30,6 +30,7 @@ typedef struct rdp_credssp rdpCredssp;
|
||||
|
||||
#include <freerdp/crypto/tls.h>
|
||||
#include <freerdp/crypto/ber.h>
|
||||
#include <freerdp/crypto/der.h>
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
|
||||
struct rdp_credssp
|
||||
@ -47,6 +48,7 @@ struct rdp_credssp
|
||||
SecBuffer PublicKey;
|
||||
SecBuffer ts_credentials;
|
||||
CryptoRc4 rc4_seal_state;
|
||||
LPTSTR ServicePrincipalName;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
PSecurityFunctionTable table;
|
||||
SecPkgContext_Sizes ContextSizes;
|
||||
|
@ -49,6 +49,7 @@ FREERDP_API boolean tls_disconnect(rdpTls* tls);
|
||||
FREERDP_API int tls_read(rdpTls* tls, uint8* data, int length);
|
||||
FREERDP_API int tls_write(rdpTls* tls, uint8* data, int length);
|
||||
|
||||
FREERDP_API int tls_read_all(rdpTls* tls, uint8* data, int length);
|
||||
FREERDP_API int tls_write_all(rdpTls* tls, uint8* data, int length);
|
||||
|
||||
FREERDP_API boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname);
|
||||
|
@ -52,6 +52,7 @@ typedef boolean (*pPreConnect)(freerdp* instance);
|
||||
typedef boolean (*pPostConnect)(freerdp* instance);
|
||||
typedef boolean (*pAuthenticate)(freerdp* instance, char** username, char** password, char** domain);
|
||||
typedef boolean (*pVerifyCertificate)(freerdp* instance, char* subject, char* issuer, char* fingerprint);
|
||||
typedef boolean (*pVerifyChangedCertificate)(freerdp* instance, char* subject, char* issuer, char* new_fingerprint, char* old_fingerprint);
|
||||
|
||||
typedef int (*pSendChannelData)(freerdp* instance, int channelId, uint8* data, int size);
|
||||
typedef int (*pReceiveChannelData)(freerdp* instance, int channelId, uint8* data, int size, int flags, int total_size);
|
||||
@ -163,7 +164,11 @@ struct rdp_freerdp
|
||||
pVerifyCertificate VerifyCertificate; /**< (offset 51)
|
||||
Callback for certificate validation.
|
||||
Used to verify that an unknown certificate is trusted. */
|
||||
uint32 paddingD[64 - 52]; /* 52 */
|
||||
pVerifyChangedCertificate VerifyChangedCertificate; /**< (offset 52)
|
||||
Callback for changed certificate validation.
|
||||
Used when a certificate differs from stored fingerprint.
|
||||
If returns true, the new fingerprint will be trusted and old thrown out. */
|
||||
uint32 paddingD[64 - 51]; /* 51 */
|
||||
|
||||
pSendChannelData SendChannelData; /* (offset 64)
|
||||
Callback for sending data to a channel.
|
||||
|
@ -70,6 +70,7 @@ struct rdp_freerdp_peer
|
||||
|
||||
uint32 ack_frame_id;
|
||||
boolean local;
|
||||
boolean activated;
|
||||
};
|
||||
|
||||
FREERDP_API void freerdp_peer_context_new(freerdp_peer* client);
|
||||
|
@ -150,18 +150,18 @@ enum SPI_MASK
|
||||
#define TF_SFT_NOEXTRAICONSONMINIMIZED 0x00000400
|
||||
#define TF_SFT_DESKBAND 0x00000800
|
||||
|
||||
struct _UNICODE_STRING
|
||||
struct _RAIL_UNICODE_STRING
|
||||
{
|
||||
uint16 length;
|
||||
uint8* string;
|
||||
};
|
||||
typedef struct _UNICODE_STRING UNICODE_STRING;
|
||||
typedef struct _RAIL_UNICODE_STRING RAIL_UNICODE_STRING;
|
||||
|
||||
struct _HIGH_CONTRAST
|
||||
{
|
||||
uint32 flags;
|
||||
uint32 colorSchemeLength;
|
||||
UNICODE_STRING colorScheme;
|
||||
RAIL_UNICODE_STRING colorScheme;
|
||||
};
|
||||
typedef struct _HIGH_CONTRAST HIGH_CONTRAST;
|
||||
|
||||
@ -182,9 +182,9 @@ typedef struct _RAIL_CLIENT_STATUS_ORDER RAIL_CLIENT_STATUS_ORDER;
|
||||
struct _RAIL_EXEC_ORDER
|
||||
{
|
||||
uint16 flags;
|
||||
UNICODE_STRING exeOrFile;
|
||||
UNICODE_STRING workingDir;
|
||||
UNICODE_STRING arguments;
|
||||
RAIL_UNICODE_STRING exeOrFile;
|
||||
RAIL_UNICODE_STRING workingDir;
|
||||
RAIL_UNICODE_STRING arguments;
|
||||
};
|
||||
typedef struct _RAIL_EXEC_ORDER RAIL_EXEC_ORDER;
|
||||
|
||||
@ -193,7 +193,7 @@ struct _RAIL_EXEC_RESULT_ORDER
|
||||
uint16 flags;
|
||||
uint16 execResult;
|
||||
uint32 rawResult;
|
||||
UNICODE_STRING exeOrFile;
|
||||
RAIL_UNICODE_STRING exeOrFile;
|
||||
};
|
||||
typedef struct _RAIL_EXEC_RESULT_ORDER RAIL_EXEC_RESULT_ORDER;
|
||||
|
||||
@ -287,7 +287,7 @@ typedef struct _RAIL_GET_APPID_REQ_ORDER RAIL_GET_APPID_REQ_ORDER;
|
||||
struct _RAIL_GET_APPID_RESP_ORDER
|
||||
{
|
||||
uint32 windowId;
|
||||
UNICODE_STRING applicationId;
|
||||
RAIL_UNICODE_STRING applicationId;
|
||||
uint8 applicationIdBuffer[512];
|
||||
};
|
||||
typedef struct _RAIL_GET_APPID_RESP_ORDER RAIL_GET_APPID_RESP_ORDER;
|
||||
|
@ -46,7 +46,7 @@ struct rdp_window
|
||||
uint32 style;
|
||||
uint32 extendedStyle;
|
||||
uint8 showState;
|
||||
UNICODE_STRING titleInfo;
|
||||
RAIL_UNICODE_STRING titleInfo;
|
||||
uint32 clientOffsetX;
|
||||
uint32 clientOffsetY;
|
||||
uint32 clientAreaWidth;
|
||||
|
95
include/freerdp/server/audin.h
Normal file
95
include/freerdp/server/audin.h
Normal file
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* Server Audio Input Virtual Channel
|
||||
*
|
||||
* Copyright 2012 Vic Lee
|
||||
*
|
||||
* 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 __SERVER_AUDIN_H
|
||||
#define __SERVER_AUDIN_H
|
||||
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
#include <freerdp/channels/rdpsnd.h>
|
||||
|
||||
typedef struct _audin_server_context audin_server_context;
|
||||
|
||||
typedef void (*psAudinServerSelectFormat)(audin_server_context* context, int client_format_index);
|
||||
typedef boolean (*psAudinServerOpen)(audin_server_context* context);
|
||||
typedef boolean (*psAudinServerClose)(audin_server_context* context);
|
||||
|
||||
typedef void (*psAudinServerOpening)(audin_server_context* context);
|
||||
typedef void (*psAudinServerOpenResult)(audin_server_context* context, uint32 result);
|
||||
typedef void (*psAudinServerReceiveSamples)(audin_server_context* context, const void* buf, int nframes);
|
||||
|
||||
struct _audin_server_context
|
||||
{
|
||||
WTSVirtualChannelManager* vcm;
|
||||
|
||||
/* Server self-defined pointer. */
|
||||
void* data;
|
||||
|
||||
/* Server supported formats. Set by server. */
|
||||
const rdpsndFormat* server_formats;
|
||||
int num_server_formats;
|
||||
|
||||
/* Server destination PCM audio format. Set by server. */
|
||||
rdpsndFormat dst_format;
|
||||
|
||||
/* Server preferred frames per packet. */
|
||||
int frames_per_packet;
|
||||
|
||||
/* Client supported formats. */
|
||||
rdpsndFormat* client_formats;
|
||||
int num_client_formats;
|
||||
int selected_client_format;
|
||||
|
||||
/*** APIs called by the server. ***/
|
||||
/**
|
||||
* Choose the audio format to be received. The index argument is an index into
|
||||
* the client_formats array and must be smaller than num_client_formats.
|
||||
*/
|
||||
psAudinServerSelectFormat SelectFormat;
|
||||
/**
|
||||
* Open the audio input stream.
|
||||
*/
|
||||
psAudinServerOpen Open;
|
||||
/**
|
||||
* Close the audio stream.
|
||||
*/
|
||||
psAudinServerClose Close;
|
||||
|
||||
/*** Callbacks registered by the server. ***/
|
||||
/**
|
||||
* It's ready to open the audio input stream. The server should examine client
|
||||
* formats and call SelectFormat to choose the desired one in this callback.
|
||||
*/
|
||||
psAudinServerOpening Opening;
|
||||
/**
|
||||
* Client replied HRESULT of the open operation.
|
||||
*/
|
||||
psAudinServerOpenResult OpenResult;
|
||||
/**
|
||||
* Receive audio samples. Actual bytes in the buffer is:
|
||||
* nframes * dst_format.nBitsPerSample * dst_format.nChannels / 8
|
||||
* Note that this callback is called from a different thread context so the
|
||||
* server must be careful of thread synchronization.
|
||||
*/
|
||||
psAudinServerReceiveSamples ReceiveSamples;
|
||||
};
|
||||
|
||||
FREERDP_API audin_server_context* audin_server_context_new(WTSVirtualChannelManager* vcm);
|
||||
FREERDP_API void audin_server_context_free(audin_server_context* context);
|
||||
|
||||
#endif
|
@ -293,7 +293,9 @@ struct rdp_settings
|
||||
ALIGN64 char* tsg_username; /* 66 */
|
||||
ALIGN64 char* tsg_password; /* 67 */
|
||||
ALIGN64 boolean local; /* 68 */
|
||||
ALIGN64 uint64 paddingC[80 - 69]; /* 69 */
|
||||
ALIGN64 boolean authentication_only; /* 69 */
|
||||
ALIGN64 boolean from_stdin; /* 70 */
|
||||
ALIGN64 uint64 paddingC[80 - 71]; /* 71 */
|
||||
|
||||
/* User Interface Parameters */
|
||||
ALIGN64 boolean sw_gdi; /* 80 */
|
||||
|
@ -29,5 +29,7 @@ FREERDP_API boolean freerdp_close_library(void* library);
|
||||
FREERDP_API void* freerdp_load_library_symbol(const char* file, const char* name);
|
||||
FREERDP_API void* freerdp_load_plugin(const char* name, const char* entry_name);
|
||||
FREERDP_API void* freerdp_load_channel_plugin(rdpSettings* settings, const char* name, const char* entry_name);
|
||||
FREERDP_API boolean freerdp_register_static_plugin(const char* name, const char* entry_name, void* entry_addr);
|
||||
FREERDP_API void* freerdp_load_static_plugin(const char* name, const char* entry_name);
|
||||
|
||||
#endif /* __LOAD_PLUGIN_UTILS_H */
|
||||
|
@ -23,6 +23,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <freerdp/api.h>
|
||||
|
||||
FREERDP_API char* freerdp_passphrase_read(const char* prompt, char* buf, size_t bufsiz);
|
||||
FREERDP_API char* freerdp_passphrase_read(const char* prompt, char* buf, size_t bufsiz, int from_stdin);
|
||||
|
||||
#endif /* __UTILS_PASSPHRASE_H */
|
||||
|
@ -25,11 +25,11 @@
|
||||
#include <freerdp/utils/rect.h>
|
||||
#include <freerdp/utils/stream.h>
|
||||
|
||||
FREERDP_API void rail_unicode_string_alloc(UNICODE_STRING* unicode_string, uint16 cbString);
|
||||
FREERDP_API void rail_unicode_string_free(UNICODE_STRING* unicode_string);
|
||||
FREERDP_API void rail_read_unicode_string(STREAM* s, UNICODE_STRING* unicode_string);
|
||||
FREERDP_API void rail_write_unicode_string(STREAM* s, UNICODE_STRING* unicode_string);
|
||||
FREERDP_API void rail_write_unicode_string_value(STREAM* s, UNICODE_STRING* unicode_string);
|
||||
FREERDP_API void rail_unicode_string_alloc(RAIL_UNICODE_STRING* unicode_string, uint16 cbString);
|
||||
FREERDP_API void rail_unicode_string_free(RAIL_UNICODE_STRING* unicode_string);
|
||||
FREERDP_API void rail_read_unicode_string(STREAM* s, RAIL_UNICODE_STRING* unicode_string);
|
||||
FREERDP_API void rail_write_unicode_string(STREAM* s, RAIL_UNICODE_STRING* unicode_string);
|
||||
FREERDP_API void rail_write_unicode_string_value(STREAM* s, RAIL_UNICODE_STRING* unicode_string);
|
||||
FREERDP_API void* rail_clone_order(uint32 event_type, void* order);
|
||||
FREERDP_API void rail_free_cloned_order(uint32 event_type, void* order);
|
||||
|
||||
|
@ -65,7 +65,7 @@ FREERDP_API void stream_extend(STREAM* stream, int request_size);
|
||||
#define stream_read_uint8(_s, _v) do { _v = *_s->p++; } while (0)
|
||||
#define stream_read_uint16(_s, _v) do { _v = \
|
||||
(uint16)(*_s->p) + \
|
||||
(((uint16)(*(_s->p + 1))) << 8); \
|
||||
(uint16)(((uint16)(*(_s->p + 1))) << 8); \
|
||||
_s->p += 2; } while (0)
|
||||
#define stream_read_uint32(_s, _v) do { _v = \
|
||||
(uint32)(*_s->p) + \
|
||||
|
@ -60,9 +60,15 @@ FREERDP_API int svc_plugin_send_event(rdpSvcPlugin* plugin, RDP_EVENT* event);
|
||||
#define DEBUG_SVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef WITH_STATIC_PLUGINS
|
||||
#define DEFINE_SVC_PLUGIN_ENTRY(_prefix) int _prefix##_entry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||
#else
|
||||
#define DEFINE_SVC_PLUGIN_ENTRY(_prefix) int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||
#endif
|
||||
|
||||
#define DEFINE_SVC_PLUGIN(_prefix, _name, _options) \
|
||||
\
|
||||
int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) \
|
||||
DEFINE_SVC_PLUGIN_ENTRY(_prefix) \
|
||||
{ \
|
||||
_prefix##Plugin* _p; \
|
||||
\
|
||||
|
@ -155,8 +155,8 @@ struct _NOTIFY_ICON_INFOTIP
|
||||
{
|
||||
uint32 timeout;
|
||||
uint32 flags;
|
||||
UNICODE_STRING text;
|
||||
UNICODE_STRING title;
|
||||
RAIL_UNICODE_STRING text;
|
||||
RAIL_UNICODE_STRING title;
|
||||
};
|
||||
typedef struct _NOTIFY_ICON_INFOTIP NOTIFY_ICON_INFOTIP;
|
||||
|
||||
@ -166,7 +166,7 @@ struct _WINDOW_STATE_ORDER
|
||||
uint32 style;
|
||||
uint32 extendedStyle;
|
||||
uint32 showState;
|
||||
UNICODE_STRING titleInfo;
|
||||
RAIL_UNICODE_STRING titleInfo;
|
||||
uint32 clientOffsetX;
|
||||
uint32 clientOffsetY;
|
||||
uint32 clientAreaWidth;
|
||||
@ -203,7 +203,7 @@ typedef struct _WINDOW_CACHED_ICON_ORDER WINDOW_CACHED_ICON_ORDER;
|
||||
struct _NOTIFY_ICON_STATE_ORDER
|
||||
{
|
||||
uint32 version;
|
||||
UNICODE_STRING toolTip;
|
||||
RAIL_UNICODE_STRING toolTip;
|
||||
NOTIFY_ICON_INFOTIP infoTip;
|
||||
uint32 state;
|
||||
ICON_INFO icon;
|
||||
|
383
include/winpr/asn1.h
Normal file
383
include/winpr/asn1.h
Normal file
@ -0,0 +1,383 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* ASN.1 Encoding & Decoding Engine
|
||||
*
|
||||
* Copyright 2012 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_ASN1_H
|
||||
#define WINPR_ASN1_H
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <msasn1.h>
|
||||
#include <msber.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
typedef unsigned char ASN1uint8_t;
|
||||
typedef signed char ASN1int8_t;
|
||||
|
||||
typedef unsigned short ASN1uint16_t;
|
||||
typedef signed short ASN1int16_t;
|
||||
|
||||
typedef unsigned long ASN1uint32_t;
|
||||
typedef signed long ASN1int32_t;
|
||||
|
||||
typedef ASN1uint8_t ASN1octet_t;
|
||||
|
||||
typedef ASN1uint8_t ASN1bool_t;
|
||||
|
||||
struct tagASN1intx_t
|
||||
{
|
||||
ASN1uint32_t length;
|
||||
ASN1octet_t* value;
|
||||
};
|
||||
typedef struct tagASN1intx_t ASN1intx_t;
|
||||
|
||||
struct tagASN1octetstring_t
|
||||
{
|
||||
ASN1uint32_t length;
|
||||
ASN1octet_t* value;
|
||||
};
|
||||
typedef struct tagASN1octetstring_t ASN1octetstring_t;
|
||||
|
||||
struct tagASN1octetstring2_t
|
||||
{
|
||||
ASN1uint32_t length;
|
||||
ASN1octet_t value[1];
|
||||
};
|
||||
typedef struct tagASN1octetstring2_t ASN1octetstring2_t;
|
||||
|
||||
struct ASN1iterator_s
|
||||
{
|
||||
struct ASN1iterator_s* next;
|
||||
void* value;
|
||||
};
|
||||
typedef struct ASN1iterator_s ASN1iterator_t;
|
||||
|
||||
struct tagASN1bitstring_t
|
||||
{
|
||||
ASN1uint32_t length;
|
||||
ASN1octet_t* value;
|
||||
};
|
||||
typedef struct tagASN1bitstring_t ASN1bitstring_t;
|
||||
|
||||
typedef char ASN1char_t;
|
||||
|
||||
struct tagASN1charstring_t
|
||||
{
|
||||
ASN1uint32_t length;
|
||||
ASN1char_t* value;
|
||||
};
|
||||
typedef struct tagASN1charstring_t ASN1charstring_t;
|
||||
|
||||
typedef ASN1uint16_t ASN1char16_t;
|
||||
|
||||
struct tagASN1char16string_t
|
||||
{
|
||||
ASN1uint32_t length;
|
||||
ASN1char16_t* value;
|
||||
};
|
||||
typedef struct tagASN1char16string_t ASN1char16string_t;
|
||||
|
||||
typedef ASN1uint32_t ASN1char32_t;
|
||||
|
||||
struct tagASN1char32string_t
|
||||
{
|
||||
ASN1uint32_t length;
|
||||
ASN1char32_t* value;
|
||||
};
|
||||
typedef struct tagASN1char32string_t ASN1char32string_t;
|
||||
|
||||
typedef ASN1char_t* ASN1ztcharstring_t;
|
||||
typedef ASN1char16_t* ASN1ztchar16string_t;
|
||||
typedef ASN1char32_t* ASN1ztchar32string_t;
|
||||
|
||||
struct tagASN1wstring_t
|
||||
{
|
||||
ASN1uint32_t length;
|
||||
WCHAR* value;
|
||||
};
|
||||
typedef struct tagASN1wstring_t ASN1wstring_t;
|
||||
|
||||
struct ASN1objectidentifier_s
|
||||
{
|
||||
struct ASN1objectidentifier_s* next;
|
||||
ASN1uint32_t value;
|
||||
};
|
||||
typedef struct ASN1objectidentifier_s* ASN1objectidentifier_t;
|
||||
|
||||
struct tagASN1objectidentifier2_t
|
||||
{
|
||||
ASN1uint16_t count;
|
||||
ASN1uint32_t value[16];
|
||||
};
|
||||
typedef struct tagASN1objectidentifier2_t ASN1objectidentifier2_t;
|
||||
|
||||
struct tagASN1encodedOID_t
|
||||
{
|
||||
ASN1uint16_t length;
|
||||
ASN1octet_t* value;
|
||||
};
|
||||
typedef struct tagASN1encodedOID_t ASN1encodedOID_t;
|
||||
|
||||
typedef ASN1ztcharstring_t ASN1objectdescriptor_t;
|
||||
|
||||
struct tagASN1generalizedtime_t
|
||||
{
|
||||
ASN1uint16_t year;
|
||||
ASN1uint8_t month;
|
||||
ASN1uint8_t day;
|
||||
ASN1uint8_t hour;
|
||||
ASN1uint8_t minute;
|
||||
ASN1uint8_t second;
|
||||
ASN1uint16_t millisecond;
|
||||
ASN1bool_t universal;
|
||||
ASN1int16_t diff;
|
||||
};
|
||||
typedef struct tagASN1generalizedtime_t ASN1generalizedtime_t;
|
||||
|
||||
struct tagASN1utctime_t
|
||||
{
|
||||
ASN1uint8_t year;
|
||||
ASN1uint8_t month;
|
||||
ASN1uint8_t day;
|
||||
ASN1uint8_t hour;
|
||||
ASN1uint8_t minute;
|
||||
ASN1uint8_t second;
|
||||
ASN1bool_t universal;
|
||||
ASN1int16_t diff;
|
||||
};
|
||||
typedef struct tagASN1utctime_t ASN1utctime_t;
|
||||
|
||||
struct tagASN1open_t
|
||||
{
|
||||
ASN1uint32_t length;
|
||||
|
||||
union
|
||||
{
|
||||
void* encoded;
|
||||
void* value;
|
||||
};
|
||||
};
|
||||
typedef struct tagASN1open_t ASN1open_t;
|
||||
|
||||
enum tagASN1blocktype_e
|
||||
{
|
||||
ASN1_DER_SET_OF_BLOCK,
|
||||
};
|
||||
typedef enum tagASN1blocktype_e ASN1blocktype_e;
|
||||
|
||||
typedef ASN1int32_t ASN1enum_t;
|
||||
typedef ASN1uint16_t ASN1choice_t;
|
||||
typedef ASN1uint32_t ASN1magic_t;
|
||||
|
||||
enum
|
||||
{
|
||||
ASN1_CHOICE_BASE = 1,
|
||||
ASN1_CHOICE_INVALID = -1,
|
||||
ASN1_CHOICE_EXTENSION = 0,
|
||||
};
|
||||
|
||||
enum tagASN1error_e
|
||||
{
|
||||
ASN1_SUCCESS = 0,
|
||||
ASN1_ERR_INTERNAL = -1001,
|
||||
ASN1_ERR_EOD = -1002,
|
||||
ASN1_ERR_CORRUPT = -1003,
|
||||
ASN1_ERR_LARGE = -1004,
|
||||
ASN1_ERR_CONSTRAINT = -1005,
|
||||
ASN1_ERR_MEMORY = -1006,
|
||||
ASN1_ERR_OVERFLOW = -1007,
|
||||
ASN1_ERR_BADPDU = -1008,
|
||||
ASN1_ERR_BADARGS = -1009,
|
||||
ASN1_ERR_BADREAL = -1010,
|
||||
ASN1_ERR_BADTAG = -1011,
|
||||
ASN1_ERR_CHOICE = -1012,
|
||||
ASN1_ERR_RULE = -1013,
|
||||
ASN1_ERR_UTF8 = -1014,
|
||||
ASN1_ERR_PDU_TYPE = -1051,
|
||||
ASN1_ERR_NYI = -1052,
|
||||
ASN1_WRN_EXTENDED = 1001,
|
||||
ASN1_WRN_NOEOD = 1002,
|
||||
};
|
||||
typedef enum tagASN1error_e ASN1error_e;
|
||||
|
||||
enum tagASN1encodingrule_e
|
||||
{
|
||||
ASN1_BER_RULE_BER = 0x0100,
|
||||
ASN1_BER_RULE_CER = 0x0200,
|
||||
ASN1_BER_RULE_DER = 0x0400,
|
||||
ASN1_BER_RULE = ASN1_BER_RULE_BER | ASN1_BER_RULE_CER | ASN1_BER_RULE_DER,
|
||||
};
|
||||
typedef enum tagASN1encodingrule_e ASN1encodingrule_e;
|
||||
|
||||
typedef struct ASN1encoding_s* ASN1encoding_t;
|
||||
typedef struct ASN1decoding_s* ASN1decoding_t;
|
||||
|
||||
typedef ASN1int32_t (*ASN1BerEncFun_t)(ASN1encoding_t enc, ASN1uint32_t tag, void* data);
|
||||
typedef ASN1int32_t (*ASN1BerDecFun_t)(ASN1decoding_t enc, ASN1uint32_t tag, void* data);
|
||||
|
||||
struct tagASN1BerFunArr_t
|
||||
{
|
||||
const ASN1BerEncFun_t* apfnEncoder;
|
||||
const ASN1BerDecFun_t* apfnDecoder;
|
||||
};
|
||||
typedef struct tagASN1BerFunArr_t ASN1BerFunArr_t;
|
||||
|
||||
typedef void (*ASN1GenericFun_t)(void);
|
||||
typedef void (*ASN1FreeFun_t)(void* data);
|
||||
|
||||
struct tagASN1module_t
|
||||
{
|
||||
ASN1magic_t nModuleName;
|
||||
ASN1encodingrule_e eRule;
|
||||
ASN1uint32_t dwFlags;
|
||||
ASN1uint32_t cPDUs;
|
||||
const ASN1FreeFun_t* apfnFreeMemory;
|
||||
const ASN1uint32_t* acbStructSize;
|
||||
ASN1BerFunArr_t BER;
|
||||
}
|
||||
typedef struct tagASN1module_t* ASN1module_t;
|
||||
|
||||
struct ASN1encoding_s
|
||||
{
|
||||
ASN1magic_t magic;
|
||||
ASN1uint32_t version;
|
||||
ASN1module_t module;
|
||||
ASN1octet_t* buf;
|
||||
ASN1uint32_t size;
|
||||
ASN1uint32_t len;
|
||||
ASN1error_e err;
|
||||
ASN1uint32_t bit;
|
||||
ASN1octet_t* pos;
|
||||
ASN1uint32_t cbExtraHeader;
|
||||
ASN1encodingrule_e eRule;
|
||||
ASN1uint32_t dwFlags;
|
||||
};
|
||||
|
||||
struct ASN1decoding_s
|
||||
{
|
||||
ASN1magic_t magic;
|
||||
ASN1uint32_t version;
|
||||
ASN1module_t module;
|
||||
ASN1octet_t* buf;
|
||||
ASN1uint32_t size;
|
||||
ASN1uint32_t len;
|
||||
ASN1error_e err;
|
||||
ASN1uint32_t bit;
|
||||
ASN1octet_t* pos;
|
||||
ASN1encodingrule_e eRule;
|
||||
ASN1uint32_t dwFlags;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ASN1FLAGS_NONE = 0x00000000L,
|
||||
ASN1FLAGS_NOASSERT = 0x00001000L,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ASN1ENCODE_APPEND = 0x00000001L,
|
||||
ASN1ENCODE_REUSEBUFFER = 0x00000004L,
|
||||
ASN1ENCODE_SETBUFFER = 0x00000008L,
|
||||
ASN1ENCODE_ALLOCATEBUFFER = 0x00000010L,
|
||||
ASN1ENCODE_NOASSERT = ASN1FLAGS_NOASSERT,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ASN1DECODE_APPENDED = 0x00000001L,
|
||||
ASN1DECODE_REWINDBUFFER = 0x00000004L,
|
||||
ASN1DECODE_SETBUFFER = 0x00000008L,
|
||||
ASN1DECODE_AUTOFREEBUFFER = 0x00000010L,
|
||||
ASN1DECODE_NOASSERT = ASN1FLAGS_NOASSERT,
|
||||
};
|
||||
|
||||
WINPR_API ASN1module_t ASN1_CreateModule(ASN1uint32_t nVersion, ASN1encodingrule_e eRule,
|
||||
ASN1uint32_t dwFlags, ASN1uint32_t cPDU, const ASN1GenericFun_t apfnEncoder[],
|
||||
const ASN1GenericFun_t apfnDecoder[], const ASN1FreeFun_t apfnFreeMemory[],
|
||||
const ASN1uint32_t acbStructSize[], ASN1magic_t nModuleName);
|
||||
|
||||
WINPR_API void ASN1_CloseModule(ASN1module_t pModule);
|
||||
|
||||
WINPR_API ASN1error_e ASN1_CreateEncoder(ASN1module_t pModule, ASN1encoding_t* ppEncoderInfo,
|
||||
ASN1octet_t* pbBuf, ASN1uint32_t cbBufSize, ASN1encoding_t pParent);
|
||||
|
||||
WINPR_API ASN1error_e ASN1_Encode(ASN1encoding_t pEncoderInfo, void* pDataStruct, ASN1uint32_t nPduNum,
|
||||
ASN1uint32_t dwFlags, ASN1octet_t* pbBuf, ASN1uint32_t cbBufSize);
|
||||
|
||||
WINPR_API void ASN1_CloseEncoder(ASN1encoding_t pEncoderInfo);
|
||||
|
||||
WINPR_API void ASN1_CloseEncoder2(ASN1encoding_t pEncoderInfo);
|
||||
|
||||
WINPR_API ASN1error_e ASN1_CreateDecoder(ASN1module_t pModule, ASN1decoding_t* ppDecoderInfo,
|
||||
ASN1octet_t* pbBuf, ASN1uint32_t cbBufSize, ASN1decoding_t pParent);
|
||||
|
||||
WINPR_API ASN1error_e ASN1_Decode(ASN1decoding_t pDecoderInfo, void** ppDataStruct, ASN1uint32_t nPduNum,
|
||||
ASN1uint32_t dwFlags, ASN1octet_t* pbBuf, ASN1uint32_t cbBufSize);
|
||||
|
||||
WINPR_API void ASN1_CloseDecoder(ASN1decoding_t pDecoderInfo);
|
||||
|
||||
WINPR_API void ASN1_FreeEncoded(ASN1encoding_t pEncoderInfo, void* pBuf);
|
||||
|
||||
WINPR_API void ASN1_FreeDecoded(ASN1decoding_t pDecoderInfo, void* pDataStruct, ASN1uint32_t nPduNum);
|
||||
|
||||
enum tagASN1option_e
|
||||
{
|
||||
ASN1OPT_CHANGE_RULE = 0x101,
|
||||
ASN1OPT_GET_RULE = 0x201,
|
||||
ASN1OPT_NOT_REUSE_BUFFER = 0x301,
|
||||
ASN1OPT_REWIND_BUFFER = 0x302,
|
||||
ASN1OPT_SET_DECODED_BUFFER = 0x501,
|
||||
ASN1OPT_DEL_DECODED_BUFFER = 0x502,
|
||||
ASN1OPT_GET_DECODED_BUFFER_SIZE = 0x601,
|
||||
};
|
||||
typedef enum ASN1option_e;
|
||||
|
||||
struct tagASN1optionparam_t
|
||||
{
|
||||
ASN1option_e eOption;
|
||||
|
||||
union
|
||||
{
|
||||
ASN1encodingrule_e eRule;
|
||||
ASN1uint32_t cbRequiredDecodedBufSize;
|
||||
|
||||
struct
|
||||
{
|
||||
ASN1octet_t* pbBuf;
|
||||
ASN1uint32_t cbBufSize;
|
||||
} Buffer;
|
||||
};
|
||||
};
|
||||
typedef struct tagASN1optionparam_t ASN1optionparam_t;
|
||||
typedef struct tagASN1optionparam_t ASN1optionparam_s;
|
||||
|
||||
WINPR_API ASN1error_e ASN1_SetEncoderOption(ASN1encoding_t pEncoderInfo, ASN1optionparam_t* pOptParam);
|
||||
WINPR_API ASN1error_e ASN1_GetEncoderOption(ASN1encoding_t pEncoderInfo, ASN1optionparam_t* pOptParam);
|
||||
|
||||
WINPR_API ASN1error_e ASN1_SetDecoderOption(ASN1decoding_t pDecoderInfo, ASN1optionparam_t* pOptParam);
|
||||
WINPR_API ASN1error_e ASN1_GetDecoderOption(ASN1decoding_t pDecoderInfo, ASN1optionparam_t* pOptParam);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_ASN1_H */
|
||||
|
59
include/winpr/dsparse.h
Normal file
59
include/winpr/dsparse.h
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Active Directory Domain Services Parsing Functions
|
||||
*
|
||||
* Copyright 2012 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_DSPARSE_H
|
||||
#define WINPR_DSPARSE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
WINPR_API DWORD DsCrackSpnW(LPCWSTR pszSpn, DWORD* pcServiceClass, LPWSTR ServiceClass, DWORD* pcServiceName,
|
||||
LPWSTR ServiceName, DWORD* pcInstanceName, LPWSTR InstanceName, USHORT* pInstancePort);
|
||||
|
||||
WINPR_API DWORD DsCrackSpnA(LPCSTR pszSpn, LPDWORD pcServiceClass, LPSTR ServiceClass, LPDWORD pcServiceName,
|
||||
LPSTR ServiceName, LPDWORD pcInstanceName, LPSTR InstanceName, USHORT* pInstancePort);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define DsCrackSpn DsCrackSpnW
|
||||
#else
|
||||
#define DsCrackSpn DsCrackSpnA
|
||||
#endif
|
||||
|
||||
WINPR_API DWORD DsMakeSpnW(LPCWSTR ServiceClass, LPCWSTR ServiceName, LPCWSTR InstanceName,
|
||||
USHORT InstancePort, LPCWSTR Referrer, DWORD* pcSpnLength, LPWSTR pszSpn);
|
||||
|
||||
WINPR_API DWORD DsMakeSpnA(LPCSTR ServiceClass, LPCSTR ServiceName, LPCSTR InstanceName,
|
||||
USHORT InstancePort, LPCSTR Referrer, DWORD* pcSpnLength, LPSTR pszSpn);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define DsMakeSpn DsMakeSpnW
|
||||
#else
|
||||
#define DsMakeSpn DsMakeSpnA
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_DSPARSE_H */
|
45
include/winpr/handle.h
Normal file
45
include/winpr/handle.h
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Handle Management
|
||||
*
|
||||
* Copyright 2012 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_HANDLE_H
|
||||
#define WINPR_HANDLE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#define HANDLE_FLAG_INHERIT 0x00000001
|
||||
#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002
|
||||
|
||||
WINPR_API BOOL CloseHandle(HANDLE hObject);
|
||||
|
||||
WINPR_API BOOL DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle,
|
||||
LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
|
||||
|
||||
WINPR_API BOOL GetHandleInformation(HANDLE hObject, LPDWORD lpdwFlags);
|
||||
WINPR_API BOOL SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_HANDLE_H */
|
||||
|
44
include/winpr/heap.h
Normal file
44
include/winpr/heap.h
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Heap Memory Allocation
|
||||
*
|
||||
* Copyright 2012 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_HEAP_H
|
||||
#define WINPR_HEAP_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#define HEAP_GENERATE_EXCEPTIONS 0x00000004
|
||||
#define HEAP_NO_SERIALIZE 0x00000001
|
||||
#define HEAP_ZERO_MEMORY 0x00000008
|
||||
#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010
|
||||
|
||||
WINPR_API HANDLE GetProcessHeap(void);
|
||||
WINPR_API LPVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
|
||||
WINPR_API LPVOID HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes);
|
||||
WINPR_API BOOL HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_HEAP_H */
|
||||
|
@ -38,16 +38,9 @@
|
||||
#define RtlFillMemory(Destination, Length, Fill) memset((Destination), (Fill), (Length))
|
||||
#define RtlZeroMemory(Destination, Length) memset((Destination), 0, (Length))
|
||||
|
||||
#define HEAP_GENERATE_EXCEPTIONS 0x00000004
|
||||
#define HEAP_NO_SERIALIZE 0x00000001
|
||||
#define HEAP_ZERO_MEMORY 0x00000008
|
||||
#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010
|
||||
|
||||
WINPR_API HANDLE GetProcessHeap(void);
|
||||
WINPR_API LPVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
|
||||
WINPR_API LPVOID HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes);
|
||||
WINPR_API BOOL HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
|
||||
|
||||
#endif
|
||||
|
||||
#include <winpr/heap.h>
|
||||
|
||||
#endif /* WINPR_CRT_MEMORY_H */
|
||||
|
||||
|
53
include/winpr/ntlm.h
Normal file
53
include/winpr/ntlm.h
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Utils
|
||||
*
|
||||
* Copyright 2012 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_UTILS_NTLM_H
|
||||
#define WINPR_UTILS_NTLM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
WINPR_API BYTE* NTOWFv1W(LPWSTR Password, UINT32 PasswordLength, BYTE* NtHash);
|
||||
WINPR_API BYTE* NTOWFv1A(LPSTR Password, UINT32 PasswordLength, BYTE* NtHash);
|
||||
|
||||
WINPR_API BYTE* NTOWFv2W(LPWSTR Password, UINT32 PasswordLength, LPWSTR User,
|
||||
UINT32 UserLength, LPWSTR Domain, UINT32 DomainLength, BYTE* NtHash);
|
||||
WINPR_API BYTE* NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User,
|
||||
UINT32 UserLength, LPSTR Domain, UINT32 DomainLength, BYTE* NtHash);
|
||||
|
||||
WINPR_API BYTE* NTOWFv2FromHashW(BYTE* NtHashV1, LPWSTR User, UINT32 UserLength,
|
||||
LPWSTR Domain, UINT32 DomainLength, BYTE* NtHash);
|
||||
WINPR_API BYTE* NTOWFv2FromHashA(BYTE* NtHashV1, LPSTR User, UINT32 UserLength,
|
||||
LPSTR Domain, UINT32 DomainLength, BYTE* NtHash);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define NTOWFv1 NTOWFv1W
|
||||
#define NTOWFv2 NTOWFv2W
|
||||
#define NTOWFv2FromHash NTOWFv2FromHashW
|
||||
#else
|
||||
#define NTOWFv1 NTOWFv1A
|
||||
#define NTOWFv2 NTOWFv2A
|
||||
#define NTOWFv2FromHash NTOWFv2FromHashA
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_UTILS_NTLM_H */
|
||||
|
@ -148,13 +148,6 @@ typedef ACCESS_MASK REGSAM;
|
||||
#define RRF_NOEXPAND 0x10000000
|
||||
#define RRF_ZEROONFAILURE 0x20000000
|
||||
|
||||
typedef struct _SECURITY_ATTRIBUTES
|
||||
{
|
||||
DWORD nLength;
|
||||
LPVOID lpSecurityDescriptor;
|
||||
BOOL bInheritHandle;
|
||||
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
|
||||
|
||||
struct val_context
|
||||
{
|
||||
int valuelen;
|
||||
@ -214,15 +207,6 @@ typedef PVALENTA PVALENT;
|
||||
|
||||
WINPR_API LONG RegCloseKey(HKEY hKey);
|
||||
|
||||
WINPR_API LONG RegConnectRegistryW(LPCWSTR lpMachineName, HKEY hKey, PHKEY phkResult);
|
||||
WINPR_API LONG RegConnectRegistryA(LPCSTR lpMachineName, HKEY hKey, PHKEY phkResult);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define RegConnectRegistry RegConnectRegistryW
|
||||
#else
|
||||
#define RegConnectRegistry RegConnectRegistryA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegCopyTreeW(HKEY hKeySrc, LPCWSTR lpSubKey, HKEY hKeyDest);
|
||||
WINPR_API LONG RegCopyTreeA(HKEY hKeySrc, LPCSTR lpSubKey, HKEY hKeyDest);
|
||||
|
||||
@ -243,28 +227,6 @@ WINPR_API LONG RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR
|
||||
#define RegCreateKeyEx RegCreateKeyExA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegCreateKeyTransactedW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass,
|
||||
DWORD dwOptions, REGSAM samDesired, const LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
PHKEY phkResult, LPDWORD lpdwDisposition, HANDLE hTransaction, PVOID pExtendedParemeter);
|
||||
WINPR_API LONG RegCreateKeyTransactedA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass,
|
||||
DWORD dwOptions, REGSAM samDesired, const LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
PHKEY phkResult, LPDWORD lpdwDisposition, HANDLE hTransaction, PVOID pExtendedParemeter);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define RegCreateKeyTransacted RegCreateKeyTransactedW
|
||||
#else
|
||||
#define RegCreateKeyTransacted RegCreateKeyTransactedA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegDeleteKeyW(HKEY hKey, LPCWSTR lpSubKey);
|
||||
WINPR_API LONG RegDeleteKeyA(HKEY hKey, LPCSTR lpSubKey);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define RegDeleteKey RegDeleteKeyW
|
||||
#else
|
||||
#define RegDeleteKey RegDeleteKeyA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegDeleteKeyExW(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved);
|
||||
WINPR_API LONG RegDeleteKeyExA(HKEY hKey, LPCSTR lpSubKey, REGSAM samDesired, DWORD Reserved);
|
||||
|
||||
@ -274,26 +236,6 @@ WINPR_API LONG RegDeleteKeyExA(HKEY hKey, LPCSTR lpSubKey, REGSAM samDesired, DW
|
||||
#define RegDeleteKeyEx RegDeleteKeyExA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegDeleteKeyTransactedW(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired,
|
||||
DWORD Reserved, HANDLE hTransaction, PVOID pExtendedParameter);
|
||||
WINPR_API LONG RegDeleteKeyTransactedA(HKEY hKey, LPCSTR lpSubKey, REGSAM samDesired,
|
||||
DWORD Reserved, HANDLE hTransaction, PVOID pExtendedParameter);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define RegDeleteKeyTransacted RegDeleteKeyTransactedW
|
||||
#else
|
||||
#define RegDeleteKeyTransacted RegDeleteKeyTransactedA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegDeleteKeyValueW(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValueName);
|
||||
WINPR_API LONG RegDeleteKeyValueA(HKEY hKey, LPCSTR lpSubKey, LPCSTR lpValueName);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define RegDeleteKeyValue RegDeleteKeyValueW
|
||||
#else
|
||||
#define RegDeleteKeyValue RegDeleteKeyValueA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegDeleteTreeW(HKEY hKey, LPCWSTR lpSubKey);
|
||||
WINPR_API LONG RegDeleteTreeA(HKEY hKey, LPCSTR lpSubKey);
|
||||
|
||||
@ -312,14 +254,8 @@ WINPR_API LONG RegDeleteValueA(HKEY hKey, LPCSTR lpValueName);
|
||||
#define RegDeleteValue RegDeleteValueA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegDisablePredefinedCache(void);
|
||||
|
||||
WINPR_API LONG RegDisablePredefinedCacheEx(void);
|
||||
|
||||
WINPR_API LONG RegDisableReflectionKey(HKEY hBase);
|
||||
|
||||
WINPR_API LONG RegEnableReflectionKey(HKEY hBase);
|
||||
|
||||
WINPR_API LONG RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcName,
|
||||
LPDWORD lpReserved, LPWSTR lpClass, LPDWORD lpcClass, PFILETIME lpftLastWriteTime);
|
||||
WINPR_API LONG RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcName,
|
||||
@ -358,6 +294,17 @@ WINPR_API LONG RegGetValueA(HKEY hkey, LPCSTR lpSubKey, LPCSTR lpValue,
|
||||
#define RegGetValue RegGetValueA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegLoadAppKeyW(LPCWSTR lpFile, PHKEY phkResult,
|
||||
REGSAM samDesired, DWORD dwOptions, DWORD Reserved);
|
||||
WINPR_API LONG RegLoadAppKeyA(LPCSTR lpFile, PHKEY phkResult,
|
||||
REGSAM samDesired, DWORD dwOptions, DWORD Reserved);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define RegLoadAppKey RegLoadAppKeyW
|
||||
#else
|
||||
#define RegLoadAppKey RegLoadAppKeyA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegLoadKeyW(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpFile);
|
||||
WINPR_API LONG RegLoadKeyA(HKEY hKey, LPCSTR lpSubKey, LPCSTR lpFile);
|
||||
|
||||
@ -391,21 +338,8 @@ WINPR_API LONG RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM
|
||||
#define RegOpenKeyEx RegOpenKeyExA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegOpenKeyTransactedW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions,
|
||||
REGSAM samDesired, PHKEY phkResult, HANDLE hTransaction, PVOID pExtendedParameter);
|
||||
WINPR_API LONG RegOpenKeyTransactedA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions,
|
||||
REGSAM samDesired, PHKEY phkResult, HANDLE hTransaction, PVOID pExtendedParameter);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define RegOpenKeyTransacted RegOpenKeyTransactedW
|
||||
#else
|
||||
#define RegOpenKeyTransacted RegOpenKeyTransactedA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegOpenUserClassesRoot(HANDLE hToken, DWORD dwOptions, REGSAM samDesired, PHKEY phkResult);
|
||||
|
||||
WINPR_API LONG RegOverridePredefKey(HKEY hKey, HKEY hNewHKey);
|
||||
|
||||
WINPR_API LONG RegQueryInfoKeyW(HKEY hKey, LPWSTR lpClass, LPDWORD lpcClass, LPDWORD lpReserved,
|
||||
LPDWORD lpcSubKeys, LPDWORD lpcMaxSubKeyLen, LPDWORD lpcMaxClassLen,
|
||||
LPDWORD lpcValues, LPDWORD lpcMaxValueNameLen, LPDWORD lpcMaxValueLen,
|
||||
@ -421,10 +355,6 @@ WINPR_API LONG RegQueryInfoKeyA(HKEY hKey, LPSTR lpClass, LPDWORD lpcClass, LPDW
|
||||
#define RegQueryInfoKey RegQueryInfoKeyA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegQueryMultipleValues(HKEY hKey, PVALENT val_list, DWORD num_vals, LPTSTR lpValueBuf, LPDWORD ldwTotsize);
|
||||
|
||||
WINPR_API LONG RegQueryReflectionKey(HKEY hBase, BOOL* bIsReflectionDisabled);
|
||||
|
||||
WINPR_API LONG RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName,
|
||||
LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
|
||||
WINPR_API LONG RegQueryValueExA(HKEY hKey, LPCSTR lpValueName,
|
||||
@ -436,15 +366,6 @@ WINPR_API LONG RegQueryValueExA(HKEY hKey, LPCSTR lpValueName,
|
||||
#define RegQueryValueEx RegQueryValueExA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegReplaceKeyW(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpNewFile, LPCWSTR lpOldFile);
|
||||
WINPR_API LONG RegReplaceKeyA(HKEY hKey, LPCSTR lpSubKey, LPCSTR lpNewFile, LPCSTR lpOldFile);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define RegReplaceKey RegReplaceKeyW
|
||||
#else
|
||||
#define RegReplaceKey RegReplaceKeyA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegRestoreKeyW(HKEY hKey, LPCWSTR lpFile, DWORD dwFlags);
|
||||
WINPR_API LONG RegRestoreKeyA(HKEY hKey, LPCSTR lpFile, DWORD dwFlags);
|
||||
|
||||
@ -454,15 +375,6 @@ WINPR_API LONG RegRestoreKeyA(HKEY hKey, LPCSTR lpFile, DWORD dwFlags);
|
||||
#define RegRestoreKey RegRestoreKeyA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegSaveKeyW(HKEY hKey, LPCWSTR lpFile, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
|
||||
WINPR_API LONG RegSaveKeyA(HKEY hKey, LPCSTR lpFile, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define RegSaveKey RegSaveKeyW
|
||||
#else
|
||||
#define RegSaveKey RegSaveKeyA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegSaveKeyExW(HKEY hKey, LPCWSTR lpFile, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD Flags);
|
||||
WINPR_API LONG RegSaveKeyExA(HKEY hKey, LPCSTR lpFile, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD Flags);
|
||||
|
||||
@ -472,15 +384,6 @@ WINPR_API LONG RegSaveKeyExA(HKEY hKey, LPCSTR lpFile, LPSECURITY_ATTRIBUTES lpS
|
||||
#define RegSaveKeyEx RegSaveKeyExA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegSetKeyValueW(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValueName, DWORD dwType, LPCVOID lpData, DWORD cbData);
|
||||
WINPR_API LONG RegSetKeyValueA(HKEY hKey, LPCSTR lpSubKey, LPCSTR lpValueName, DWORD dwType, LPCVOID lpData, DWORD cbData);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define RegSetKeyValue RegSetKeyValueW
|
||||
#else
|
||||
#define RegSetKeyValue RegSetKeyValueA
|
||||
#endif
|
||||
|
||||
WINPR_API LONG RegSetKeySecurity(HKEY hKey, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor);
|
||||
|
||||
WINPR_API LONG RegSetValueExW(HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, const BYTE* lpData, DWORD cbData);
|
||||
|
55
include/winpr/sam.h
Normal file
55
include/winpr/sam.h
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Security Accounts Manager (SAM)
|
||||
*
|
||||
* Copyright 2012 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_UTILS_SAM_H
|
||||
#define WINPR_UTILS_SAM_H
|
||||
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
struct winpr_sam
|
||||
{
|
||||
FILE* fp;
|
||||
char* line;
|
||||
char* buffer;
|
||||
BOOL read_only;
|
||||
};
|
||||
typedef struct winpr_sam WINPR_SAM;
|
||||
|
||||
struct winpr_sam_entry
|
||||
{
|
||||
LPSTR User;
|
||||
UINT32 UserLength;
|
||||
LPSTR Domain;
|
||||
UINT32 DomainLength;
|
||||
BYTE LmHash[16];
|
||||
BYTE NtHash[16];
|
||||
};
|
||||
typedef struct winpr_sam_entry WINPR_SAM_ENTRY;
|
||||
|
||||
WINPR_API WINPR_SAM_ENTRY* SamLookupUserA(WINPR_SAM* sam, LPSTR User, UINT32 UserLength, LPSTR Domain, UINT32 DomainLength);
|
||||
WINPR_API WINPR_SAM_ENTRY* SamLookupUserW(WINPR_SAM* sam, LPWSTR User, UINT32 UserLength, LPWSTR Domain, UINT32 DomainLength);
|
||||
|
||||
WINPR_API void SamFreeEntry(WINPR_SAM* sam, WINPR_SAM_ENTRY* entry);
|
||||
|
||||
WINPR_API WINPR_SAM* SamOpen(BOOL read_only);
|
||||
WINPR_API void SamClose(WINPR_SAM* sam);
|
||||
|
||||
#endif /* WINPR_UTILS_SAM_H */
|
||||
|
34
include/winpr/security.h
Normal file
34
include/winpr/security.h
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Security Definitions
|
||||
*
|
||||
* Copyright 2012 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_SECURITY_H
|
||||
#define WINPR_SECURITY_H
|
||||
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
typedef struct _LSA_UNICODE_STRING
|
||||
{
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;
|
||||
|
||||
#endif /* WINPR_SECURITY_H */
|
||||
|
@ -22,19 +22,18 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
//#define NATIVE_SSPI
|
||||
|
||||
#include <wchar.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/windows.h>
|
||||
#include <winpr/security.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <tchar.h>
|
||||
#include <winerror.h>
|
||||
|
||||
#ifdef NATIVE_SSPI
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
#define SECURITY_WIN32
|
||||
#include <sspi.h>
|
||||
#include <security.h>
|
||||
@ -103,6 +102,7 @@ typedef SecPkgInfoW* PSecPkgInfoW;
|
||||
#endif
|
||||
|
||||
#define NTLMSP_NAME _T("NTLM")
|
||||
#define NEGOSSP_NAME _T("Negotiate")
|
||||
|
||||
#endif
|
||||
|
||||
|
90
include/winpr/sspicli.h
Normal file
90
include/winpr/sspicli.h
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Security Support Provider Interface
|
||||
*
|
||||
* Copyright 2012 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_SSPICLI_H
|
||||
#define WINPR_SSPICLI_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* An unknown name type */
|
||||
NameUnknown = 0,
|
||||
|
||||
/* The fully qualified distinguished name (for example, CN=Jeff Smith,OU=Users,DC=Engineering,DC=Microsoft,DC=Com) */
|
||||
NameFullyQualifiedDN = 1,
|
||||
|
||||
/*
|
||||
* A legacy account name (for example, Engineering\JSmith).
|
||||
* The domain-only version includes trailing backslashes (\\)
|
||||
*/
|
||||
NameSamCompatible = 2,
|
||||
|
||||
/*
|
||||
* A "friendly" display name (for example, Jeff Smith).
|
||||
* The display name is not necessarily the defining relative distinguished name (RDN)
|
||||
*/
|
||||
NameDisplay = 3,
|
||||
|
||||
/* A GUID string that the IIDFromString function returns (for example, {4fa050f0-f561-11cf-bdd9-00aa003a77b6}) */
|
||||
NameUniqueId = 6,
|
||||
|
||||
/*
|
||||
* The complete canonical name (for example, engineering.microsoft.com/software/someone).
|
||||
* The domain-only version includes a trailing forward slash (/)
|
||||
*/
|
||||
NameCanonical = 7,
|
||||
|
||||
/* The user principal name (for example, someone@example.com) */
|
||||
NameUserPrincipal = 8,
|
||||
|
||||
/*
|
||||
* The same as NameCanonical except that the rightmost forward slash (/)
|
||||
* is replaced with a new line character (\n), even in a domain-only case
|
||||
* (for example, engineering.microsoft.com/software\nJSmith)
|
||||
*/
|
||||
NameCanonicalEx = 9,
|
||||
|
||||
/* The generalized service principal name (for example, www/www.microsoft.com@microsoft.com) */
|
||||
NameServicePrincipal = 10,
|
||||
|
||||
/* The DNS domain name followed by a backward-slash and the SAM user name */
|
||||
NameDnsDomain = 12
|
||||
|
||||
} EXTENDED_NAME_FORMAT, *PEXTENDED_NAME_FORMAT;
|
||||
|
||||
WINPR_API BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize);
|
||||
WINPR_API BOOL GetUserNameExW(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define GetUserNameEx GetUserNameExW
|
||||
#else
|
||||
#define GetUserNameEx GetUserNameExA
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_SSPICLI_H */
|
||||
|
@ -26,10 +26,10 @@
|
||||
|
||||
struct stream
|
||||
{
|
||||
BYTE* p;
|
||||
BYTE* end;
|
||||
BYTE* data;
|
||||
BYTE* pointer;
|
||||
BYTE* buffer;
|
||||
size_t size;
|
||||
size_t length;
|
||||
};
|
||||
typedef struct stream Stream;
|
||||
typedef struct stream* PStream;
|
||||
@ -37,74 +37,74 @@ typedef struct stream* PStream;
|
||||
WINPR_API PStream PStreamAlloc(size_t size);
|
||||
WINPR_API void StreamAlloc(PStream s, size_t size);
|
||||
WINPR_API void StreamReAlloc(PStream s, size_t size);
|
||||
WINPR_API PStream PStreamAllocAttach(BYTE* data, size_t size);
|
||||
WINPR_API void StreamAllocAttach(PStream s, BYTE* data, size_t size);
|
||||
WINPR_API PStream PStreamAllocAttach(BYTE* buffer, size_t size);
|
||||
WINPR_API void StreamAllocAttach(PStream s, BYTE* buffer, size_t size);
|
||||
WINPR_API void PStreamFree(PStream s);
|
||||
WINPR_API void StreamFree(PStream s);
|
||||
WINPR_API void PStreamFreeDetach(PStream s);
|
||||
WINPR_API void StreamFreeDetach(PStream s);
|
||||
WINPR_API void StreamAttach(PStream s, BYTE* data, size_t size);
|
||||
WINPR_API void StreamAttach(PStream s, BYTE* buffer, size_t size);
|
||||
WINPR_API void StreamDetach(PStream s);
|
||||
|
||||
#define StreamRead_UINT8(_s, _v) do { _v = \
|
||||
*_s->p++; } while (0)
|
||||
*_s->pointer++; } while (0)
|
||||
|
||||
#define StreamRead_UINT16(_s, _v) do { _v = \
|
||||
(UINT16)(*_s->p) + \
|
||||
(((UINT16)(*(_s->p + 1))) << 8); \
|
||||
_s->p += 2; } while (0)
|
||||
(UINT16)(*_s->pointer) + \
|
||||
(((UINT16)(*(_s->pointer + 1))) << 8); \
|
||||
_s->pointer += 2; } while (0)
|
||||
|
||||
#define StreamRead_UINT16_BE(_s, _v) do { _v = \
|
||||
(((UINT16)(*_s->p)) << 8) + \
|
||||
(UINT16)(*(_s->p + 1)); \
|
||||
_s->p += 2; } while (0)
|
||||
(((UINT16)(*_s->pointer)) << 8) + \
|
||||
(UINT16)(*(_s->pointer + 1)); \
|
||||
_s->pointer += 2; } while (0)
|
||||
|
||||
#define StreamRead_UINT32(_s, _v) do { _v = \
|
||||
(UINT32)(*_s->p) + \
|
||||
(((UINT32)(*(_s->p + 1))) << 8) + \
|
||||
(((UINT32)(*(_s->p + 2))) << 16) + \
|
||||
(((UINT32)(*(_s->p + 3))) << 24); \
|
||||
_s->p += 4; } while (0)
|
||||
(UINT32)(*_s->pointer) + \
|
||||
(((UINT32)(*(_s->pointer + 1))) << 8) + \
|
||||
(((UINT32)(*(_s->pointer + 2))) << 16) + \
|
||||
(((UINT32)(*(_s->pointer + 3))) << 24); \
|
||||
_s->pointer += 4; } while (0)
|
||||
|
||||
#define StreamRead_UINT32_BE(_s, _v) do { _v = \
|
||||
(((uint32)(*(_s->p))) << 24) + \
|
||||
(((uint32)(*(_s->p + 1))) << 16) + \
|
||||
(((uint32)(*(_s->p + 2))) << 8) + \
|
||||
(((uint32)(*(_s->p + 3)))); \
|
||||
_s->p += 4; } while (0)
|
||||
(((uint32)(*(_s->pointer))) << 24) + \
|
||||
(((uint32)(*(_s->pointer + 1))) << 16) + \
|
||||
(((uint32)(*(_s->pointer + 2))) << 8) + \
|
||||
(((uint32)(*(_s->pointer + 3)))); \
|
||||
_s->pointer += 4; } while (0)
|
||||
|
||||
#define StreamRead_UINT64(_s, _v) do { _v = \
|
||||
(UINT64)(*_s->p) + \
|
||||
(((UINT64)(*(_s->p + 1))) << 8) + \
|
||||
(((UINT64)(*(_s->p + 2))) << 16) + \
|
||||
(((UINT64)(*(_s->p + 3))) << 24) + \
|
||||
(((UINT64)(*(_s->p + 4))) << 32) + \
|
||||
(((UINT64)(*(_s->p + 5))) << 40) + \
|
||||
(((UINT64)(*(_s->p + 6))) << 48) + \
|
||||
(((UINT64)(*(_s->p + 7))) << 56); \
|
||||
_s->p += 8; } while (0)
|
||||
(UINT64)(*_s->pointer) + \
|
||||
(((UINT64)(*(_s->pointer + 1))) << 8) + \
|
||||
(((UINT64)(*(_s->pointer + 2))) << 16) + \
|
||||
(((UINT64)(*(_s->pointer + 3))) << 24) + \
|
||||
(((UINT64)(*(_s->pointer + 4))) << 32) + \
|
||||
(((UINT64)(*(_s->pointer + 5))) << 40) + \
|
||||
(((UINT64)(*(_s->pointer + 6))) << 48) + \
|
||||
(((UINT64)(*(_s->pointer + 7))) << 56); \
|
||||
_s->pointer += 8; } while (0)
|
||||
|
||||
#define StreamRead(_s, _b, _n) do { \
|
||||
memcpy(_b, (_s->p), (_n)); \
|
||||
_s->p += (_n); \
|
||||
memcpy(_b, (_s->pointer), (_n)); \
|
||||
_s->pointer += (_n); \
|
||||
} while (0)
|
||||
|
||||
#define StreamWrite_UINT8(_s, _v) do { \
|
||||
*_s->p++ = (UINT8)(_v); } while (0)
|
||||
*_s->pointer++ = (UINT8)(_v); } while (0)
|
||||
|
||||
#define StreamWrite_UINT16(_s, _v) do { \
|
||||
*_s->p++ = (_v) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 8) & 0xFF; } while (0)
|
||||
*_s->pointer++ = (_v) & 0xFF; \
|
||||
*_s->pointer++ = ((_v) >> 8) & 0xFF; } while (0)
|
||||
|
||||
#define StreamWrite_UINT16_BE(_s, _v) do { \
|
||||
*_s->p++ = ((_v) >> 8) & 0xFF; \
|
||||
*_s->p++ = (_v) & 0xFF; } while (0)
|
||||
*_s->pointer++ = ((_v) >> 8) & 0xFF; \
|
||||
*_s->pointer++ = (_v) & 0xFF; } while (0)
|
||||
|
||||
#define StreamWrite_UINT32(_s, _v) do { \
|
||||
*_s->p++ = (_v) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 8) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 16) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 24) & 0xFF; } while (0)
|
||||
*_s->pointer++ = (_v) & 0xFF; \
|
||||
*_s->pointer++ = ((_v) >> 8) & 0xFF; \
|
||||
*_s->pointer++ = ((_v) >> 16) & 0xFF; \
|
||||
*_s->pointer++ = ((_v) >> 24) & 0xFF; } while (0)
|
||||
|
||||
#define StreamWrite_UINT32_BE(_s, _v) do { \
|
||||
StreamWrite_UINT16_BE(_s, ((_v) >> 16 & 0xFFFF)); \
|
||||
@ -112,52 +112,52 @@ WINPR_API void StreamDetach(PStream s);
|
||||
} while (0)
|
||||
|
||||
#define StreamWrite_UINT64(_s, _v) do { \
|
||||
*_s->p++ = (UINT64)(_v) & 0xFF; \
|
||||
*_s->p++ = ((UINT64)(_v) >> 8) & 0xFF; \
|
||||
*_s->p++ = ((UINT64)(_v) >> 16) & 0xFF; \
|
||||
*_s->p++ = ((UINT64)(_v) >> 24) & 0xFF; \
|
||||
*_s->p++ = ((UINT64)(_v) >> 32) & 0xFF; \
|
||||
*_s->p++ = ((UINT64)(_v) >> 40) & 0xFF; \
|
||||
*_s->p++ = ((UINT64)(_v) >> 48) & 0xFF; \
|
||||
*_s->p++ = ((UINT64)(_v) >> 56) & 0xFF; } while (0)
|
||||
*_s->pointer++ = (UINT64)(_v) & 0xFF; \
|
||||
*_s->pointer++ = ((UINT64)(_v) >> 8) & 0xFF; \
|
||||
*_s->pointer++ = ((UINT64)(_v) >> 16) & 0xFF; \
|
||||
*_s->pointer++ = ((UINT64)(_v) >> 24) & 0xFF; \
|
||||
*_s->pointer++ = ((UINT64)(_v) >> 32) & 0xFF; \
|
||||
*_s->pointer++ = ((UINT64)(_v) >> 40) & 0xFF; \
|
||||
*_s->pointer++ = ((UINT64)(_v) >> 48) & 0xFF; \
|
||||
*_s->pointer++ = ((UINT64)(_v) >> 56) & 0xFF; } while (0)
|
||||
|
||||
#define StreamWrite(_s, _b, _n) do { \
|
||||
memcpy(_s->p, (_b), (_n)); \
|
||||
_s->p += (_n); \
|
||||
memcpy(_s->pointer, (_b), (_n)); \
|
||||
_s->pointer += (_n); \
|
||||
} while (0)
|
||||
|
||||
#define StreamPeek_UINT8(_s, _v) do { _v = \
|
||||
*_s->p; } while (0)
|
||||
*_s->pointer; } while (0)
|
||||
|
||||
#define StreamPeek_UINT16(_s, _v) do { _v = \
|
||||
(UINT16)(*_s->p) + \
|
||||
(((UINT16)(*(_s->p + 1))) << 8); \
|
||||
(UINT16)(*_s->pointer) + \
|
||||
(((UINT16)(*(_s->pointer + 1))) << 8); \
|
||||
} while (0)
|
||||
|
||||
#define StreamPeek_UINT32(_s, _v) do { _v = \
|
||||
(UINT32)(*_s->p) + \
|
||||
(((UINT32)(*(_s->p + 1))) << 8) + \
|
||||
(((UINT32)(*(_s->p + 2))) << 16) + \
|
||||
(((UINT32)(*(_s->p + 3))) << 24); \
|
||||
(UINT32)(*_s->pointer) + \
|
||||
(((UINT32)(*(_s->pointer + 1))) << 8) + \
|
||||
(((UINT32)(*(_s->pointer + 2))) << 16) + \
|
||||
(((UINT32)(*(_s->pointer + 3))) << 24); \
|
||||
} while (0)
|
||||
|
||||
#define StreamPeek_UINT64(_s, _v) do { _v = \
|
||||
(UINT64)(*_s->p) + \
|
||||
(((UINT64)(*(_s->p + 1))) << 8) + \
|
||||
(((UINT64)(*(_s->p + 2))) << 16) + \
|
||||
(((UINT64)(*(_s->p + 3))) << 24) + \
|
||||
(((UINT64)(*(_s->p + 4))) << 32) + \
|
||||
(((UINT64)(*(_s->p + 5))) << 40) + \
|
||||
(((UINT64)(*(_s->p + 6))) << 48) + \
|
||||
(((UINT64)(*(_s->p + 7))) << 56); \
|
||||
(UINT64)(*_s->pointer) + \
|
||||
(((UINT64)(*(_s->pointer + 1))) << 8) + \
|
||||
(((UINT64)(*(_s->pointer + 2))) << 16) + \
|
||||
(((UINT64)(*(_s->pointer + 3))) << 24) + \
|
||||
(((UINT64)(*(_s->pointer + 4))) << 32) + \
|
||||
(((UINT64)(*(_s->pointer + 5))) << 40) + \
|
||||
(((UINT64)(*(_s->pointer + 6))) << 48) + \
|
||||
(((UINT64)(*(_s->pointer + 7))) << 56); \
|
||||
} while (0)
|
||||
|
||||
#define StreamPeek(_s, _b, _n) do { \
|
||||
memcpy(_b, (_s->p), (_n)); \
|
||||
memcpy(_b, (_s->pointer), (_n)); \
|
||||
} while (0)
|
||||
|
||||
#define StreamSeek(_s,_offset) _s->p += (_offset)
|
||||
#define StreamRewind(_s,_offset) _s->p -= (_offset)
|
||||
#define StreamSeek(_s,_offset) _s->pointer += (_offset)
|
||||
#define StreamRewind(_s,_offset) _s->pointer -= (_offset)
|
||||
|
||||
#define StreamSeek_UINT8(_s) StreamSeek(_s, 1)
|
||||
#define StreamSeek_UINT16(_s) StreamSeek(_s, 2)
|
||||
@ -170,37 +170,33 @@ WINPR_API void StreamDetach(PStream s);
|
||||
#define StreamRewind_UINT64(_s) StreamRewind(_s, 8)
|
||||
|
||||
#define StreamZero(_s, _n) do { \
|
||||
memset(_s->p, '\0', (_n)); \
|
||||
_s->p += (_n); \
|
||||
memset(_s->pointer, '\0', (_n)); \
|
||||
_s->pointer += (_n); \
|
||||
} while (0)
|
||||
|
||||
#define StreamFill(_s, _v, _n) do { \
|
||||
memset(_s->p, _v, (_n)); \
|
||||
_s->p += (_n); \
|
||||
memset(_s->pointer, _v, (_n)); \
|
||||
_s->pointer += (_n); \
|
||||
} while (0)
|
||||
|
||||
#define StreamCopy(_dst, _src, _n) do { \
|
||||
memcpy(_dst->p, _src->p, _n); \
|
||||
_dst->p += _n; \
|
||||
_src->p += _n; \
|
||||
memcpy(_dst->pointer, _src->pointer, _n); \
|
||||
_dst->pointer += _n; \
|
||||
_src->pointer += _n; \
|
||||
} while (0)
|
||||
|
||||
#define StreamGetOffset(_s) (_s->p - _s->data)
|
||||
#define StreamSetOffset(_s, _m) _s->p = _s->data + (_m)
|
||||
#define StreamGetPointer(_s, _p) _p = _s->pointer
|
||||
#define StreamSetPointer(_s, _p) _s->pointer = _p
|
||||
|
||||
#define StreamSeal(_s) _s->end = (_s->p - _s->data)
|
||||
#define StreamGetPosition(_s) (_s->pointer - _s->buffer)
|
||||
#define StreamSetPosition(_s, _p) _s->pointer = _s->buffer + (_p)
|
||||
|
||||
#define StreamGetMark(_s, _m) _m = _s->p
|
||||
#define StreamSetMark(_s, _m) _s->p = _m
|
||||
#define StreamPointer(_s) _s->pointer
|
||||
#define StreamBuffer(_s) _s->buffer
|
||||
#define StreamSize(_s) _s->size
|
||||
#define StreamLength(_s) _s->length
|
||||
|
||||
#define StreamGetData(_s) _s->data
|
||||
#define StreamGetPointer(_s) _s->p
|
||||
#define StreamSetPointer(_s, _m) _s->p = _m
|
||||
#define StreamGetEnd(_s) _s->end
|
||||
#define StreamGetSize(_s) _s->size
|
||||
|
||||
#define StreamSize(_s) (_s->p - _s->data)
|
||||
#define StreamSealedSize(_s) (_s->end - _s->data)
|
||||
#define StreamRemainingSize(_s) (_s->size - (_s->p - _s->data))
|
||||
#define StreamRemainingSize(_s) (_s->size - (_s->pointer - _s->buffer))
|
||||
#define StreamRemainingLength(_s) (_s->length - (_s->pointer - _s->buffer))
|
||||
|
||||
#endif /* WINPR_UTILS_STREAM_H */
|
||||
|
@ -45,7 +45,7 @@
|
||||
#define MB_ERR_INVALID_CHARS 0x00000008
|
||||
|
||||
WINPR_API char* _strdup(const char* strSource);
|
||||
WINPR_API wchar_t* _wcsdup(const wchar_t* strSource);
|
||||
WINPR_API WCHAR* _wcsdup(const WCHAR* strSource);
|
||||
|
||||
WINPR_API LPSTR CharUpperA(LPSTR lpsz);
|
||||
WINPR_API LPWSTR CharUpperW(LPWSTR lpsz);
|
||||
@ -125,6 +125,24 @@ WINPR_API int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiBy
|
||||
WINPR_API int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
|
||||
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
|
||||
|
||||
WINPR_API int lstrlenA(LPCSTR lpString);
|
||||
WINPR_API int lstrlenW(LPCWSTR lpString);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define lstrlen lstrlenW
|
||||
#else
|
||||
#define lstrlen lstrlenA
|
||||
#endif
|
||||
|
||||
WINPR_API int lstrcmpA(LPCSTR lpString1, LPCSTR lpString2);
|
||||
WINPR_API int lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define lstrcmp lstrcmpW
|
||||
#else
|
||||
#define lstrcmp lstrcmpA
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_CRT_STRING_H */
|
||||
|
64
include/winpr/synch.h
Normal file
64
include/winpr/synch.h
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Synchronization Functions
|
||||
*
|
||||
* Copyright 2012 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_SYNCH_H
|
||||
#define WINPR_SYNCH_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#include <winpr/handle.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
WINPR_API HANDLE CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCSTR lpName);
|
||||
WINPR_API HANDLE CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCWSTR lpName);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define CreateSemaphore CreateSemaphoreW
|
||||
#else
|
||||
#define CreateSemaphore CreateSemaphoreA
|
||||
#endif
|
||||
|
||||
WINPR_API HANDLE OpenSemaphoreA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName);
|
||||
WINPR_API HANDLE OpenSemaphoreW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define OpenSemaphore OpenSemaphoreW
|
||||
#else
|
||||
#define OpenSemaphore OpenSemaphoreA
|
||||
#endif
|
||||
|
||||
WINPR_API BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount);
|
||||
|
||||
#define WAIT_OBJECT_0 0x00000000L
|
||||
#define WAIT_ABANDONED 0x00000080L
|
||||
#define WAIT_TIMEOUT 0x00000102L
|
||||
#define WAIT_FAILED ((DWORD) 0xFFFFFFFF)
|
||||
|
||||
WINPR_API DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
|
||||
WINPR_API DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_SYNCH_H */
|
||||
|
153
include/winpr/sysinfo.h
Normal file
153
include/winpr/sysinfo.h
Normal file
@ -0,0 +1,153 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* System Information
|
||||
*
|
||||
* Copyright 2012 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_SYSINFO_H
|
||||
#define WINPR_SYSINFO_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
typedef enum _COMPUTER_NAME_FORMAT
|
||||
{
|
||||
ComputerNameNetBIOS,
|
||||
ComputerNameDnsHostname,
|
||||
ComputerNameDnsDomain,
|
||||
ComputerNameDnsFullyQualified,
|
||||
ComputerNamePhysicalNetBIOS,
|
||||
ComputerNamePhysicalDnsHostname,
|
||||
ComputerNamePhysicalDnsDomain,
|
||||
ComputerNamePhysicalDnsFullyQualified,
|
||||
ComputerNameMax
|
||||
} COMPUTER_NAME_FORMAT;
|
||||
|
||||
WINPR_API BOOL GetComputerNameExA(COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD nSize);
|
||||
WINPR_API BOOL GetComputerNameExW(COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD nSize);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define GetComputerNameEx GetComputerNameExW
|
||||
#else
|
||||
#define GetComputerNameEx GetComputerNameExA
|
||||
#endif
|
||||
|
||||
typedef struct _OSVERSIONINFOA
|
||||
{
|
||||
DWORD dwOSVersionInfoSize;
|
||||
DWORD dwMajorVersion;
|
||||
DWORD dwMinorVersion;
|
||||
DWORD dwBuildNumber;
|
||||
DWORD dwPlatformId;
|
||||
CHAR szCSDVersion[128];
|
||||
} OSVERSIONINFOA, *POSVERSIONINFOA, *LPOSVERSIONINFOA;
|
||||
|
||||
typedef struct _OSVERSIONINFOW
|
||||
{
|
||||
DWORD dwOSVersionInfoSize;
|
||||
DWORD dwMajorVersion;
|
||||
DWORD dwMinorVersion;
|
||||
DWORD dwBuildNumber;
|
||||
DWORD dwPlatformId;
|
||||
WCHAR szCSDVersion[128];
|
||||
} OSVERSIONINFOW, *POSVERSIONINFOW, *LPOSVERSIONINFOW;
|
||||
|
||||
typedef struct _OSVERSIONINFOEXA
|
||||
{
|
||||
DWORD dwOSVersionInfoSize;
|
||||
DWORD dwMajorVersion;
|
||||
DWORD dwMinorVersion;
|
||||
DWORD dwBuildNumber;
|
||||
DWORD dwPlatformId;
|
||||
CHAR szCSDVersion[128];
|
||||
WORD wServicePackMajor;
|
||||
WORD wServicePackMinor;
|
||||
WORD wSuiteMask;
|
||||
BYTE wProductType;
|
||||
BYTE wReserved;
|
||||
} OSVERSIONINFOEXA, *POSVERSIONINFOEXA, *LPOSVERSIONINFOEXA;
|
||||
|
||||
typedef struct _OSVERSIONINFOEXW
|
||||
{
|
||||
DWORD dwOSVersionInfoSize;
|
||||
DWORD dwMajorVersion;
|
||||
DWORD dwMinorVersion;
|
||||
DWORD dwBuildNumber;
|
||||
DWORD dwPlatformId;
|
||||
WCHAR szCSDVersion[128];
|
||||
WORD wServicePackMajor;
|
||||
WORD wServicePackMinor;
|
||||
WORD wSuiteMask;
|
||||
BYTE wProductType;
|
||||
BYTE wReserved;
|
||||
} OSVERSIONINFOEXW, *POSVERSIONINFOEXW, *LPOSVERSIONINFOEXW;
|
||||
|
||||
#ifdef UNICODE
|
||||
#define OSVERSIONINFO OSVERSIONINFOW
|
||||
#define OSVERSIONINFOEX OSVERSIONINFOEXW
|
||||
#define POSVERSIONINFO POSVERSIONINFOW
|
||||
#define POSVERSIONINFOEX POSVERSIONINFOEXW
|
||||
#define LPOSVERSIONINFO LPOSVERSIONINFOW
|
||||
#define LPOSVERSIONINFOEX LPOSVERSIONINFOEXW
|
||||
#else
|
||||
#define OSVERSIONINFO OSVERSIONINFOA
|
||||
#define OSVERSIONINFOEX OSVERSIONINFOEXA
|
||||
#define POSVERSIONINFO POSVERSIONINFOA
|
||||
#define POSVERSIONINFOEX POSVERSIONINFOEXA
|
||||
#define LPOSVERSIONINFO LPOSVERSIONINFOA
|
||||
#define LPOSVERSIONINFOEX LPOSVERSIONINFOEXA
|
||||
#endif
|
||||
|
||||
#define VER_PLATFORM_WIN32_NT 0x00000002
|
||||
|
||||
#define VER_SUITE_BACKOFFICE 0x00000004
|
||||
#define VER_SUITE_BLADE 0x00000400
|
||||
#define VER_SUITE_COMPUTE_SERVER 0x00004000
|
||||
#define VER_SUITE_DATACENTER 0x00000080
|
||||
#define VER_SUITE_ENTERPRISE 0x00000002
|
||||
#define VER_SUITE_EMBEDDEDNT 0x00000040
|
||||
#define VER_SUITE_PERSONAL 0x00000200
|
||||
#define VER_SUITE_SINGLEUSERTS 0x00000100
|
||||
#define VER_SUITE_SMALLBUSINESS 0x00000001
|
||||
#define VER_SUITE_SMALLBUSINESS_RESTRICTED 0x00000020
|
||||
#define VER_SUITE_STORAGE_SERVER 0x00002000
|
||||
#define VER_SUITE_TERMINAL 0x00000010
|
||||
#define VER_SUITE_WH_SERVER 0x00008000
|
||||
|
||||
#define VER_NT_DOMAIN_CONTROLLER 0x0000002
|
||||
#define VER_NT_SERVER 0x0000003
|
||||
#define VER_NT_WORKSTATION 0x0000001
|
||||
|
||||
WINPR_API BOOL GetVersionExA(LPOSVERSIONINFOA lpVersionInformation);
|
||||
WINPR_API BOOL GetVersionExW(LPOSVERSIONINFOW lpVersionInformation);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define GetVersionEx GetVersionExW
|
||||
#else
|
||||
#define GetVersionEx GetVersionExA
|
||||
#endif
|
||||
|
||||
WINPR_API VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_SYSINFO_H */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Windows Registry
|
||||
* TCHAR
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
@ -17,16 +17,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/xmlmemory.h>
|
||||
#ifndef WINPR_TCHAR_H
|
||||
#define WINPR_TCHAR_H
|
||||
|
||||
struct _registry_xml
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr node;
|
||||
};
|
||||
typedef struct _registry_xml RegistryXml;
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
RegistryXml* registry_xml_new();
|
||||
RegistryXml* registry_xml_open();
|
||||
void registry_xml_close(RegistryXml* registry);
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <tchar.h>
|
||||
|
||||
#else
|
||||
|
||||
#ifdef UNICODE
|
||||
typedef WCHAR TCHAR;
|
||||
#define _tprintf wprintf
|
||||
#else
|
||||
typedef CHAR TCHAR;
|
||||
#define _tprintf printf
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_TCHAR_H */
|
@ -42,7 +42,7 @@
|
||||
typedef int BOOL, *PBOOL, *LPBOOL;
|
||||
typedef unsigned char BYTE, *PBYTE, *LPBYTE;
|
||||
typedef BYTE BOOLEAN, *PBOOLEAN;
|
||||
typedef wchar_t WCHAR, *PWCHAR;
|
||||
typedef unsigned short WCHAR, *PWCHAR;
|
||||
typedef WCHAR* BSTR;
|
||||
typedef char CHAR, *PCHAR;
|
||||
typedef unsigned long DWORD, *PDWORD, *LPDWORD;
|
||||
@ -54,14 +54,22 @@ typedef float FLOAT;
|
||||
typedef unsigned char UCHAR, *PUCHAR;
|
||||
typedef short SHORT;
|
||||
|
||||
typedef void* HANDLE;
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
typedef void* HANDLE, *LPHANDLE;
|
||||
typedef DWORD HCALL;
|
||||
typedef int INT, *LPINT;
|
||||
typedef signed char INT8;
|
||||
typedef signed short INT16;
|
||||
typedef signed int INT32;
|
||||
typedef signed __int64 INT64;
|
||||
typedef const wchar_t* LMCSTR;
|
||||
typedef const WCHAR* LMCSTR;
|
||||
typedef WCHAR* LMSTR;
|
||||
typedef long LONG, *PLONG, *LPLONG;
|
||||
typedef signed __int64 LONGLONG;
|
||||
@ -74,10 +82,10 @@ typedef signed int LONG32;
|
||||
typedef signed __int64 LONG64;
|
||||
typedef const char* LPCSTR;
|
||||
|
||||
typedef const wchar_t* LPCWSTR;
|
||||
typedef const WCHAR* LPCWSTR;
|
||||
typedef char* PSTR, *LPSTR;
|
||||
|
||||
typedef wchar_t* LPWSTR, *PWSTR;
|
||||
typedef WCHAR* LPWSTR, *PWSTR;
|
||||
|
||||
typedef unsigned __int64 QWORD;
|
||||
typedef UCHAR* STRING;
|
||||
@ -135,6 +143,23 @@ typedef LPSTR LPTSTR;
|
||||
typedef LPCSTR LPCTSTR;
|
||||
#endif
|
||||
|
||||
typedef union _ULARGE_INTEGER
|
||||
{
|
||||
struct
|
||||
{
|
||||
DWORD LowPart;
|
||||
DWORD HighPart;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
DWORD LowPart;
|
||||
DWORD HighPart;
|
||||
} u;
|
||||
|
||||
ULONGLONG QuadPart;
|
||||
} ULARGE_INTEGER, *PULARGE_INTEGER;
|
||||
|
||||
typedef struct _FILETIME
|
||||
{
|
||||
DWORD dwLowDateTime;
|
||||
@ -176,6 +201,13 @@ typedef struct _SECURITY_DESCRIPTOR
|
||||
PACL Dacl;
|
||||
} SECURITY_DESCRIPTOR, *PSECURITY_DESCRIPTOR;
|
||||
|
||||
typedef struct _SECURITY_ATTRIBUTES
|
||||
{
|
||||
DWORD nLength;
|
||||
LPVOID lpSecurityDescriptor;
|
||||
BOOL bInheritHandle;
|
||||
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
|
||||
|
||||
#endif
|
||||
|
||||
typedef BYTE byte;
|
||||
|
@ -78,7 +78,7 @@ void* brush_cache_get(rdpBrushCache* brush, uint32 index, uint32* bpp)
|
||||
|
||||
if (*bpp == 1)
|
||||
{
|
||||
if (index > brush->maxMonoEntries)
|
||||
if (index >= brush->maxMonoEntries)
|
||||
{
|
||||
printf("invalid brush (%d bpp) index: 0x%04X\n", *bpp, index);
|
||||
return NULL;
|
||||
@ -89,7 +89,7 @@ void* brush_cache_get(rdpBrushCache* brush, uint32 index, uint32* bpp)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index > brush->maxEntries)
|
||||
if (index >= brush->maxEntries)
|
||||
{
|
||||
printf("invalid brush (%d bpp) index: 0x%04X\n", *bpp, index);
|
||||
return NULL;
|
||||
@ -114,7 +114,7 @@ void brush_cache_put(rdpBrushCache* brush, uint32 index, void* entry, uint32 bpp
|
||||
|
||||
if (bpp == 1)
|
||||
{
|
||||
if (index > brush->maxMonoEntries)
|
||||
if (index >= brush->maxMonoEntries)
|
||||
{
|
||||
printf("invalid brush (%d bpp) index: 0x%04X\n", bpp, index);
|
||||
return;
|
||||
@ -130,7 +130,7 @@ void brush_cache_put(rdpBrushCache* brush, uint32 index, void* entry, uint32 bpp
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index > brush->maxEntries)
|
||||
if (index >= brush->maxEntries)
|
||||
{
|
||||
printf("invalid brush (%d bpp) index: 0x%04X\n", bpp, index);
|
||||
return;
|
||||
|
@ -51,7 +51,7 @@ void* nine_grid_cache_get(rdpNineGridCache* nine_grid, uint32 index)
|
||||
{
|
||||
void* entry;
|
||||
|
||||
if (index > nine_grid->maxEntries)
|
||||
if (index >= nine_grid->maxEntries)
|
||||
{
|
||||
printf("invalid NineGrid index: 0x%04X\n", index);
|
||||
return NULL;
|
||||
@ -72,7 +72,7 @@ void nine_grid_cache_put(rdpNineGridCache* nine_grid, uint32 index, void* entry)
|
||||
{
|
||||
void* prevEntry;
|
||||
|
||||
if (index > nine_grid->maxEntries)
|
||||
if (index >= nine_grid->maxEntries)
|
||||
{
|
||||
printf("invalid NineGrid index: 0x%04X\n", index);
|
||||
return;
|
||||
|
@ -71,7 +71,7 @@ rdpBitmap* offscreen_cache_get(rdpOffscreenCache* offscreen_cache, uint32 index)
|
||||
{
|
||||
rdpBitmap* bitmap;
|
||||
|
||||
if (index > offscreen_cache->maxEntries)
|
||||
if (index >= offscreen_cache->maxEntries)
|
||||
{
|
||||
printf("invalid offscreen bitmap index: 0x%04X\n", index);
|
||||
return NULL;
|
||||
@ -90,7 +90,7 @@ rdpBitmap* offscreen_cache_get(rdpOffscreenCache* offscreen_cache, uint32 index)
|
||||
|
||||
void offscreen_cache_put(rdpOffscreenCache* offscreen, uint32 index, rdpBitmap* bitmap)
|
||||
{
|
||||
if (index > offscreen->maxEntries)
|
||||
if (index >= offscreen->maxEntries)
|
||||
{
|
||||
printf("invalid offscreen bitmap index: 0x%04X\n", index);
|
||||
return;
|
||||
@ -104,7 +104,7 @@ void offscreen_cache_delete(rdpOffscreenCache* offscreen, uint32 index)
|
||||
{
|
||||
rdpBitmap* prevBitmap;
|
||||
|
||||
if (index > offscreen->maxEntries)
|
||||
if (index >= offscreen->maxEntries)
|
||||
{
|
||||
printf("invalid offscreen bitmap index (delete): 0x%04X\n", index);
|
||||
return;
|
||||
|
@ -32,7 +32,7 @@ void* palette_cache_get(rdpPaletteCache* palette_cache, uint32 index)
|
||||
{
|
||||
void* entry;
|
||||
|
||||
if (index > palette_cache->maxEntries)
|
||||
if (index >= palette_cache->maxEntries)
|
||||
{
|
||||
printf("invalid color table index: 0x%04X\n", index);
|
||||
return NULL;
|
||||
@ -51,7 +51,7 @@ void* palette_cache_get(rdpPaletteCache* palette_cache, uint32 index)
|
||||
|
||||
void palette_cache_put(rdpPaletteCache* palette_cache, uint32 index, void* entry)
|
||||
{
|
||||
if (index > palette_cache->maxEntries)
|
||||
if (index >= palette_cache->maxEntries)
|
||||
{
|
||||
printf("invalid color table index: 0x%04X\n", index);
|
||||
return;
|
||||
|
@ -26,6 +26,12 @@
|
||||
|
||||
#include "wtsvc.h"
|
||||
|
||||
#define CREATE_REQUEST_PDU 0x01
|
||||
#define DATA_FIRST_PDU 0x02
|
||||
#define DATA_PDU 0x03
|
||||
#define CLOSE_REQUEST_PDU 0x04
|
||||
#define CAPABILITY_REQUEST_PDU 0x05
|
||||
|
||||
typedef struct wts_data_item
|
||||
{
|
||||
uint16 channel_id;
|
||||
@ -39,10 +45,267 @@ static void wts_data_item_free(wts_data_item* item)
|
||||
xfree(item);
|
||||
}
|
||||
|
||||
static void WTSProcessChannelData(rdpPeerChannel* channel, int channelId, uint8* data, int size, int flags, int total_size)
|
||||
static rdpPeerChannel* wts_get_dvc_channel_by_id(WTSVirtualChannelManager* vcm, uint32 ChannelId)
|
||||
{
|
||||
LIST_ITEM* item;
|
||||
rdpPeerChannel* channel = NULL;
|
||||
|
||||
for (item = vcm->dvc_channel_list->head; item; item = item->next)
|
||||
{
|
||||
channel = (rdpPeerChannel*) item->data;
|
||||
if (channel->channel_id == ChannelId)
|
||||
break;
|
||||
}
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
static void wts_queue_receive_data(rdpPeerChannel* channel, const uint8* buffer, uint32 length)
|
||||
{
|
||||
wts_data_item* item;
|
||||
|
||||
item = xnew(wts_data_item);
|
||||
item->length = length;
|
||||
item->buffer = xmalloc(length);
|
||||
memcpy(item->buffer, buffer, length);
|
||||
|
||||
freerdp_mutex_lock(channel->mutex);
|
||||
list_enqueue(channel->receive_queue, item);
|
||||
freerdp_mutex_unlock(channel->mutex);
|
||||
|
||||
wait_obj_set(channel->receive_event);
|
||||
}
|
||||
|
||||
static void wts_queue_send_item(rdpPeerChannel* channel, wts_data_item* item)
|
||||
{
|
||||
WTSVirtualChannelManager* vcm;
|
||||
|
||||
vcm = channel->vcm;
|
||||
|
||||
item->channel_id = channel->channel_id;
|
||||
|
||||
freerdp_mutex_lock(vcm->mutex);
|
||||
list_enqueue(vcm->send_queue, item);
|
||||
freerdp_mutex_unlock(vcm->mutex);
|
||||
|
||||
wait_obj_set(vcm->send_event);
|
||||
}
|
||||
|
||||
static int wts_read_variable_uint(STREAM* s, int cbLen, uint32 *val)
|
||||
{
|
||||
switch (cbLen)
|
||||
{
|
||||
case 0:
|
||||
if (stream_get_left(s) < 1)
|
||||
return 0;
|
||||
stream_read_uint8(s, *val);
|
||||
return 1;
|
||||
case 1:
|
||||
if (stream_get_left(s) < 2)
|
||||
return 0;
|
||||
stream_read_uint16(s, *val);
|
||||
return 2;
|
||||
default:
|
||||
if (stream_get_left(s) < 4)
|
||||
return 0;
|
||||
stream_read_uint32(s, *val);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, uint32 length)
|
||||
{
|
||||
uint16 Version;
|
||||
|
||||
if (length < 3)
|
||||
return;
|
||||
stream_seek_uint8(channel->receive_data); /* Pad (1 byte) */
|
||||
stream_read_uint16(channel->receive_data, Version);
|
||||
|
||||
DEBUG_DVC("Version: %d", Version);
|
||||
|
||||
channel->vcm->drdynvc_state = DRDYNVC_STATE_READY;
|
||||
}
|
||||
|
||||
static void wts_read_drdynvc_create_response(rdpPeerChannel* channel, STREAM* s, uint32 length)
|
||||
{
|
||||
uint32 CreationStatus;
|
||||
|
||||
if (length < 4)
|
||||
return;
|
||||
stream_read_uint32(s, CreationStatus);
|
||||
if ((sint32)CreationStatus < 0)
|
||||
{
|
||||
DEBUG_DVC("ChannelId %d creation failed (%d)", channel->channel_id, (sint32)CreationStatus);
|
||||
channel->dvc_open_state = DVC_OPEN_STATE_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_DVC("ChannelId %d creation succeeded", channel->channel_id);
|
||||
channel->dvc_open_state = DVC_OPEN_STATE_SUCCEEDED;
|
||||
}
|
||||
wait_obj_set(channel->receive_event);
|
||||
}
|
||||
|
||||
static void wts_read_drdynvc_data_first(rdpPeerChannel* channel, STREAM* s, int cbLen, uint32 length)
|
||||
{
|
||||
int value;
|
||||
|
||||
value = wts_read_variable_uint(s, cbLen, &channel->dvc_total_length);
|
||||
if (value == 0)
|
||||
return;
|
||||
length -= value;
|
||||
if (length > channel->dvc_total_length)
|
||||
return;
|
||||
|
||||
stream_set_pos(channel->receive_data, 0);
|
||||
stream_check_size(channel->receive_data, channel->dvc_total_length);
|
||||
stream_write(channel->receive_data, stream_get_tail(s), length);
|
||||
}
|
||||
|
||||
static void wts_read_drdynvc_data(rdpPeerChannel* channel, STREAM* s, uint32 length)
|
||||
{
|
||||
if (channel->dvc_total_length > 0)
|
||||
{
|
||||
if (stream_get_length(channel->receive_data) + length > channel->dvc_total_length)
|
||||
{
|
||||
channel->dvc_total_length = 0;
|
||||
printf("wts_read_drdynvc_data: incorrect fragment data, discarded.\n");
|
||||
return;
|
||||
}
|
||||
stream_write(channel->receive_data, stream_get_tail(s), length);
|
||||
if (stream_get_length(channel->receive_data) >= channel->dvc_total_length)
|
||||
{
|
||||
wts_queue_receive_data(channel, stream_get_head(channel->receive_data), channel->dvc_total_length);
|
||||
channel->dvc_total_length = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wts_queue_receive_data(channel, stream_get_tail(s), length);
|
||||
}
|
||||
}
|
||||
|
||||
static void wts_read_drdynvc_close_response(rdpPeerChannel* channel)
|
||||
{
|
||||
DEBUG_DVC("ChannelId %d close response", channel->channel_id);
|
||||
channel->dvc_open_state = DVC_OPEN_STATE_CLOSED;
|
||||
}
|
||||
|
||||
static void wts_read_drdynvc_pdu(rdpPeerChannel* channel)
|
||||
{
|
||||
uint32 length;
|
||||
int value;
|
||||
int Cmd;
|
||||
int Sp;
|
||||
int cbChId;
|
||||
uint32 ChannelId;
|
||||
rdpPeerChannel* dvc;
|
||||
|
||||
length = stream_get_pos(channel->receive_data);
|
||||
if (length < 1)
|
||||
return;
|
||||
stream_set_pos(channel->receive_data, 0);
|
||||
stream_read_uint8(channel->receive_data, value);
|
||||
length--;
|
||||
Cmd = (value & 0xf0) >> 4;
|
||||
Sp = (value & 0x0c) >> 2;
|
||||
cbChId = (value & 0x03) >> 0;
|
||||
|
||||
if (Cmd == CAPABILITY_REQUEST_PDU)
|
||||
{
|
||||
wts_read_drdynvc_capabilities_response(channel, length);
|
||||
}
|
||||
else if (channel->vcm->drdynvc_state == DRDYNVC_STATE_READY)
|
||||
{
|
||||
value = wts_read_variable_uint(channel->receive_data, cbChId, &ChannelId);
|
||||
if (value == 0)
|
||||
return;
|
||||
length -= value;
|
||||
|
||||
DEBUG_DVC("Cmd %d ChannelId %d length %d", Cmd, ChannelId, length);
|
||||
dvc = wts_get_dvc_channel_by_id(channel->vcm, ChannelId);
|
||||
if (dvc)
|
||||
{
|
||||
switch (Cmd)
|
||||
{
|
||||
case CREATE_REQUEST_PDU:
|
||||
wts_read_drdynvc_create_response(dvc, channel->receive_data, length);
|
||||
break;
|
||||
|
||||
case DATA_FIRST_PDU:
|
||||
wts_read_drdynvc_data_first(dvc, channel->receive_data, Sp, length);
|
||||
break;
|
||||
|
||||
case DATA_PDU:
|
||||
wts_read_drdynvc_data(dvc, channel->receive_data, length);
|
||||
break;
|
||||
|
||||
case CLOSE_REQUEST_PDU:
|
||||
wts_read_drdynvc_close_response(dvc);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("wts_read_drdynvc_pdu: Cmd %d not recognized.\n", Cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_DVC("ChannelId %d not exists.", ChannelId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("wts_read_drdynvc_pdu: received Cmd %d but channel is not ready.\n", Cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static int wts_write_variable_uint(STREAM* stream, uint32 val)
|
||||
{
|
||||
int cb;
|
||||
|
||||
if (val <= 0xFF)
|
||||
{
|
||||
cb = 0;
|
||||
stream_write_uint8(stream, val);
|
||||
}
|
||||
else if (val <= 0xFFFF)
|
||||
{
|
||||
cb = 1;
|
||||
stream_write_uint16(stream, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
cb = 3;
|
||||
stream_write_uint32(stream, val);
|
||||
}
|
||||
return cb;
|
||||
}
|
||||
|
||||
static void wts_write_drdynvc_header(STREAM *s, uint8 Cmd, uint32 ChannelId)
|
||||
{
|
||||
uint8* bm;
|
||||
int cbChId;
|
||||
|
||||
stream_get_mark(s, bm);
|
||||
stream_seek_uint8(s);
|
||||
cbChId = wts_write_variable_uint(s, ChannelId);
|
||||
*bm = ((Cmd & 0x0F) << 4) | cbChId;
|
||||
}
|
||||
|
||||
static void wts_write_drdynvc_create_request(STREAM *s, uint32 ChannelId, const char *ChannelName)
|
||||
{
|
||||
uint32 len;
|
||||
|
||||
wts_write_drdynvc_header(s, CREATE_REQUEST_PDU, ChannelId);
|
||||
len = strlen(ChannelName) + 1;
|
||||
stream_check_size(s, len);
|
||||
stream_write(s, ChannelName, len);
|
||||
}
|
||||
|
||||
static void WTSProcessChannelData(rdpPeerChannel* channel, int channelId, uint8* data, int size, int flags, int total_size)
|
||||
{
|
||||
if (flags & CHANNEL_FLAG_FIRST)
|
||||
{
|
||||
stream_set_pos(channel->receive_data, 0);
|
||||
@ -57,22 +320,13 @@ static void WTSProcessChannelData(rdpPeerChannel* channel, int channelId, uint8*
|
||||
{
|
||||
printf("WTSProcessChannelData: read error\n");
|
||||
}
|
||||
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_DVC)
|
||||
if (channel == channel->vcm->drdynvc_channel)
|
||||
{
|
||||
/* TODO: Receive DVC channel data */
|
||||
wts_read_drdynvc_pdu(channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
item = xnew(wts_data_item);
|
||||
item->length = stream_get_length(channel->receive_data);
|
||||
item->buffer = xmalloc(item->length);
|
||||
memcpy(item->buffer, stream_get_head(channel->receive_data), item->length);
|
||||
|
||||
freerdp_mutex_lock(channel->mutex);
|
||||
list_enqueue(channel->receive_queue, item);
|
||||
freerdp_mutex_unlock(channel->mutex);
|
||||
|
||||
wait_obj_set(channel->receive_event);
|
||||
wts_queue_receive_data(channel, stream_get_head(channel->receive_data), stream_get_length(channel->receive_data));
|
||||
}
|
||||
stream_set_pos(channel->receive_data, 0);
|
||||
}
|
||||
@ -113,6 +367,8 @@ WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client)
|
||||
vcm->send_event = wait_obj_new();
|
||||
vcm->send_queue = list_new();
|
||||
vcm->mutex = freerdp_mutex_new();
|
||||
vcm->dvc_channel_id_seq = 1;
|
||||
vcm->dvc_channel_list = list_new();
|
||||
|
||||
client->ReceiveChannelData = WTSReceiveChannelData;
|
||||
}
|
||||
@ -123,9 +379,15 @@ WTSVirtualChannelManager* WTSCreateVirtualChannelManager(freerdp_peer* client)
|
||||
void WTSDestroyVirtualChannelManager(WTSVirtualChannelManager* vcm)
|
||||
{
|
||||
wts_data_item* item;
|
||||
rdpPeerChannel* channel;
|
||||
|
||||
if (vcm != NULL)
|
||||
{
|
||||
while ((channel = (rdpPeerChannel*) list_dequeue(vcm->dvc_channel_list)) != NULL)
|
||||
{
|
||||
WTSVirtualChannelClose(channel);
|
||||
}
|
||||
list_free(vcm->dvc_channel_list);
|
||||
if (vcm->drdynvc_channel != NULL)
|
||||
{
|
||||
WTSVirtualChannelClose(vcm->drdynvc_channel);
|
||||
@ -147,12 +409,32 @@ void WTSVirtualChannelManagerGetFileDescriptor(WTSVirtualChannelManager* vcm,
|
||||
void** fds, int* fds_count)
|
||||
{
|
||||
wait_obj_get_fds(vcm->send_event, fds, fds_count);
|
||||
if (vcm->drdynvc_channel)
|
||||
{
|
||||
wait_obj_get_fds(vcm->drdynvc_channel->receive_event, fds, fds_count);
|
||||
}
|
||||
}
|
||||
|
||||
boolean WTSVirtualChannelManagerCheckFileDescriptor(WTSVirtualChannelManager* vcm)
|
||||
{
|
||||
boolean result = true;
|
||||
wts_data_item* item;
|
||||
rdpPeerChannel* channel;
|
||||
uint32 dynvc_caps;
|
||||
|
||||
if (vcm->drdynvc_state == DRDYNVC_STATE_NONE && vcm->client->activated)
|
||||
{
|
||||
/* Initialize drdynvc channel once and only once. */
|
||||
vcm->drdynvc_state = DRDYNVC_STATE_INITIALIZED;
|
||||
|
||||
channel = WTSVirtualChannelOpenEx(vcm, "drdynvc", 0);
|
||||
if (channel)
|
||||
{
|
||||
vcm->drdynvc_channel = channel;
|
||||
dynvc_caps = 0x00010050; /* DYNVC_CAPS_VERSION1 (4 bytes) */
|
||||
WTSVirtualChannelWrite(channel, (uint8*) &dynvc_caps, sizeof(dynvc_caps), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
wait_obj_clear(vcm->send_event);
|
||||
|
||||
@ -180,55 +462,71 @@ void* WTSVirtualChannelOpenEx(
|
||||
int i;
|
||||
int len;
|
||||
rdpPeerChannel* channel;
|
||||
const char* channel_name;
|
||||
freerdp_peer* client = vcm->client;
|
||||
STREAM* s;
|
||||
|
||||
channel_name = ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0 ? "drdynvc" : pVirtualName);
|
||||
|
||||
len = strlen(channel_name);
|
||||
if (len > 8)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < client->settings->num_channels; i++)
|
||||
if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0)
|
||||
{
|
||||
if (client->settings->channels[i].joined &&
|
||||
strncmp(client->settings->channels[i].name, channel_name, len) == 0)
|
||||
if (vcm->drdynvc_channel == NULL || vcm->drdynvc_state != DRDYNVC_STATE_READY)
|
||||
{
|
||||
break;
|
||||
DEBUG_DVC("Dynamic virtual channel not ready.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (i >= client->settings->num_channels)
|
||||
return NULL;
|
||||
|
||||
channel = (rdpPeerChannel*) client->settings->channels[i].handle;
|
||||
if (channel == NULL)
|
||||
{
|
||||
channel = xnew(rdpPeerChannel);
|
||||
channel->vcm = vcm;
|
||||
channel->client = client;
|
||||
channel->channel_id = client->settings->channels[i].channel_id;
|
||||
channel->index = i;
|
||||
channel->channel_type = RDP_PEER_CHANNEL_TYPE_DVC;
|
||||
channel->receive_data = stream_new(client->settings->vc_chunk_size);
|
||||
if ((flags & WTS_CHANNEL_OPTION_DYNAMIC) != 0)
|
||||
channel->receive_event = wait_obj_new();
|
||||
channel->receive_queue = list_new();
|
||||
channel->mutex = freerdp_mutex_new();
|
||||
|
||||
freerdp_mutex_lock(vcm->mutex);
|
||||
channel->channel_id = vcm->dvc_channel_id_seq++;
|
||||
list_enqueue(vcm->dvc_channel_list, channel);
|
||||
freerdp_mutex_unlock(vcm->mutex);
|
||||
|
||||
s = stream_new(64);
|
||||
wts_write_drdynvc_create_request(s, channel->channel_id, pVirtualName);
|
||||
WTSVirtualChannelWrite(vcm->drdynvc_channel, stream_get_head(s), stream_get_length(s), NULL);
|
||||
stream_free(s);
|
||||
|
||||
DEBUG_DVC("ChannelId %d.%s (total %d)", channel->channel_id, pVirtualName, list_size(vcm->dvc_channel_list));
|
||||
}
|
||||
else
|
||||
{
|
||||
len = strlen(pVirtualName);
|
||||
if (len > 8)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < client->settings->num_channels; i++)
|
||||
{
|
||||
channel->channel_type = RDP_PEER_CHANNEL_TYPE_DVC;
|
||||
vcm->drdynvc_channel = channel;
|
||||
if (client->settings->channels[i].joined &&
|
||||
strncmp(client->settings->channels[i].name, pVirtualName, len) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (i >= client->settings->num_channels)
|
||||
return NULL;
|
||||
|
||||
channel = (rdpPeerChannel*) client->settings->channels[i].handle;
|
||||
if (channel == NULL)
|
||||
{
|
||||
channel = xnew(rdpPeerChannel);
|
||||
channel->vcm = vcm;
|
||||
channel->client = client;
|
||||
channel->channel_id = client->settings->channels[i].channel_id;
|
||||
channel->index = i;
|
||||
channel->channel_type = RDP_PEER_CHANNEL_TYPE_SVC;
|
||||
channel->receive_data = stream_new(client->settings->vc_chunk_size);
|
||||
channel->receive_event = wait_obj_new();
|
||||
channel->receive_queue = list_new();
|
||||
channel->mutex = freerdp_mutex_new();
|
||||
}
|
||||
|
||||
client->settings->channels[i].handle = channel;
|
||||
}
|
||||
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_DVC)
|
||||
{
|
||||
/* TODO: do DVC channel initialization here using pVirtualName */
|
||||
/* A sub-channel should be created and returned, instead of using the main drdynvc channel */
|
||||
/* Set channel->index to num_channels */
|
||||
client->settings->channels[i].handle = channel;
|
||||
}
|
||||
}
|
||||
|
||||
return channel;
|
||||
@ -240,6 +538,7 @@ boolean WTSVirtualChannelQuery(
|
||||
/* __out */ void** ppBuffer,
|
||||
/* __out */ uint32* pBytesReturned)
|
||||
{
|
||||
boolean bval;
|
||||
void* fds[10];
|
||||
int fds_count = 0;
|
||||
boolean result = false;
|
||||
@ -255,6 +554,35 @@ boolean WTSVirtualChannelQuery(
|
||||
result = true;
|
||||
break;
|
||||
|
||||
case WTSVirtualChannelReady:
|
||||
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
|
||||
{
|
||||
bval = true;
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (channel->dvc_open_state)
|
||||
{
|
||||
case DVC_OPEN_STATE_NONE:
|
||||
bval = false;
|
||||
result = true;
|
||||
break;
|
||||
case DVC_OPEN_STATE_SUCCEEDED:
|
||||
bval = true;
|
||||
result = true;
|
||||
break;
|
||||
default:
|
||||
bval = false;
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*ppBuffer = xmalloc(sizeof(boolean));
|
||||
memcpy(*ppBuffer, &bval, sizeof(boolean));
|
||||
*pBytesReturned = sizeof(boolean);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -307,55 +635,107 @@ boolean WTSVirtualChannelWrite(
|
||||
/* __in */ uint32 Length,
|
||||
/* __out */ uint32* pBytesWritten)
|
||||
{
|
||||
uint32 written = 0;
|
||||
wts_data_item* item;
|
||||
boolean result = false;
|
||||
rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
|
||||
WTSVirtualChannelManager* vcm ;
|
||||
wts_data_item* item;
|
||||
STREAM* s;
|
||||
int cbLen;
|
||||
int cbChId;
|
||||
int first;
|
||||
uint32 written;
|
||||
|
||||
if (channel == NULL)
|
||||
return false;
|
||||
|
||||
vcm = channel->vcm ;
|
||||
|
||||
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
|
||||
{
|
||||
item = xnew(wts_data_item);
|
||||
item->channel_id = channel->channel_id;
|
||||
item->buffer = xmalloc(Length);
|
||||
item->length = Length;
|
||||
memcpy(item->buffer, Buffer, Length);
|
||||
|
||||
freerdp_mutex_lock(vcm->mutex);
|
||||
list_enqueue(vcm->send_queue, item);
|
||||
freerdp_mutex_unlock(vcm->mutex);
|
||||
|
||||
wait_obj_set(vcm->send_event);
|
||||
|
||||
written = Length;
|
||||
result = true;
|
||||
wts_queue_send_item(channel, item);
|
||||
}
|
||||
else if (channel->vcm->drdynvc_channel == NULL || channel->vcm->drdynvc_state != DRDYNVC_STATE_READY)
|
||||
{
|
||||
DEBUG_DVC("drdynvc not ready");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Send to DVC channel */
|
||||
s = stream_new(0);
|
||||
first = true;
|
||||
|
||||
while (Length > 0)
|
||||
{
|
||||
item = xnew(wts_data_item);
|
||||
item->buffer = xmalloc(channel->client->settings->vc_chunk_size);
|
||||
stream_attach(s, item->buffer, channel->client->settings->vc_chunk_size);
|
||||
|
||||
stream_seek_uint8(s);
|
||||
cbChId = wts_write_variable_uint(s, channel->channel_id);
|
||||
if (first && Length > stream_get_left(s))
|
||||
{
|
||||
cbLen = wts_write_variable_uint(s, Length);
|
||||
item->buffer[0] = (DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->buffer[0] = (DATA_PDU << 4) | cbChId;
|
||||
}
|
||||
first = false;
|
||||
written = stream_get_left(s);
|
||||
if (written > Length)
|
||||
written = Length;
|
||||
stream_write(s, Buffer, written);
|
||||
item->length = stream_get_length(s);
|
||||
stream_detach(s);
|
||||
Length -= written;
|
||||
Buffer += written;
|
||||
|
||||
wts_queue_send_item(channel->vcm->drdynvc_channel, item);
|
||||
}
|
||||
|
||||
stream_free(s);
|
||||
}
|
||||
|
||||
if (pBytesWritten != NULL)
|
||||
*pBytesWritten = written;
|
||||
return result;
|
||||
*pBytesWritten = Length;
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean WTSVirtualChannelClose(
|
||||
/* __in */ void* hChannelHandle)
|
||||
{
|
||||
STREAM* s;
|
||||
wts_data_item* item;
|
||||
WTSVirtualChannelManager* vcm;
|
||||
rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;
|
||||
|
||||
if (channel != NULL)
|
||||
if (channel)
|
||||
{
|
||||
if (channel->index < channel->client->settings->num_channels)
|
||||
channel->client->settings->channels[channel->index].handle = NULL;
|
||||
stream_free(channel->receive_data);
|
||||
vcm = channel->vcm;
|
||||
|
||||
if (channel->channel_type == RDP_PEER_CHANNEL_TYPE_SVC)
|
||||
{
|
||||
if (channel->index < channel->client->settings->num_channels)
|
||||
channel->client->settings->channels[channel->index].handle = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
freerdp_mutex_lock(vcm->mutex);
|
||||
list_remove(vcm->dvc_channel_list, channel);
|
||||
freerdp_mutex_unlock(vcm->mutex);
|
||||
|
||||
if (channel->dvc_open_state == DVC_OPEN_STATE_SUCCEEDED)
|
||||
{
|
||||
s = stream_new(8);
|
||||
wts_write_drdynvc_header(s, CLOSE_REQUEST_PDU, channel->channel_id);
|
||||
WTSVirtualChannelWrite(vcm->drdynvc_channel, stream_get_head(s), stream_get_length(s), NULL);
|
||||
stream_free(s);
|
||||
}
|
||||
}
|
||||
if (channel->receive_data)
|
||||
stream_free(channel->receive_data);
|
||||
if (channel->receive_event)
|
||||
wait_obj_free(channel->receive_event);
|
||||
if (channel->receive_queue)
|
||||
@ -370,6 +750,5 @@ boolean WTSVirtualChannelClose(
|
||||
freerdp_mutex_free(channel->mutex);
|
||||
xfree(channel);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -24,21 +24,43 @@
|
||||
#include <freerdp/utils/stream.h>
|
||||
#include <freerdp/utils/list.h>
|
||||
#include <freerdp/utils/mutex.h>
|
||||
#include <freerdp/utils/debug.h>
|
||||
#include <freerdp/utils/wait_obj.h>
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
|
||||
#ifdef WITH_DEBUG_DVC
|
||||
#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
RDP_PEER_CHANNEL_TYPE_SVC = 0,
|
||||
RDP_PEER_CHANNEL_TYPE_DVC = 1,
|
||||
RDP_PEER_CHANNEL_TYPE_DVC_SUB = 2
|
||||
RDP_PEER_CHANNEL_TYPE_DVC = 1
|
||||
};
|
||||
|
||||
typedef struct rdp_peer_channel
|
||||
enum
|
||||
{
|
||||
DRDYNVC_STATE_NONE = 0,
|
||||
DRDYNVC_STATE_INITIALIZED = 1,
|
||||
DRDYNVC_STATE_READY = 2
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DVC_OPEN_STATE_NONE = 0,
|
||||
DVC_OPEN_STATE_SUCCEEDED = 1,
|
||||
DVC_OPEN_STATE_FAILED = 2,
|
||||
DVC_OPEN_STATE_CLOSED = 3
|
||||
};
|
||||
|
||||
typedef struct rdp_peer_channel rdpPeerChannel;
|
||||
struct rdp_peer_channel
|
||||
{
|
||||
WTSVirtualChannelManager* vcm;
|
||||
freerdp_peer* client;
|
||||
uint16 channel_id;
|
||||
uint32 channel_id;
|
||||
uint16 channel_type;
|
||||
uint16 index;
|
||||
|
||||
@ -46,7 +68,10 @@ typedef struct rdp_peer_channel
|
||||
struct wait_obj* receive_event;
|
||||
LIST* receive_queue;
|
||||
freerdp_mutex mutex;
|
||||
} rdpPeerChannel;
|
||||
|
||||
uint8 dvc_open_state;
|
||||
uint32 dvc_total_length;
|
||||
};
|
||||
|
||||
struct WTSVirtualChannelManager
|
||||
{
|
||||
@ -56,6 +81,9 @@ struct WTSVirtualChannelManager
|
||||
freerdp_mutex mutex;
|
||||
|
||||
rdpPeerChannel* drdynvc_channel;
|
||||
uint8 drdynvc_state;
|
||||
uint32 dvc_channel_id_seq;
|
||||
LIST* dvc_channel_list;
|
||||
};
|
||||
|
||||
#endif /* __WTSVC_H */
|
||||
|
@ -1445,5 +1445,10 @@ void mppc_dec_free(struct rdp_mppc_dec* dec)
|
||||
dec->history_buf = NULL;
|
||||
dec->history_ptr = NULL;
|
||||
}
|
||||
if (dec->offset_cache)
|
||||
{
|
||||
xfree(dec->offset_cache);
|
||||
dec->offset_cache = NULL;
|
||||
}
|
||||
xfree(dec);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
add_definitions(-DEXT_PATH="/usr/lib/freerdp/extensions")
|
||||
add_definitions(-DEXT_PATH="${FREERDP_EXTENSION_PATH}")
|
||||
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
@ -110,6 +110,10 @@ target_link_libraries(freerdp-core winpr-utils)
|
||||
target_link_libraries(freerdp-core winpr-rpc)
|
||||
target_link_libraries(freerdp-core winpr-sspi)
|
||||
|
||||
if(NOT WIN32)
|
||||
target_link_libraries(freerdp-core winpr-registry)
|
||||
endif()
|
||||
|
||||
target_link_libraries(freerdp-core freerdp-crypto)
|
||||
target_link_libraries(freerdp-core ${OPENSSL_LIBRARIES})
|
||||
|
||||
|
@ -1061,7 +1061,7 @@ void rdp_write_virtual_channel_capability_set(STREAM* s, rdpSettings* settings)
|
||||
|
||||
header = rdp_capability_set_start(s);
|
||||
|
||||
flags = (settings->server_mode) ? VCCAPS_COMPR_CS_8K : VCCAPS_NO_COMPR;
|
||||
flags = VCCAPS_NO_COMPR;
|
||||
|
||||
stream_write_uint32(s, flags); /* flags (4 bytes) */
|
||||
stream_write_uint32(s, settings->vc_chunk_size); /* VCChunkSize (4 bytes) */
|
||||
|
@ -573,6 +573,7 @@ boolean rdp_client_connect_finalize(rdpRdp* rdp)
|
||||
boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s)
|
||||
{
|
||||
boolean status;
|
||||
rdpSettings* settings = rdp->settings;
|
||||
|
||||
transport_set_blocking_mode(rdp->transport, true);
|
||||
|
||||
@ -581,38 +582,35 @@ boolean rdp_server_accept_nego(rdpRdp* rdp, STREAM* s)
|
||||
|
||||
rdp->nego->selected_protocol = 0;
|
||||
|
||||
printf("Requested protocols:");
|
||||
if ((rdp->nego->requested_protocols & PROTOCOL_TLS))
|
||||
printf("Client Security: NLA:%d TLS:%d RDP:%d\n",
|
||||
(rdp->nego->requested_protocols & PROTOCOL_NLA) ? 1 : 0,
|
||||
(rdp->nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0,
|
||||
(rdp->nego->requested_protocols == PROTOCOL_RDP) ? 1: 0);
|
||||
|
||||
printf("Server Security: NLA:%d TLS:%d RDP:%d\n",
|
||||
settings->nla_security, settings->tls_security, settings->rdp_security);
|
||||
|
||||
if ((settings->nla_security) && (rdp->nego->requested_protocols & PROTOCOL_NLA))
|
||||
{
|
||||
printf(" TLS");
|
||||
if (rdp->settings->tls_security)
|
||||
{
|
||||
printf("(Y)");
|
||||
rdp->nego->selected_protocol |= PROTOCOL_TLS;
|
||||
}
|
||||
else
|
||||
printf("(n)");
|
||||
rdp->nego->selected_protocol = PROTOCOL_NLA;
|
||||
}
|
||||
if ((rdp->nego->requested_protocols & PROTOCOL_NLA))
|
||||
else if ((settings->tls_security) && (rdp->nego->requested_protocols & PROTOCOL_TLS))
|
||||
{
|
||||
printf(" NLA");
|
||||
if (rdp->settings->nla_security)
|
||||
{
|
||||
printf("(Y)");
|
||||
rdp->nego->selected_protocol |= PROTOCOL_NLA;
|
||||
}
|
||||
else
|
||||
printf("(n)");
|
||||
rdp->nego->selected_protocol = PROTOCOL_TLS;
|
||||
}
|
||||
printf(" RDP");
|
||||
if (rdp->settings->rdp_security && rdp->nego->selected_protocol == 0)
|
||||
else if ((settings->rdp_security) && (rdp->nego->selected_protocol == PROTOCOL_RDP))
|
||||
{
|
||||
printf("(Y)");
|
||||
rdp->nego->selected_protocol = PROTOCOL_RDP;
|
||||
}
|
||||
else
|
||||
printf("(n)");
|
||||
printf("\n");
|
||||
{
|
||||
printf("Protocol security negotiation failure\n");
|
||||
}
|
||||
|
||||
printf("Negotiated Security: NLA:%d TLS:%d RDP:%d\n",
|
||||
(rdp->nego->selected_protocol & PROTOCOL_NLA) ? 1 : 0,
|
||||
(rdp->nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0,
|
||||
(rdp->nego->selected_protocol == PROTOCOL_RDP) ? 1: 0);
|
||||
|
||||
if (!nego_send_negotiation_response(rdp->nego))
|
||||
return false;
|
||||
|
@ -52,20 +52,26 @@ boolean freerdp_connect(freerdp* instance)
|
||||
|
||||
rdp = instance->context->rdp;
|
||||
|
||||
extension_pre_connect(rdp->extension);
|
||||
|
||||
IFCALLRET(instance->PreConnect, status, instance);
|
||||
|
||||
rdp->extension = extension_new(instance);
|
||||
extension_pre_connect(rdp->extension);
|
||||
|
||||
if (status != true)
|
||||
{
|
||||
if(!connectErrorCode){
|
||||
connectErrorCode = PREECONNECTERROR;
|
||||
}
|
||||
printf("freerdp_pre_connect failed\n");
|
||||
fprintf(stderr, "%s:%d: freerdp_pre_connect failed\n", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
status = rdp_client_connect(rdp);
|
||||
// --authonly tests the connection without a UI
|
||||
if (instance->settings->authentication_only) {
|
||||
fprintf(stderr, "%s:%d: Authentication only, exit status %d\n", __FILE__, __LINE__, !status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (status)
|
||||
{
|
||||
|
@ -543,7 +543,7 @@ boolean gcc_read_client_core_data(STREAM* s, rdpSettings* settings, uint16 block
|
||||
break;
|
||||
str = freerdp_uniconv_in(settings->uniconv, stream_get_tail(s), 64);
|
||||
stream_seek(s, 64);
|
||||
snprintf(settings->client_product_id, sizeof(settings->client_product_id), "%s", str);
|
||||
snprintf(settings->client_product_id, 32, "%s", str);
|
||||
xfree(str);
|
||||
blockLength -= 64;
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
||||
|
||||
static boolean freerdp_listener_open(freerdp_listener* instance, const char* bind_address, uint16 port)
|
||||
{
|
||||
rdpListener* listener = (rdpListener*)instance->listener;
|
||||
rdpListener* listener = (rdpListener*) instance->listener;
|
||||
int status;
|
||||
int sockfd;
|
||||
char servname[10];
|
||||
@ -56,14 +56,20 @@ static boolean freerdp_listener_open(freerdp_listener* instance, const char* bin
|
||||
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if (bind_address == NULL)
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
snprintf(servname, sizeof(servname), "%d", port);
|
||||
status = getaddrinfo(bind_address, servname, &hints, &res);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_tprintf(_T("getaddrinfo error: %s\n"), gai_strerror(status));
|
||||
#else
|
||||
perror("getaddrinfo");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -73,6 +79,7 @@ static boolean freerdp_listener_open(freerdp_listener* instance, const char* bin
|
||||
continue;
|
||||
|
||||
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
|
||||
if (sockfd == -1)
|
||||
{
|
||||
perror("socket");
|
||||
@ -92,14 +99,21 @@ static boolean freerdp_listener_open(freerdp_listener* instance, const char* bin
|
||||
#endif
|
||||
|
||||
status = bind(sockfd, ai->ai_addr, ai->ai_addrlen);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_tprintf(L"bind() failed with error: %u\n", WSAGetLastError());
|
||||
WSACleanup();
|
||||
#else
|
||||
perror("bind");
|
||||
close(sockfd);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
status = listen(sockfd, 10);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
perror("listen");
|
||||
@ -110,9 +124,9 @@ static boolean freerdp_listener_open(freerdp_listener* instance, const char* bin
|
||||
listener->sockfds[listener->num_sockfds++] = sockfd;
|
||||
|
||||
if (ai->ai_family == AF_INET)
|
||||
sin_addr = &(((struct sockaddr_in*)ai->ai_addr)->sin_addr);
|
||||
sin_addr = &(((struct sockaddr_in*) ai->ai_addr)->sin_addr);
|
||||
else
|
||||
sin_addr = &(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr);
|
||||
sin_addr = &(((struct sockaddr_in6*) ai->ai_addr)->sin6_addr);
|
||||
|
||||
printf("Listening on %s port %s.\n", inet_ntop(ai->ai_family, sin_addr, buf, sizeof(buf)), servname);
|
||||
}
|
||||
@ -125,12 +139,13 @@ static boolean freerdp_listener_open(freerdp_listener* instance, const char* bin
|
||||
static boolean freerdp_listener_open_local(freerdp_listener* instance, const char* path)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
rdpListener* listener = (rdpListener*)instance->listener;
|
||||
int status;
|
||||
int sockfd;
|
||||
struct sockaddr_un addr;
|
||||
rdpListener* listener = (rdpListener*) instance->listener;
|
||||
|
||||
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (sockfd == -1)
|
||||
{
|
||||
perror("socket");
|
||||
@ -142,7 +157,9 @@ static boolean freerdp_listener_open_local(freerdp_listener* instance, const cha
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, path, sizeof(addr.sun_path));
|
||||
unlink(path);
|
||||
status = bind(sockfd, (struct sockaddr *) &addr, sizeof(addr));
|
||||
|
||||
status = bind(sockfd, (struct sockaddr*) &addr, sizeof(addr));
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
perror("bind");
|
||||
@ -151,6 +168,7 @@ static boolean freerdp_listener_open_local(freerdp_listener* instance, const cha
|
||||
}
|
||||
|
||||
status = listen(sockfd, 10);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
perror("listen");
|
||||
@ -164,7 +182,7 @@ static boolean freerdp_listener_open_local(freerdp_listener* instance, const cha
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -172,19 +190,20 @@ static void freerdp_listener_close(freerdp_listener* instance)
|
||||
{
|
||||
int i;
|
||||
|
||||
rdpListener* listener = (rdpListener*)instance->listener;
|
||||
rdpListener* listener = (rdpListener*) instance->listener;
|
||||
|
||||
for (i = 0; i < listener->num_sockfds; i++)
|
||||
{
|
||||
close(listener->sockfds[i]);
|
||||
}
|
||||
|
||||
listener->num_sockfds = 0;
|
||||
}
|
||||
|
||||
static boolean freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount)
|
||||
{
|
||||
rdpListener* listener = (rdpListener*)instance->listener;
|
||||
int i;
|
||||
rdpListener* listener = (rdpListener*) instance->listener;
|
||||
|
||||
if (listener->num_sockfds < 1)
|
||||
return false;
|
||||
|
@ -297,15 +297,24 @@ boolean nego_recv(rdpTransport* transport, STREAM* s, void* extra)
|
||||
DEBUG_NEGO("selected_protocol: %d", nego->selected_protocol);
|
||||
|
||||
/* enhanced security selected ? */
|
||||
if (nego->selected_protocol) {
|
||||
if (nego->selected_protocol == PROTOCOL_NLA &&
|
||||
!nego->enabled_protocols[PROTOCOL_NLA])
|
||||
|
||||
if (nego->selected_protocol)
|
||||
{
|
||||
if ((nego->selected_protocol == PROTOCOL_NLA) &&
|
||||
(!nego->enabled_protocols[PROTOCOL_NLA]))
|
||||
{
|
||||
nego->state = NEGO_STATE_FAIL;
|
||||
if (nego->selected_protocol == PROTOCOL_TLS &&
|
||||
!nego->enabled_protocols[PROTOCOL_TLS])
|
||||
}
|
||||
if ((nego->selected_protocol == PROTOCOL_TLS) &&
|
||||
(!nego->enabled_protocols[PROTOCOL_TLS]))
|
||||
{
|
||||
nego->state = NEGO_STATE_FAIL;
|
||||
} else if (!nego->enabled_protocols[PROTOCOL_RDP])
|
||||
}
|
||||
}
|
||||
else if (!nego->enabled_protocols[PROTOCOL_RDP])
|
||||
{
|
||||
nego->state = NEGO_STATE_FAIL;
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_RDP_NEG_FAILURE:
|
||||
@ -316,6 +325,7 @@ boolean nego_recv(rdpTransport* transport, STREAM* s, void* extra)
|
||||
else
|
||||
{
|
||||
DEBUG_NEGO("no rdpNegData");
|
||||
|
||||
if (!nego->enabled_protocols[PROTOCOL_RDP])
|
||||
nego->state = NEGO_STATE_FAIL;
|
||||
else
|
||||
@ -368,6 +378,7 @@ boolean nego_read_request(rdpNego* nego, STREAM* s)
|
||||
/* rdpNegData (optional) */
|
||||
|
||||
stream_read_uint8(s, type); /* Type */
|
||||
|
||||
if (type != TYPE_RDP_NEG_REQ)
|
||||
{
|
||||
printf("Incorrect negotiation request type %d\n", type);
|
||||
@ -470,6 +481,8 @@ void nego_process_negotiation_request(rdpNego* nego, STREAM* s)
|
||||
stream_read_uint16(s, length);
|
||||
stream_read_uint32(s, nego->requested_protocols);
|
||||
|
||||
DEBUG_NEGO("requested_protocols: %d", nego->requested_protocols);
|
||||
|
||||
nego->state = NEGO_STATE_FINAL;
|
||||
}
|
||||
|
||||
@ -543,12 +556,13 @@ void nego_process_negotiation_failure(rdpNego* nego, STREAM* s)
|
||||
boolean nego_send_negotiation_response(rdpNego* nego)
|
||||
{
|
||||
STREAM* s;
|
||||
rdpSettings* settings;
|
||||
uint8* bm;
|
||||
uint8* em;
|
||||
int length;
|
||||
uint8 *bm, *em;
|
||||
boolean ret;
|
||||
boolean status;
|
||||
rdpSettings* settings;
|
||||
|
||||
ret = true;
|
||||
status = true;
|
||||
settings = nego->transport->settings;
|
||||
|
||||
s = transport_send_stream_init(nego->transport, 256);
|
||||
@ -577,7 +591,7 @@ boolean nego_send_negotiation_response(rdpNego* nego)
|
||||
printf("nego_send_negotiation_response: client supports only Standard RDP Security\n");
|
||||
stream_write_uint32(s, SSL_REQUIRED_BY_SERVER);
|
||||
length += 8;
|
||||
ret = false;
|
||||
status = false;
|
||||
}
|
||||
|
||||
stream_get_mark(s, em);
|
||||
@ -589,7 +603,7 @@ boolean nego_send_negotiation_response(rdpNego* nego)
|
||||
if (transport_write(nego->transport, s) < 0)
|
||||
return false;
|
||||
|
||||
if (ret)
|
||||
if (status)
|
||||
{
|
||||
/* update settings with negotiated protocol security */
|
||||
settings->requested_protocols = nego->requested_protocols;
|
||||
@ -600,12 +614,14 @@ boolean nego_send_negotiation_response(rdpNego* nego)
|
||||
settings->tls_security = false;
|
||||
settings->nla_security = false;
|
||||
settings->rdp_security = true;
|
||||
|
||||
if (!settings->local)
|
||||
{
|
||||
settings->encryption = true;
|
||||
settings->encryption_method = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
|
||||
settings->encryption_level = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
|
||||
}
|
||||
|
||||
if (settings->encryption && settings->server_key == NULL && settings->rdp_key_file == NULL)
|
||||
return false;
|
||||
}
|
||||
@ -629,7 +645,7 @@ boolean nego_send_negotiation_response(rdpNego* nego)
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,6 +116,8 @@ static boolean peer_recv_data_pdu(freerdp_peer* client, STREAM* s)
|
||||
return false;
|
||||
}
|
||||
|
||||
client->activated = true;
|
||||
|
||||
break;
|
||||
|
||||
case DATA_PDU_TYPE_SHUTDOWN_REQUEST:
|
||||
@ -392,6 +394,7 @@ void freerdp_peer_free(freerdp_peer* client)
|
||||
if (client)
|
||||
{
|
||||
rdp_free(client->context->rdp);
|
||||
xfree(client->context);
|
||||
xfree(client);
|
||||
}
|
||||
}
|
||||
|
@ -912,9 +912,10 @@ rdpRdp* rdp_new(freerdp* instance)
|
||||
{
|
||||
rdp->instance = instance;
|
||||
rdp->settings = settings_new((void*) instance);
|
||||
|
||||
if (instance != NULL)
|
||||
instance->settings = rdp->settings;
|
||||
rdp->extension = extension_new(instance);
|
||||
|
||||
rdp->transport = transport_new(rdp->settings);
|
||||
rdp->license = license_new(rdp);
|
||||
rdp->input = input_new(rdp);
|
||||
|
@ -38,7 +38,7 @@ boolean ntlm_client_init(rdpNtlm* ntlm, boolean confidentiality, char* user, cha
|
||||
|
||||
ntlm->confidentiality = confidentiality;
|
||||
|
||||
#ifdef NATIVE_SSPI
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
{
|
||||
HMODULE hSSPI;
|
||||
INIT_SECURITY_INTERFACE InitSecurityInterface;
|
||||
|
@ -29,8 +29,53 @@
|
||||
#include <freerdp/settings.h>
|
||||
#include <freerdp/utils/file.h>
|
||||
|
||||
#include <winpr/registry.h>
|
||||
|
||||
static const char client_dll[] = "C:\\Windows\\System32\\mstscax.dll";
|
||||
|
||||
void settings_load_hkey_local_machine(rdpSettings* settings)
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
DWORD dwValue;
|
||||
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Client"), 0, KEY_READ, &hKey);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("DesktopWidth"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
settings->width = dwValue;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("DesktopHeight"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
settings->height = dwValue;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("KeyboardType"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
settings->kbd_type = dwValue;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("KeyboardSubType"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
settings->kbd_subtype = dwValue;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("KeyboardFunctionKeys"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
settings->kbd_fn_keys = dwValue;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("KeyboardLayout"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
settings->kbd_layout = dwValue;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("NlaSecurity"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
settings->nla_security = dwValue ? 1 : 0;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("TlsSecurity"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
settings->tls_security = dwValue ? 1 : 0;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("RdpSecurity"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
settings->rdp_security = dwValue ? 1 : 0;
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
rdpSettings* settings_new(void* instance)
|
||||
{
|
||||
rdpSettings* settings;
|
||||
@ -73,6 +118,8 @@ rdpSettings* settings_new(void* instance)
|
||||
settings->encryption_level = ENCRYPTION_LEVEL_NONE;
|
||||
|
||||
settings->authentication = true;
|
||||
settings->authentication_only = false;
|
||||
settings->from_stdin = false;
|
||||
|
||||
settings->received_caps = xzalloc(32);
|
||||
settings->order_support = xzalloc(32);
|
||||
@ -186,6 +233,8 @@ rdpSettings* settings_new(void* instance)
|
||||
settings->server_certificate = xnew(rdpBlob);
|
||||
|
||||
freerdp_detect_paths(settings);
|
||||
|
||||
settings_load_hkey_local_machine(settings);
|
||||
}
|
||||
|
||||
return settings;
|
||||
|
@ -189,8 +189,14 @@ boolean tcp_set_blocking_mode(rdpTcp* tcp, boolean blocking)
|
||||
else
|
||||
fcntl(tcp->sockfd, F_SETFL, flags | O_NONBLOCK);
|
||||
#else
|
||||
int status;
|
||||
u_long arg = blocking;
|
||||
ioctlsocket(tcp->sockfd, FIONBIO, &arg);
|
||||
|
||||
status = ioctlsocket(tcp->sockfd, FIONBIO, &arg);
|
||||
|
||||
if (status != NO_ERROR)
|
||||
printf("ioctlsocket() failed with error: %ld\n", status);
|
||||
|
||||
tcp->wsa_event = WSACreateEvent();
|
||||
WSAEventSelect(tcp->sockfd, tcp->wsa_event, FD_READ);
|
||||
#endif
|
||||
|
@ -526,6 +526,7 @@ void transport_free(rdpTransport* transport)
|
||||
tls_free(transport->tls);
|
||||
|
||||
tcp_free(transport->tcp);
|
||||
tcp_free(transport->tcp_in);
|
||||
tsg_free(transport->tsg);
|
||||
|
||||
xfree(transport);
|
||||
|
@ -129,6 +129,68 @@ int certificate_data_match(rdpCertificateStore* certificate_store, rdpCertificat
|
||||
return match;
|
||||
}
|
||||
|
||||
void certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data)
|
||||
{
|
||||
FILE* fp;
|
||||
int length;
|
||||
char* data;
|
||||
char* pline;
|
||||
long int size;
|
||||
|
||||
fp = certificate_store->fp;
|
||||
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
// Read the current contents of the file.
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
if (size < 1)
|
||||
return;
|
||||
|
||||
data = (char*) xmalloc(size + 2);
|
||||
|
||||
if (fread(data, size, 1, fp) != 1)
|
||||
{
|
||||
xfree(data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Write the file back out, with appropriate fingerprint substitutions
|
||||
fp = fopen(certificate_store->file, "w+");
|
||||
data[size] = '\n';
|
||||
data[size + 1] = '\0';
|
||||
pline = strtok(data, "\n"); // xxx: use strsep
|
||||
|
||||
while (pline != NULL)
|
||||
{
|
||||
length = strlen(pline);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
char* hostname = pline, *fingerprint;
|
||||
|
||||
length = strcspn(pline, " \t");
|
||||
hostname[length] = '\0';
|
||||
|
||||
/* If this is the replaced hostname, use the updated fingerprint. */
|
||||
if (strcmp(hostname, certificate_data->hostname) == 0)
|
||||
fingerprint = certificate_data->fingerprint;
|
||||
else
|
||||
fingerprint = &hostname[length + 1];
|
||||
|
||||
fprintf(fp, "%s %s\n", hostname, fingerprint);
|
||||
}
|
||||
|
||||
pline = strtok(NULL, "\n");
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
xfree(data);
|
||||
}
|
||||
|
||||
void certificate_data_print(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data)
|
||||
{
|
||||
FILE* fp;
|
||||
|
@ -69,7 +69,8 @@ void crypto_rc4(CryptoRc4 rc4, uint32 length, const uint8* in_data, uint8* out_d
|
||||
|
||||
void crypto_rc4_free(CryptoRc4 rc4)
|
||||
{
|
||||
xfree(rc4);
|
||||
if (rc4)
|
||||
xfree(rc4);
|
||||
}
|
||||
|
||||
CryptoDes3 crypto_des3_encrypt_init(const uint8* key, const uint8* ivec)
|
||||
@ -315,7 +316,7 @@ char* crypto_cert_fingerprint(X509* xcert)
|
||||
for (i = 0; i < (int) (fp_len - 1); i++)
|
||||
{
|
||||
sprintf(p, "%02x:", fp[i]);
|
||||
p = &fp_buffer[i * 3];
|
||||
p = &fp_buffer[(i + 1) * 3];
|
||||
}
|
||||
sprintf(p, "%02x", fp[i]);
|
||||
|
||||
|
@ -19,6 +19,16 @@
|
||||
|
||||
#include <freerdp/crypto/der.h>
|
||||
|
||||
int _der_skip_length(int length)
|
||||
{
|
||||
if (length > 0x7F && length <= 0xFF)
|
||||
return 2;
|
||||
else if (length > 0xFF)
|
||||
return 3;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int der_write_length(STREAM* s, int length)
|
||||
{
|
||||
if (length > 0x7F && length <= 0xFF)
|
||||
@ -40,114 +50,52 @@ int der_write_length(STREAM* s, int length)
|
||||
}
|
||||
}
|
||||
|
||||
boolean der_write_general_string(STREAM* s, char* str)
|
||||
int der_get_content_length(int length)
|
||||
{
|
||||
STREAM* tmp_s;
|
||||
|
||||
tmp_s = stream_new(0);
|
||||
stream_attach(tmp_s, (uint8*)str, strlen(str));
|
||||
|
||||
der_write_universal_tag(s, ER_TAG_GENERAL_STRING, false);
|
||||
der_write_length(s, strlen(str));
|
||||
|
||||
stream_copy(s, tmp_s, strlen(str));
|
||||
stream_detach(tmp_s);
|
||||
stream_free(tmp_s) ;
|
||||
|
||||
return true;
|
||||
if (length > 0x7F && length <= 0xFF)
|
||||
return length - 3;
|
||||
else if (length > 0xFF)
|
||||
return length - 4;
|
||||
else
|
||||
return length - 2;
|
||||
}
|
||||
|
||||
char* der_read_general_string(STREAM* s, int *length)
|
||||
int der_skip_contextual_tag(int length)
|
||||
{
|
||||
char* str;
|
||||
int len;
|
||||
|
||||
if(der_read_universal_tag(s, ER_TAG_GENERAL_STRING, false))
|
||||
{
|
||||
der_read_length(s, &len);
|
||||
str = (char*)xzalloc((len + 1) * sizeof(char));
|
||||
memcpy(str, s->p, len);
|
||||
stream_seek(s, len);
|
||||
*length = len + 2;
|
||||
return str;
|
||||
}
|
||||
|
||||
stream_rewind(s, 1);
|
||||
*length = 0;
|
||||
|
||||
return NULL;
|
||||
return _der_skip_length(length) + 1;
|
||||
}
|
||||
|
||||
int der_write_principal_name(STREAM* s, uint8 ntype, char** name)
|
||||
int der_write_contextual_tag(STREAM* s, uint8 tag, int length, boolean pc)
|
||||
{
|
||||
uint8 len;
|
||||
char** p;
|
||||
|
||||
len = 0;
|
||||
p = name;
|
||||
|
||||
while (*p != NULL)
|
||||
{
|
||||
len += strlen(*p) + 2;
|
||||
p++;
|
||||
}
|
||||
|
||||
p = name;
|
||||
der_write_sequence_tag(s, len+9);
|
||||
der_write_contextual_tag(s, 0, 3, true);
|
||||
der_write_integer(s, ntype);
|
||||
der_write_contextual_tag(s, 1, len + 2, true);
|
||||
der_write_sequence_tag(s, len);
|
||||
|
||||
while (*p != NULL)
|
||||
{
|
||||
der_write_general_string(s, *p);
|
||||
p++;
|
||||
}
|
||||
|
||||
return len + 11;
|
||||
stream_write_uint8(s, (ER_CLASS_CTXT | ER_PC(pc)) | (ER_TAG_MASK & tag));
|
||||
return der_write_length(s, length) + 1;
|
||||
}
|
||||
|
||||
int der_write_generalized_time(STREAM* s, char* tstr)
|
||||
void der_write_universal_tag(STREAM* s, uint8 tag, boolean pc)
|
||||
{
|
||||
uint8 len;
|
||||
STREAM* tmp_s;
|
||||
|
||||
len = strlen(tstr);
|
||||
tmp_s = stream_new(0);
|
||||
|
||||
stream_attach(tmp_s, (uint8*) tstr, strlen(tstr));
|
||||
der_write_universal_tag(s, ER_TAG_GENERALIZED_TIME, false);
|
||||
der_write_length(s, len);
|
||||
|
||||
stream_copy(s, tmp_s, len);
|
||||
stream_detach(tmp_s);
|
||||
stream_free(tmp_s) ;
|
||||
|
||||
return len + 2;
|
||||
stream_write_uint8(s, (ER_CLASS_UNIV | ER_PC(pc)) | (ER_TAG_MASK & tag));
|
||||
}
|
||||
|
||||
boolean der_read_generalized_time(STREAM* s, char** tstr)
|
||||
int der_skip_octet_string(int length)
|
||||
{
|
||||
int length;
|
||||
uint8* bm;
|
||||
stream_get_mark(s, bm);
|
||||
|
||||
if (!der_read_universal_tag(s, ER_TAG_GENERALIZED_TIME, false))
|
||||
goto err;
|
||||
|
||||
der_read_length(s, &length);
|
||||
|
||||
if (length != 15)
|
||||
goto err;
|
||||
|
||||
*tstr = xzalloc(length + 1);
|
||||
stream_read(s, *tstr, length);
|
||||
|
||||
return true;
|
||||
|
||||
err:
|
||||
stream_set_mark(s, bm);
|
||||
return false;
|
||||
return 1 + _der_skip_length(length) + length;
|
||||
}
|
||||
|
||||
void der_write_octet_string(STREAM* s, uint8* oct_str, int length)
|
||||
{
|
||||
der_write_universal_tag(s, ER_TAG_OCTET_STRING, false);
|
||||
der_write_length(s, length);
|
||||
stream_write(s, oct_str, length);
|
||||
}
|
||||
|
||||
int der_skip_sequence_tag(int length)
|
||||
{
|
||||
return 1 + _der_skip_length(length);
|
||||
}
|
||||
|
||||
int der_write_sequence_tag(STREAM* s, int length)
|
||||
{
|
||||
stream_write_uint8(s, (ER_CLASS_UNIV | ER_CONSTRUCT) | (ER_TAG_MASK & ER_TAG_SEQUENCE));
|
||||
return der_write_length(s, length) + 1;
|
||||
}
|
||||
|
||||
|
@ -76,12 +76,20 @@
|
||||
#define WITH_DEBUG_CREDSSP
|
||||
#endif
|
||||
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
#define NLA_PKG_NAME NEGOSSP_NAME
|
||||
#else
|
||||
#define NLA_PKG_NAME NTLMSP_NAME
|
||||
#endif
|
||||
|
||||
#define TERMSRV_SPN_PREFIX "TERMSRV/"
|
||||
|
||||
void credssp_send(rdpCredssp* credssp);
|
||||
int credssp_recv(rdpCredssp* credssp);
|
||||
void credssp_buffer_print(rdpCredssp* credssp);
|
||||
void credssp_buffer_free(rdpCredssp* credssp);
|
||||
SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp);
|
||||
void credssp_encode_ts_credentials(rdpCredssp* credssp);
|
||||
SECURITY_STATUS credssp_encrypt_public_key_echo(rdpCredssp* credssp);
|
||||
SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp);
|
||||
SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp);
|
||||
SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp);
|
||||
|
||||
@ -92,8 +100,12 @@ SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp);
|
||||
|
||||
int credssp_ntlm_client_init(rdpCredssp* credssp)
|
||||
{
|
||||
char* spn;
|
||||
int length;
|
||||
freerdp* instance;
|
||||
rdpSettings* settings = credssp->settings;
|
||||
rdpSettings* settings;
|
||||
|
||||
settings = credssp->settings;
|
||||
instance = (freerdp*) settings->instance;
|
||||
|
||||
if ((settings->password == NULL) || (settings->username == NULL))
|
||||
@ -112,6 +124,20 @@ int credssp_ntlm_client_init(rdpCredssp* credssp)
|
||||
sspi_SecBufferAlloc(&credssp->PublicKey, credssp->tls->public_key.length);
|
||||
CopyMemory(credssp->PublicKey.pvBuffer, credssp->tls->public_key.data, credssp->tls->public_key.length);
|
||||
|
||||
length = sizeof(TERMSRV_SPN_PREFIX) + strlen(settings->hostname);
|
||||
|
||||
spn = (SEC_CHAR*) malloc(length + 1);
|
||||
sprintf(spn, "%s%s", TERMSRV_SPN_PREFIX, settings->hostname);
|
||||
|
||||
#ifdef UNICODE
|
||||
credssp->ServicePrincipalName = (LPTSTR) malloc(length * 2 + 2);
|
||||
MultiByteToWideChar(CP_ACP, 0, spn, length,
|
||||
(LPWSTR) credssp->ServicePrincipalName, length);
|
||||
free(spn);
|
||||
#else
|
||||
credssp->ServicePrincipalName = spn;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -126,8 +152,6 @@ int credssp_ntlm_server_init(rdpCredssp* credssp)
|
||||
rdpSettings* settings = credssp->settings;
|
||||
instance = (freerdp*) settings->instance;
|
||||
|
||||
sspi_SetAuthIdentity(&(credssp->identity), "username", NULL, NULL);
|
||||
|
||||
sspi_SecBufferAlloc(&credssp->PublicKey, credssp->tls->public_key.length);
|
||||
CopyMemory(credssp->PublicKey.pvBuffer, credssp->tls->public_key.data, credssp->tls->public_key.length);
|
||||
|
||||
@ -157,7 +181,7 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
if (credssp_ntlm_client_init(credssp) == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef NATIVE_SSPI
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
{
|
||||
HMODULE hSSPI;
|
||||
INIT_SECURITY_INTERFACE InitSecurityInterface;
|
||||
@ -176,7 +200,7 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
credssp->table = InitSecurityInterface();
|
||||
#endif
|
||||
|
||||
status = credssp->table->QuerySecurityPackageInfo(NTLMSP_NAME, &pPackageInfo);
|
||||
status = credssp->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
@ -186,7 +210,7 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
|
||||
cbMaxToken = pPackageInfo->cbMaxToken;
|
||||
|
||||
status = credssp->table->AcquireCredentialsHandle(NULL, NTLMSP_NAME,
|
||||
status = credssp->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME,
|
||||
SECPKG_CRED_OUTBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
@ -198,12 +222,19 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
have_context = false;
|
||||
have_input_buffer = false;
|
||||
have_pub_key_auth = false;
|
||||
memset(&input_buffer, 0, sizeof(SecBuffer));
|
||||
memset(&output_buffer, 0, sizeof(SecBuffer));
|
||||
memset(&credssp->ContextSizes, 0, sizeof(SecPkgContext_Sizes));
|
||||
ZeroMemory(&input_buffer, sizeof(SecBuffer));
|
||||
ZeroMemory(&output_buffer, sizeof(SecBuffer));
|
||||
ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes));
|
||||
|
||||
fContextReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
|
||||
ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE;
|
||||
/*
|
||||
* from tspkg.dll: 0x00000132
|
||||
* ISC_REQ_MUTUAL_AUTH
|
||||
* ISC_REQ_CONFIDENTIALITY
|
||||
* ISC_REQ_USE_SESSION_KEY
|
||||
* ISC_REQ_ALLOCATE_MEMORY
|
||||
*/
|
||||
|
||||
fContextReq = ISC_REQ_MUTUAL_AUTH | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -216,8 +247,8 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
|
||||
status = credssp->table->InitializeSecurityContext(&credentials,
|
||||
(have_context) ? &credssp->context : NULL,
|
||||
NULL, fContextReq, 0, SECURITY_NETWORK_DREP,
|
||||
(have_input_buffer) ? &input_buffer_desc : NULL,
|
||||
credssp->ServicePrincipalName, fContextReq, 0,
|
||||
SECURITY_NATIVE_DREP, (have_input_buffer) ? &input_buffer_desc : NULL,
|
||||
0, &credssp->context, &output_buffer_desc, &pfContextAttr, &expiration);
|
||||
|
||||
if (input_buffer.pvBuffer != NULL)
|
||||
@ -239,52 +270,7 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (have_pub_key_auth)
|
||||
{
|
||||
BYTE* p;
|
||||
SecBuffer Buffers[2];
|
||||
SecBufferDesc Message;
|
||||
SECURITY_STATUS encrypt_status;
|
||||
|
||||
Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
|
||||
Buffers[1].BufferType = SECBUFFER_DATA; /* TLS Public Key */
|
||||
|
||||
Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
|
||||
Buffers[0].pvBuffer = xzalloc(Buffers[0].cbBuffer);
|
||||
|
||||
Buffers[1].cbBuffer = credssp->PublicKey.cbBuffer;
|
||||
Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
|
||||
CopyMemory(Buffers[1].pvBuffer, credssp->PublicKey.pvBuffer, Buffers[1].cbBuffer);
|
||||
|
||||
Message.cBuffers = 2;
|
||||
Message.ulVersion = SECBUFFER_VERSION;
|
||||
Message.pBuffers = (PSecBuffer) &Buffers;
|
||||
|
||||
sspi_SecBufferAlloc(&credssp->pubKeyAuth, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
|
||||
|
||||
encrypt_status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, 0);
|
||||
|
||||
if (encrypt_status != SEC_E_OK)
|
||||
{
|
||||
printf("EncryptMessage status: 0x%08X\n", encrypt_status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_CREDSSP
|
||||
printf("CredSSP.Signature: (%d)\n", (int) Buffers[0].cbBuffer);
|
||||
winpr_HexDump((BYTE*) Buffers[0].pvBuffer, Buffers[0].cbBuffer);
|
||||
printf("CredSSP.PublicKey: (%d)\n", (int) credssp->PublicKey.cbBuffer);
|
||||
winpr_HexDump((BYTE*) credssp->PublicKey.pvBuffer, credssp->PublicKey.cbBuffer);
|
||||
printf("CredSSP.PublicKey (encrypted) (%d):\n", (int) Buffers[1].cbBuffer);
|
||||
winpr_HexDump((BYTE*) Buffers[1].pvBuffer, Buffers[1].cbBuffer);
|
||||
#endif
|
||||
|
||||
p = (BYTE*) credssp->pubKeyAuth.pvBuffer;
|
||||
CopyMemory(p, Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Message Signature */
|
||||
CopyMemory(&p[Buffers[0].cbBuffer], Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Encrypted Public Key */
|
||||
free(Buffers[0].pvBuffer);
|
||||
free(Buffers[1].pvBuffer);
|
||||
}
|
||||
credssp_encrypt_public_key_echo(credssp);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
status = SEC_E_OK;
|
||||
@ -324,7 +310,7 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
return -1;
|
||||
|
||||
#ifdef WITH_DEBUG_CREDSSP
|
||||
printf("Receiving Authentication Token\n");
|
||||
printf("Receiving Authentication Token (%d)\n", (int) credssp->negoToken.cbBuffer);
|
||||
winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
|
||||
#endif
|
||||
|
||||
@ -342,11 +328,14 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
|
||||
/* Verify Server Public Key Echo */
|
||||
|
||||
status = credssp_verify_public_key_echo(credssp);
|
||||
status = credssp_decrypt_public_key_echo(credssp);
|
||||
credssp_buffer_free(credssp);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
return 0;
|
||||
{
|
||||
printf("Could not verify public key echo!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Send encrypted credentials */
|
||||
|
||||
@ -398,7 +387,7 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
if (credssp_ntlm_server_init(credssp) == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef NATIVE_SSPI
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
{
|
||||
HMODULE hSSPI;
|
||||
INIT_SECURITY_INTERFACE InitSecurityInterface;
|
||||
@ -417,7 +406,7 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
credssp->table = InitSecurityInterface();
|
||||
#endif
|
||||
|
||||
status = credssp->table->QuerySecurityPackageInfo(NTLMSP_NAME, &pPackageInfo);
|
||||
status = credssp->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
@ -427,8 +416,8 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
|
||||
cbMaxToken = pPackageInfo->cbMaxToken;
|
||||
|
||||
status = credssp->table->AcquireCredentialsHandle(NULL, NTLMSP_NAME,
|
||||
SECPKG_CRED_INBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration);
|
||||
status = credssp->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME,
|
||||
SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &credentials, &expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
@ -439,12 +428,29 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
have_context = false;
|
||||
have_input_buffer = false;
|
||||
have_pub_key_auth = false;
|
||||
memset(&input_buffer, 0, sizeof(SecBuffer));
|
||||
memset(&output_buffer, 0, sizeof(SecBuffer));
|
||||
memset(&credssp->ContextSizes, 0, sizeof(SecPkgContext_Sizes));
|
||||
ZeroMemory(&input_buffer, sizeof(SecBuffer));
|
||||
ZeroMemory(&output_buffer, sizeof(SecBuffer));
|
||||
ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes));
|
||||
|
||||
fContextReq = ASC_REQ_REPLAY_DETECT | ASC_REQ_SEQUENCE_DETECT |
|
||||
ASC_REQ_CONFIDENTIALITY | ASC_REQ_DELEGATE;
|
||||
/*
|
||||
* from tspkg.dll: 0x00000112
|
||||
* ASC_REQ_MUTUAL_AUTH
|
||||
* ASC_REQ_CONFIDENTIALITY
|
||||
* ASC_REQ_ALLOCATE_MEMORY
|
||||
*/
|
||||
|
||||
fContextReq = 0;
|
||||
fContextReq |= ASC_REQ_MUTUAL_AUTH;
|
||||
fContextReq |= ASC_REQ_CONFIDENTIALITY;
|
||||
|
||||
fContextReq |= ASC_REQ_CONNECTION;
|
||||
fContextReq |= ASC_REQ_USE_SESSION_KEY;
|
||||
fContextReq |= ASC_REQ_CONFIDENTIALITY;
|
||||
|
||||
fContextReq |= ASC_REQ_REPLAY_DETECT;
|
||||
fContextReq |= ASC_REQ_SEQUENCE_DETECT;
|
||||
|
||||
fContextReq |= ASC_REQ_EXTENDED_ERROR;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -472,6 +478,12 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
p_buffer->pvBuffer = credssp->negoToken.pvBuffer;
|
||||
p_buffer->cbBuffer = credssp->negoToken.cbBuffer;
|
||||
|
||||
if (credssp->negoToken.cbBuffer < 1)
|
||||
{
|
||||
printf("CredSSP: invalid negoToken!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
output_buffer_desc.ulVersion = SECBUFFER_VERSION;
|
||||
output_buffer_desc.cBuffers = 1;
|
||||
output_buffer_desc.pBuffers = &output_buffer;
|
||||
@ -481,7 +493,7 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
|
||||
status = credssp->table->AcceptSecurityContext(&credentials,
|
||||
have_context? &credssp->context: NULL,
|
||||
&input_buffer_desc, fContextReq, SECURITY_NETWORK_DREP, &credssp->context,
|
||||
&input_buffer_desc, fContextReq, SECURITY_NATIVE_DREP, &credssp->context,
|
||||
&output_buffer_desc, &pfContextAttr, &expiration);
|
||||
|
||||
if (input_buffer.pvBuffer != NULL)
|
||||
@ -507,43 +519,17 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
credssp_verify_public_key_echo(credssp);
|
||||
if (credssp_decrypt_public_key_echo(credssp) != SEC_E_OK)
|
||||
{
|
||||
printf("Error: could not verify client's public key echo\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sspi_SecBufferFree(&credssp->negoToken);
|
||||
credssp->negoToken.pvBuffer = NULL;
|
||||
credssp->negoToken.cbBuffer = 0;
|
||||
|
||||
if (have_pub_key_auth)
|
||||
{
|
||||
BYTE* p;
|
||||
SecBuffer Buffers[2];
|
||||
SecBufferDesc Message;
|
||||
|
||||
Buffers[0].BufferType = SECBUFFER_DATA; /* TLS Public Key */
|
||||
Buffers[1].BufferType = SECBUFFER_TOKEN; /* Signature */
|
||||
|
||||
Buffers[0].cbBuffer = credssp->PublicKey.cbBuffer;
|
||||
Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer);
|
||||
CopyMemory(Buffers[0].pvBuffer, credssp->PublicKey.pvBuffer, Buffers[0].cbBuffer);
|
||||
|
||||
Buffers[1].cbBuffer = credssp->ContextSizes.cbMaxSignature;
|
||||
Buffers[1].pvBuffer = xzalloc(Buffers[1].cbBuffer);
|
||||
|
||||
Message.cBuffers = 2;
|
||||
Message.ulVersion = SECBUFFER_VERSION;
|
||||
Message.pBuffers = (PSecBuffer) &Buffers;
|
||||
|
||||
p = (BYTE*) Buffers[0].pvBuffer;
|
||||
p[0]++; /* Public Key +1 */
|
||||
|
||||
sspi_SecBufferAlloc(&credssp->pubKeyAuth, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
|
||||
|
||||
credssp->table->EncryptMessage(&credssp->context, 0, &Message, 0);
|
||||
|
||||
p = (BYTE*) credssp->pubKeyAuth.pvBuffer;
|
||||
CopyMemory(p, Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Message Signature */
|
||||
CopyMemory(&p[Buffers[1].cbBuffer], Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Encrypted Public Key */
|
||||
}
|
||||
credssp_encrypt_public_key_echo(credssp);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
status = SEC_E_OK;
|
||||
@ -551,6 +537,12 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
|
||||
{
|
||||
printf("AcceptSecurityContext status: 0x%08X\n", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* send authentication token */
|
||||
|
||||
#ifdef WITH_DEBUG_CREDSSP
|
||||
@ -617,38 +609,124 @@ int credssp_authenticate(rdpCredssp* credssp)
|
||||
return credssp_client_authenticate(credssp);
|
||||
}
|
||||
|
||||
SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp)
|
||||
void ap_integer_increment_le(BYTE* number, int size)
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < size; index++)
|
||||
{
|
||||
if (number[index] < 0xFF)
|
||||
{
|
||||
number[index]++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
number[index] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ap_integer_decrement_le(BYTE* number, int size)
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < size; index++)
|
||||
{
|
||||
if (number[index] > 0)
|
||||
{
|
||||
number[index]--;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
number[index] = 0xFF;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECURITY_STATUS credssp_encrypt_public_key_echo(rdpCredssp* credssp)
|
||||
{
|
||||
SecBuffer Buffers[2];
|
||||
SecBufferDesc Message;
|
||||
SECURITY_STATUS status;
|
||||
int public_key_length;
|
||||
|
||||
public_key_length = credssp->PublicKey.cbBuffer;
|
||||
|
||||
Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
|
||||
Buffers[1].BufferType = SECBUFFER_DATA; /* TLS Public Key */
|
||||
|
||||
sspi_SecBufferAlloc(&credssp->pubKeyAuth, credssp->ContextSizes.cbMaxSignature + public_key_length);
|
||||
|
||||
Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
|
||||
Buffers[0].pvBuffer = credssp->pubKeyAuth.pvBuffer;
|
||||
|
||||
Buffers[1].cbBuffer = public_key_length;
|
||||
Buffers[1].pvBuffer = ((BYTE*) credssp->pubKeyAuth.pvBuffer) + credssp->ContextSizes.cbMaxSignature;
|
||||
CopyMemory(Buffers[1].pvBuffer, credssp->PublicKey.pvBuffer, Buffers[1].cbBuffer);
|
||||
|
||||
if (credssp->server)
|
||||
{
|
||||
/* server echos the public key +1 */
|
||||
ap_integer_increment_le((BYTE*) Buffers[1].pvBuffer, Buffers[1].cbBuffer);
|
||||
}
|
||||
|
||||
Message.cBuffers = 2;
|
||||
Message.ulVersion = SECBUFFER_VERSION;
|
||||
Message.pBuffers = (PSecBuffer) &Buffers;
|
||||
|
||||
status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, credssp->send_seq_num++);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
printf("EncryptMessage status: 0x%08X\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp)
|
||||
{
|
||||
int length;
|
||||
BYTE* buffer;
|
||||
ULONG pfQOP;
|
||||
BYTE* public_key1;
|
||||
BYTE* public_key2;
|
||||
BYTE* pub_key_auth;
|
||||
int public_key_length;
|
||||
SecBuffer Buffers[2];
|
||||
SecBufferDesc Message;
|
||||
SECURITY_STATUS status;
|
||||
|
||||
if (credssp->PublicKey.cbBuffer + credssp->ContextSizes.cbMaxSignature != credssp->pubKeyAuth.cbBuffer)
|
||||
{
|
||||
printf("unexpected pubKeyAuth buffer size:%d\n", (int) credssp->pubKeyAuth.cbBuffer);
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
|
||||
length = credssp->pubKeyAuth.cbBuffer;
|
||||
pub_key_auth = (BYTE*) credssp->pubKeyAuth.pvBuffer;
|
||||
buffer = (BYTE*) malloc(length);
|
||||
CopyMemory(buffer, credssp->pubKeyAuth.pvBuffer, length);
|
||||
|
||||
public_key_length = credssp->PublicKey.cbBuffer;
|
||||
|
||||
Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
|
||||
Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */
|
||||
|
||||
Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
|
||||
Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer);
|
||||
CopyMemory(Buffers[0].pvBuffer, pub_key_auth, Buffers[0].cbBuffer);
|
||||
Buffers[0].pvBuffer = buffer;
|
||||
|
||||
Buffers[1].cbBuffer = length - Buffers[0].cbBuffer;
|
||||
Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
|
||||
CopyMemory(Buffers[1].pvBuffer, &pub_key_auth[Buffers[0].cbBuffer], Buffers[1].cbBuffer);
|
||||
Buffers[1].cbBuffer = length - credssp->ContextSizes.cbMaxSignature;
|
||||
Buffers[1].pvBuffer = buffer + credssp->ContextSizes.cbMaxSignature;
|
||||
|
||||
Message.cBuffers = 2;
|
||||
Message.ulVersion = SECBUFFER_VERSION;
|
||||
Message.pBuffers = (PSecBuffer) &Buffers;
|
||||
|
||||
status = credssp->table->DecryptMessage(&credssp->context, &Message, 0, &pfQOP);
|
||||
status = credssp->table->DecryptMessage(&credssp->context, &Message, credssp->recv_seq_num++, &pfQOP);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
@ -660,7 +738,10 @@ SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp)
|
||||
public_key2 = (BYTE*) Buffers[1].pvBuffer;
|
||||
|
||||
if (!credssp->server)
|
||||
public_key2[0]--; /* server echos the public key +1 */
|
||||
{
|
||||
/* server echos the public key +1 */
|
||||
ap_integer_decrement_le(public_key2, public_key_length);
|
||||
}
|
||||
|
||||
if (memcmp(public_key1, public_key2, public_key_length) != 0)
|
||||
{
|
||||
@ -675,10 +756,7 @@ SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp)
|
||||
return SEC_E_MESSAGE_ALTERED; /* DO NOT SEND CREDENTIALS! */
|
||||
}
|
||||
|
||||
public_key2[0]++;
|
||||
|
||||
free(Buffers[0].pvBuffer);
|
||||
free(Buffers[1].pvBuffer);
|
||||
free(buffer);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
@ -688,15 +766,15 @@ int credssp_skip_ts_password_creds(rdpCredssp* credssp)
|
||||
int length;
|
||||
int ts_password_creds_length = 0;
|
||||
|
||||
length = ber_skip_octet_string(credssp->identity.DomainLength);
|
||||
length = ber_skip_octet_string(credssp->identity.DomainLength * 2);
|
||||
length += ber_skip_contextual_tag(length);
|
||||
ts_password_creds_length += length;
|
||||
|
||||
length = ber_skip_octet_string(credssp->identity.UserLength);
|
||||
length = ber_skip_octet_string(credssp->identity.UserLength * 2);
|
||||
length += ber_skip_contextual_tag(length);
|
||||
ts_password_creds_length += length;
|
||||
|
||||
length = ber_skip_octet_string(credssp->identity.PasswordLength);
|
||||
length = ber_skip_octet_string(credssp->identity.PasswordLength * 2);
|
||||
length += ber_skip_contextual_tag(length);
|
||||
ts_password_creds_length += length;
|
||||
|
||||
@ -719,6 +797,7 @@ void credssp_read_ts_password_creds(rdpCredssp* credssp, STREAM* s)
|
||||
credssp->identity.Domain = (UINT16*) malloc(length);
|
||||
CopyMemory(credssp->identity.Domain, s->p, credssp->identity.DomainLength);
|
||||
stream_seek(s, credssp->identity.DomainLength);
|
||||
credssp->identity.DomainLength /= 2;
|
||||
|
||||
/* [1] userName (OCTET STRING) */
|
||||
ber_read_contextual_tag(s, 1, &length, true);
|
||||
@ -727,6 +806,7 @@ void credssp_read_ts_password_creds(rdpCredssp* credssp, STREAM* s)
|
||||
credssp->identity.User = (UINT16*) malloc(length);
|
||||
CopyMemory(credssp->identity.User, s->p, credssp->identity.UserLength);
|
||||
stream_seek(s, credssp->identity.UserLength);
|
||||
credssp->identity.UserLength /= 2;
|
||||
|
||||
/* [2] password (OCTET STRING) */
|
||||
ber_read_contextual_tag(s, 2, &length, true);
|
||||
@ -735,6 +815,7 @@ void credssp_read_ts_password_creds(rdpCredssp* credssp, STREAM* s)
|
||||
credssp->identity.Password = (UINT16*) malloc(length);
|
||||
CopyMemory(credssp->identity.Password, s->p, credssp->identity.PasswordLength);
|
||||
stream_seek(s, credssp->identity.PasswordLength);
|
||||
credssp->identity.PasswordLength /= 2;
|
||||
}
|
||||
|
||||
void credssp_write_ts_password_creds(rdpCredssp* credssp, STREAM* s)
|
||||
@ -748,16 +829,16 @@ void credssp_write_ts_password_creds(rdpCredssp* credssp, STREAM* s)
|
||||
ber_write_sequence_tag(s, length);
|
||||
|
||||
/* [0] domainName (OCTET STRING) */
|
||||
ber_write_contextual_tag(s, 0, credssp->identity.DomainLength + 2, true);
|
||||
ber_write_octet_string(s, (BYTE*) credssp->identity.Domain, credssp->identity.DomainLength);
|
||||
ber_write_contextual_tag(s, 0, credssp->identity.DomainLength * 2 + 2, true);
|
||||
ber_write_octet_string(s, (BYTE*) credssp->identity.Domain, credssp->identity.DomainLength * 2);
|
||||
|
||||
/* [1] userName (OCTET STRING) */
|
||||
ber_write_contextual_tag(s, 1, credssp->identity.UserLength + 2, true);
|
||||
ber_write_octet_string(s, (BYTE*) credssp->identity.User, credssp->identity.UserLength);
|
||||
ber_write_contextual_tag(s, 1, credssp->identity.UserLength * 2 + 2, true);
|
||||
ber_write_octet_string(s, (BYTE*) credssp->identity.User, credssp->identity.UserLength * 2);
|
||||
|
||||
/* [2] password (OCTET STRING) */
|
||||
ber_write_contextual_tag(s, 2, credssp->identity.PasswordLength + 2, true);
|
||||
ber_write_octet_string(s, (BYTE*) credssp->identity.Password, credssp->identity.PasswordLength);
|
||||
ber_write_contextual_tag(s, 2, credssp->identity.PasswordLength * 2 + 2, true);
|
||||
ber_write_octet_string(s, (BYTE*) credssp->identity.Password, credssp->identity.PasswordLength * 2);
|
||||
}
|
||||
|
||||
int credssp_skip_ts_credentials(rdpCredssp* credssp)
|
||||
@ -852,7 +933,6 @@ void credssp_encode_ts_credentials(rdpCredssp* credssp)
|
||||
|
||||
SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp)
|
||||
{
|
||||
BYTE* p;
|
||||
SecBuffer Buffers[2];
|
||||
SecBufferDesc Message;
|
||||
SECURITY_STATUS status;
|
||||
@ -862,37 +942,33 @@ SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp)
|
||||
Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
|
||||
Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
|
||||
|
||||
Buffers[0].cbBuffer = 16;
|
||||
Buffers[0].pvBuffer = xzalloc(Buffers[0].cbBuffer);
|
||||
sspi_SecBufferAlloc(&credssp->authInfo, credssp->ContextSizes.cbMaxSignature + credssp->ts_credentials.cbBuffer);
|
||||
|
||||
Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
|
||||
Buffers[0].pvBuffer = credssp->authInfo.pvBuffer;
|
||||
ZeroMemory(Buffers[0].pvBuffer, Buffers[0].cbBuffer);
|
||||
|
||||
Buffers[1].cbBuffer = credssp->ts_credentials.cbBuffer;
|
||||
Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
|
||||
Buffers[1].pvBuffer = &((BYTE*) credssp->authInfo.pvBuffer)[Buffers[0].cbBuffer];
|
||||
CopyMemory(Buffers[1].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[1].cbBuffer);
|
||||
|
||||
Message.cBuffers = 2;
|
||||
Message.ulVersion = SECBUFFER_VERSION;
|
||||
Message.pBuffers = (PSecBuffer) &Buffers;
|
||||
|
||||
sspi_SecBufferAlloc(&credssp->authInfo, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
|
||||
|
||||
status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, 1);
|
||||
status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, credssp->send_seq_num++);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
|
||||
p = (BYTE*) credssp->authInfo.pvBuffer;
|
||||
CopyMemory(p, Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Message Signature */
|
||||
CopyMemory(&p[Buffers[0].cbBuffer], Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Encrypted TSCredentials */
|
||||
|
||||
free(Buffers[0].pvBuffer);
|
||||
free(Buffers[1].pvBuffer);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp)
|
||||
{
|
||||
BYTE* p;
|
||||
int length;
|
||||
BYTE* buffer;
|
||||
ULONG pfQOP;
|
||||
SecBuffer Buffers[2];
|
||||
SecBufferDesc Message;
|
||||
SECURITY_STATUS status;
|
||||
@ -900,47 +976,51 @@ SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp)
|
||||
Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
|
||||
Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
|
||||
|
||||
Buffers[0].cbBuffer = 16;
|
||||
Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer);
|
||||
CopyMemory(Buffers[0].pvBuffer, credssp->authInfo.pvBuffer, Buffers[0].cbBuffer);
|
||||
if (credssp->authInfo.cbBuffer < 1)
|
||||
{
|
||||
printf("credssp_decrypt_ts_credentials missing authInfo buffer\n");
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
}
|
||||
|
||||
Buffers[1].cbBuffer = credssp->authInfo.cbBuffer - Buffers[0].cbBuffer;
|
||||
Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
|
||||
p = (BYTE*) credssp->authInfo.pvBuffer;
|
||||
CopyMemory(Buffers[1].pvBuffer, &p[Buffers[0].cbBuffer], Buffers[1].cbBuffer);
|
||||
length = credssp->authInfo.cbBuffer;
|
||||
buffer = (BYTE*) malloc(length);
|
||||
CopyMemory(buffer, credssp->authInfo.pvBuffer, length);
|
||||
|
||||
Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
|
||||
Buffers[0].pvBuffer = buffer;
|
||||
|
||||
Buffers[1].cbBuffer = length - credssp->ContextSizes.cbMaxSignature;
|
||||
Buffers[1].pvBuffer = &buffer[credssp->ContextSizes.cbMaxSignature];
|
||||
|
||||
Message.cBuffers = 2;
|
||||
Message.ulVersion = SECBUFFER_VERSION;
|
||||
Message.pBuffers = (PSecBuffer) &Buffers;
|
||||
|
||||
sspi_SecBufferAlloc(&credssp->authInfo, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
|
||||
|
||||
status = credssp->table->DecryptMessage(&credssp->context, &Message, 1, 0);
|
||||
status = credssp->table->DecryptMessage(&credssp->context, &Message, credssp->recv_seq_num++, &pfQOP);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
return status;
|
||||
|
||||
credssp_read_ts_credentials(credssp, &Buffers[1]);
|
||||
|
||||
free(Buffers[0].pvBuffer);
|
||||
free(Buffers[1].pvBuffer);
|
||||
free(buffer);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
int credssp_skip_nego_token(int length)
|
||||
{
|
||||
length = ber_skip_octet_string(length);
|
||||
length += ber_skip_contextual_tag(length);
|
||||
length = der_skip_octet_string(length);
|
||||
length += der_skip_contextual_tag(length);
|
||||
return length;
|
||||
}
|
||||
|
||||
int credssp_skip_nego_tokens(int length)
|
||||
{
|
||||
length = credssp_skip_nego_token(length);
|
||||
length += ber_skip_sequence_tag(length);
|
||||
length += ber_skip_sequence_tag(length);
|
||||
length += ber_skip_contextual_tag(length);
|
||||
length += der_skip_sequence_tag(length);
|
||||
length += der_skip_sequence_tag(length);
|
||||
length += der_skip_contextual_tag(length);
|
||||
return length;
|
||||
}
|
||||
|
||||
@ -962,7 +1042,7 @@ int credssp_skip_ts_request(int length)
|
||||
{
|
||||
length += ber_skip_integer(2);
|
||||
length += ber_skip_contextual_tag(3);
|
||||
length += ber_skip_sequence_tag(length);
|
||||
length += der_skip_sequence_tag(length);
|
||||
return length;
|
||||
}
|
||||
|
||||
@ -990,20 +1070,22 @@ void credssp_send(rdpCredssp* credssp)
|
||||
s = stream_new(ts_request_length);
|
||||
|
||||
/* TSRequest */
|
||||
length = ber_get_content_length(ts_request_length);
|
||||
ber_write_sequence_tag(s, length); /* SEQUENCE */
|
||||
ber_write_contextual_tag(s, 0, 3, true); /* [0] version */
|
||||
length = der_get_content_length(ts_request_length);
|
||||
der_write_sequence_tag(s, length); /* SEQUENCE */
|
||||
|
||||
/* [0] version */
|
||||
ber_write_contextual_tag(s, 0, 3, true);
|
||||
ber_write_integer(s, 2); /* INTEGER */
|
||||
|
||||
/* [1] negoTokens (NegoData) */
|
||||
if (nego_tokens_length > 0)
|
||||
{
|
||||
length = ber_get_content_length(nego_tokens_length);
|
||||
length -= ber_write_contextual_tag(s, 1, length, true); /* NegoData */
|
||||
length -= ber_write_sequence_tag(s, length); /* SEQUENCE OF NegoDataItem */
|
||||
length -= ber_write_sequence_tag(s, length); /* NegoDataItem */
|
||||
length -= ber_write_contextual_tag(s, 0, length, true); /* [0] negoToken */
|
||||
ber_write_octet_string(s, credssp->negoToken.pvBuffer, length); /* OCTET STRING */
|
||||
length = der_get_content_length(nego_tokens_length);
|
||||
length -= der_write_contextual_tag(s, 1, length, true); /* NegoData */
|
||||
length -= der_write_sequence_tag(s, length); /* SEQUENCE OF NegoDataItem */
|
||||
length -= der_write_sequence_tag(s, length); /* NegoDataItem */
|
||||
length -= der_write_contextual_tag(s, 0, length, true); /* [0] negoToken */
|
||||
der_write_octet_string(s, (uint8*) credssp->negoToken.pvBuffer, length); /* OCTET STRING */
|
||||
}
|
||||
|
||||
/* [2] authInfo (OCTET STRING) */
|
||||
@ -1022,6 +1104,9 @@ void credssp_send(rdpCredssp* credssp)
|
||||
ber_write_octet_string(s, credssp->pubKeyAuth.pvBuffer, length);
|
||||
}
|
||||
|
||||
//printf("Sending TSRequest: (%d)\n", stream_get_length(s));
|
||||
//freerdp_hexdump(s->data, stream_get_length(s));
|
||||
|
||||
tls_write(credssp->tls, s->data, stream_get_length(s));
|
||||
stream_free(s);
|
||||
}
|
||||
@ -1039,15 +1124,21 @@ int credssp_recv(rdpCredssp* credssp)
|
||||
int status;
|
||||
UINT32 version;
|
||||
|
||||
s = stream_new(2048);
|
||||
status = tls_read(credssp->tls, s->data, stream_get_left(s));
|
||||
s = stream_new(4096);
|
||||
|
||||
status = tls_read_all(credssp->tls, s->p, stream_get_left(s));
|
||||
s->size = status;
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
stream_free(s) ;
|
||||
printf("credssp_recv() error: %d\n", status);
|
||||
stream_free(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//printf("Receiving TSRequest: (%d)\n", s->size);
|
||||
//freerdp_hexdump(s->data, s->size);
|
||||
|
||||
/* TSRequest */
|
||||
ber_read_sequence_tag(s, &length);
|
||||
ber_read_contextual_tag(s, 0, &length, true);
|
||||
@ -1136,9 +1227,9 @@ rdpCredssp* credssp_new(freerdp* instance, rdpTls* tls, rdpSettings* settings)
|
||||
credssp->tls = tls;
|
||||
credssp->send_seq_num = 0;
|
||||
credssp->recv_seq_num = 0;
|
||||
memset(&credssp->negoToken, 0, sizeof(SecBuffer));
|
||||
memset(&credssp->pubKeyAuth, 0, sizeof(SecBuffer));
|
||||
memset(&credssp->authInfo, 0, sizeof(SecBuffer));
|
||||
ZeroMemory(&credssp->negoToken, sizeof(SecBuffer));
|
||||
ZeroMemory(&credssp->pubKeyAuth, sizeof(SecBuffer));
|
||||
ZeroMemory(&credssp->authInfo, sizeof(SecBuffer));
|
||||
}
|
||||
|
||||
return credssp;
|
||||
|
@ -53,10 +53,10 @@ static void tls_free_certificate(CryptoCert cert)
|
||||
xfree(cert);
|
||||
}
|
||||
|
||||
|
||||
boolean tls_connect(rdpTls* tls)
|
||||
{
|
||||
CryptoCert cert;
|
||||
long options = 0;
|
||||
int connection_status;
|
||||
|
||||
tls->ctx = SSL_CTX_new(TLSv1_client_method());
|
||||
@ -67,15 +67,36 @@ boolean tls_connect(rdpTls* tls)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is necessary, because the Microsoft TLS implementation is not perfect.
|
||||
* SSL_OP_ALL enables a couple of workarounds for buggy TLS implementations,
|
||||
* but the most important workaround being SSL_OP_TLS_BLOCK_PADDING_BUG.
|
||||
* As the size of the encrypted payload may give hints about its contents,
|
||||
* block padding is normally used, but the Microsoft TLS implementation
|
||||
* won't recognize it and will disconnect you after sending a TLS alert.
|
||||
/**
|
||||
* SSL_OP_NO_COMPRESSION:
|
||||
*
|
||||
* The Microsoft RDP server does not advertise support
|
||||
* for TLS compression, but alternative servers may support it.
|
||||
* This was observed between early versions of the FreeRDP server
|
||||
* and the FreeRDP client, and caused major performance issues,
|
||||
* which is why we're disabling it.
|
||||
*/
|
||||
SSL_CTX_set_options(tls->ctx, SSL_OP_ALL);
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
options |= SSL_OP_NO_COMPRESSION;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SSL_OP_TLS_BLOCK_PADDING_BUG:
|
||||
*
|
||||
* The Microsoft RDP server does *not* support TLS padding.
|
||||
* It absolutely needs to be disabled otherwise it won't work.
|
||||
*/
|
||||
options |= SSL_OP_TLS_BLOCK_PADDING_BUG;
|
||||
|
||||
/**
|
||||
* SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS:
|
||||
*
|
||||
* Just like TLS padding, the Microsoft RDP server does not
|
||||
* support empty fragments. This needs to be disabled.
|
||||
*/
|
||||
options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
|
||||
|
||||
SSL_CTX_set_options(tls->ctx, options);
|
||||
|
||||
tls->ssl = SSL_new(tls->ctx);
|
||||
|
||||
@ -116,7 +137,8 @@ boolean tls_connect(rdpTls* tls)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tls_verify_certificate(tls, cert, tls->settings->hostname)) {
|
||||
if (!tls_verify_certificate(tls, cert, tls->settings->hostname))
|
||||
{
|
||||
printf("tls_connect: certificate not trusted, aborting.\n");
|
||||
tls_disconnect(tls);
|
||||
tls_free_certificate(cert);
|
||||
@ -131,6 +153,7 @@ boolean tls_connect(rdpTls* tls)
|
||||
boolean tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file)
|
||||
{
|
||||
CryptoCert cert;
|
||||
long options = 0;
|
||||
int connection_status;
|
||||
|
||||
tls->ctx = SSL_CTX_new(SSLv23_server_method());
|
||||
@ -142,10 +165,43 @@ boolean tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_fi
|
||||
}
|
||||
|
||||
/*
|
||||
* SSL_OP_NO_SSLv2:
|
||||
*
|
||||
* We only want SSLv3 and TLSv1, so disable SSLv2.
|
||||
* SSLv3 is used by, eg. Microsoft RDC for Mac OS X.
|
||||
*/
|
||||
SSL_CTX_set_options(tls->ctx, SSL_OP_NO_SSLv2);
|
||||
options |= SSL_OP_NO_SSLv2;
|
||||
|
||||
/**
|
||||
* SSL_OP_NO_COMPRESSION:
|
||||
*
|
||||
* The Microsoft RDP server does not advertise support
|
||||
* for TLS compression, but alternative servers may support it.
|
||||
* This was observed between early versions of the FreeRDP server
|
||||
* and the FreeRDP client, and caused major performance issues,
|
||||
* which is why we're disabling it.
|
||||
*/
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
options |= SSL_OP_NO_COMPRESSION;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SSL_OP_TLS_BLOCK_PADDING_BUG:
|
||||
*
|
||||
* The Microsoft RDP server does *not* support TLS padding.
|
||||
* It absolutely needs to be disabled otherwise it won't work.
|
||||
*/
|
||||
options |= SSL_OP_TLS_BLOCK_PADDING_BUG;
|
||||
|
||||
/**
|
||||
* SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS:
|
||||
*
|
||||
* Just like TLS padding, the Microsoft RDP server does not
|
||||
* support empty fragments. This needs to be disabled.
|
||||
*/
|
||||
options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
|
||||
|
||||
SSL_CTX_set_options(tls->ctx, options);
|
||||
|
||||
if (SSL_CTX_use_RSAPrivateKey_file(tls->ctx, privatekey_file, SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
@ -182,18 +238,37 @@ boolean tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_fi
|
||||
return false;
|
||||
}
|
||||
|
||||
xfree(cert);
|
||||
|
||||
if (SSL_set_fd(tls->ssl, tls->sockfd) < 1)
|
||||
{
|
||||
printf("SSL_set_fd failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
connection_status = SSL_accept(tls->ssl);
|
||||
|
||||
if (connection_status <= 0)
|
||||
while (1)
|
||||
{
|
||||
if (tls_print_error("SSL_accept", tls->ssl, connection_status))
|
||||
return false;
|
||||
connection_status = SSL_accept(tls->ssl);
|
||||
|
||||
if (connection_status <= 0)
|
||||
{
|
||||
switch (SSL_get_error(tls->ssl, connection_status))
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
break;
|
||||
|
||||
default:
|
||||
if (tls_print_error("SSL_accept", tls->ssl, connection_status))
|
||||
return false;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("TLS connection accepted\n");
|
||||
@ -232,6 +307,19 @@ int tls_read(rdpTls* tls, uint8* data, int length)
|
||||
return status;
|
||||
}
|
||||
|
||||
int tls_read_all(rdpTls* tls, uint8* data, int length)
|
||||
{
|
||||
int status;
|
||||
|
||||
do
|
||||
{
|
||||
status = tls_read(tls, data, length);
|
||||
}
|
||||
while (status == 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int tls_write(rdpTls* tls, uint8* data, int length)
|
||||
{
|
||||
int status;
|
||||
@ -298,11 +386,11 @@ boolean tls_print_error(char* func, SSL* connection, int value)
|
||||
return true;
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
printf("SSL_ERROR_WANT_READ\n");
|
||||
printf("%s: SSL_ERROR_WANT_READ\n", func);
|
||||
return false;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
printf("SSL_ERROR_WANT_WRITE\n");
|
||||
printf("%s: SSL_ERROR_WANT_WRITE\n", func);
|
||||
return false;
|
||||
|
||||
case SSL_ERROR_SYSCALL:
|
||||
@ -385,7 +473,7 @@ boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname)
|
||||
if (common_name)
|
||||
{
|
||||
xfree(common_name);
|
||||
common_name=NULL ;
|
||||
common_name = NULL;
|
||||
}
|
||||
|
||||
verification_status = true; /* success! */
|
||||
@ -402,6 +490,7 @@ boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname)
|
||||
char* issuer;
|
||||
char* subject;
|
||||
char* fingerprint;
|
||||
freerdp* instance = (freerdp*) tls->settings->instance;
|
||||
boolean accept_certificate = false;
|
||||
|
||||
issuer = crypto_cert_issuer(cert->px509);
|
||||
@ -414,9 +503,6 @@ boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname)
|
||||
if (match == 1)
|
||||
{
|
||||
/* no entry was found in known_hosts file, prompt user for manual verification */
|
||||
|
||||
freerdp* instance = (freerdp*) tls->settings->instance;
|
||||
|
||||
if (!hostname_match)
|
||||
tls_print_certificate_name_mismatch_error(hostname, common_name, alt_names, alt_names_count);
|
||||
|
||||
@ -426,7 +512,7 @@ boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname)
|
||||
if (!accept_certificate)
|
||||
{
|
||||
/* user did not accept, abort and do not add entry in known_hosts file */
|
||||
verification_status = false; /* failure! */
|
||||
verification_status = false; /* failure! */
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -437,9 +523,23 @@ boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname)
|
||||
}
|
||||
else if (match == -1)
|
||||
{
|
||||
/* entry was found in known_hosts file, but fingerprint does not match */
|
||||
/* entry was found in known_hosts file, but fingerprint does not match. ask user to use it */
|
||||
tls_print_certificate_error(hostname, fingerprint);
|
||||
verification_status = false; /* failure! */
|
||||
|
||||
if (instance->VerifyChangedCertificate)
|
||||
accept_certificate = instance->VerifyChangedCertificate(instance, subject, issuer, fingerprint, "");
|
||||
|
||||
if (!accept_certificate)
|
||||
{
|
||||
/* user did not accept, abort and do not change known_hosts file */
|
||||
verification_status = false; /* failure! */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* user accepted new certificate, add replace fingerprint for this host in known_hosts file */
|
||||
certificate_data_replace(tls->certificate_store, certificate_data);
|
||||
verification_status = true; /* success! */
|
||||
}
|
||||
}
|
||||
else if (match == 0)
|
||||
{
|
||||
@ -451,20 +551,6 @@ boolean tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname)
|
||||
xfree(fingerprint);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
if (common_name)
|
||||
xfree(common_name);
|
||||
|
||||
if (alt_names)
|
||||
{
|
||||
for (index = 0; index < alt_names_count; index++)
|
||||
xfree(alt_names[index]);
|
||||
|
||||
xfree(alt_names);
|
||||
xfree(alt_names_lengths) ;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (certificate_data)
|
||||
{
|
||||
xfree(certificate_data->fingerprint);
|
||||
|
@ -27,6 +27,30 @@
|
||||
#include <freerdp/utils/memory.h>
|
||||
#include <freerdp/utils/args.h>
|
||||
|
||||
|
||||
void freerdp_parse_hostname(rdpSettings* settings, char* hostname) {
|
||||
char* p;
|
||||
if (hostname[0] == '[' && (p = strchr(hostname, ']'))
|
||||
&& (p[1] == 0 || (p[1] == ':' && !strchr(p + 2, ':')))) {
|
||||
/* Either "[...]" or "[...]:..." with at most one : after the brackets */
|
||||
settings->hostname = xstrdup(hostname + 1);
|
||||
if ((p = strchr((char*)settings->hostname, ']'))) {
|
||||
*p = 0;
|
||||
if (p[1] == ':')
|
||||
settings->port = atoi(p + 2);
|
||||
}
|
||||
} else {
|
||||
/* Port number is cut off and used if exactly one : in the string */
|
||||
settings->hostname = xstrdup(hostname);
|
||||
if ((p = strchr((char*)settings->hostname, ':')) && !strchr(p + 1, ':')) {
|
||||
*p = 0;
|
||||
settings->port = atoi(p + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parse command-line arguments and update rdpSettings members accordingly.
|
||||
* @param settings pointer to rdpSettings struct to be updated.
|
||||
@ -81,6 +105,8 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
|
||||
" --app: RemoteApp connection. This implies -g workarea\n"
|
||||
" --ext: load an extension\n"
|
||||
" --no-auth: disable authentication\n"
|
||||
" --authonly: authentication only, no UI\n"
|
||||
" --from-stdin: unspecified username, password, domain and hostname params are prompted\n"
|
||||
" --no-fastpath: disable fast-path\n"
|
||||
" --no-motion: don't send mouse motion events\n"
|
||||
" --gdi: graphics rendering (hw, sw)\n"
|
||||
@ -306,6 +332,14 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
|
||||
{
|
||||
settings->authentication = false;
|
||||
}
|
||||
else if (strcmp("--authonly", argv[index]) == 0)
|
||||
{
|
||||
settings->authentication_only = true;
|
||||
}
|
||||
else if (strcmp("--from-stdin", argv[index]) == 0)
|
||||
{
|
||||
settings->from_stdin = true;
|
||||
}
|
||||
else if (strcmp("--ignore-certificate", argv[index]) == 0)
|
||||
{
|
||||
settings->ignore_certificate = true;
|
||||
@ -671,28 +705,8 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
|
||||
}
|
||||
else if (argv[index][0] != '-')
|
||||
{
|
||||
if (argv[index][0] == '[' && (p = strchr(argv[index], ']'))
|
||||
&& (p[1] == 0 || (p[1] == ':' && !strchr(p + 2, ':'))))
|
||||
{
|
||||
/* Either "[...]" or "[...]:..." with at most one : after the brackets */
|
||||
settings->hostname = xstrdup(argv[index] + 1);
|
||||
if ((p = strchr((char*)settings->hostname, ']')))
|
||||
{
|
||||
*p = 0;
|
||||
if (p[1] == ':')
|
||||
settings->port = atoi(p + 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Port number is cut off and used if exactly one : in the string */
|
||||
settings->hostname = xstrdup(argv[index]);
|
||||
if ((p = strchr((char*)settings->hostname, ':')) && !strchr(p + 1, ':'))
|
||||
{
|
||||
*p = 0;
|
||||
settings->port = atoi(p + 1);
|
||||
}
|
||||
}
|
||||
freerdp_parse_hostname(settings, argv[index]);
|
||||
|
||||
/* server is the last argument for the current session. arguments
|
||||
followed will be parsed for the next session. */
|
||||
index++;
|
||||
@ -715,7 +729,8 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
|
||||
if (settings->disable_theming)
|
||||
settings->performance_flags |= PERF_DISABLE_THEMING;
|
||||
|
||||
return index;
|
||||
break; /* post process missing arguments */
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -733,6 +748,49 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
|
||||
}
|
||||
index++;
|
||||
}
|
||||
printf("missing server name\n");
|
||||
return FREERDP_ARGS_PARSE_FAILURE;
|
||||
|
||||
|
||||
/* --from-stdin will prompt for missing arguments only.
|
||||
You can prompt for username, password, domain and hostname to avoid disclosing
|
||||
these settings to ps. */
|
||||
|
||||
if (settings->from_stdin) {
|
||||
/* username */
|
||||
if (NULL == settings->username) {
|
||||
char input[512];
|
||||
printf("username: ");
|
||||
scanf("%511s", input);
|
||||
settings->username = xstrdup(input);
|
||||
}
|
||||
/* password */
|
||||
if (NULL == settings->password) {
|
||||
char input[512];
|
||||
printf("password: ");
|
||||
scanf("%511s", input);
|
||||
settings->password = xstrdup(input);
|
||||
}
|
||||
/* domain */
|
||||
if (NULL == settings->domain) {
|
||||
char input[512];
|
||||
printf("domain (control-D to skip): ");
|
||||
scanf("%511s", input);
|
||||
settings->domain = xstrdup(input);
|
||||
}
|
||||
/* hostname */
|
||||
if (NULL == settings->hostname) {
|
||||
char input[512];
|
||||
printf("hostname: ");
|
||||
scanf("%511s", input);
|
||||
freerdp_parse_hostname(settings, input);
|
||||
}
|
||||
}
|
||||
|
||||
/* Must have a hostname. Do you? */
|
||||
if (NULL == settings->hostname) {
|
||||
printf("missing server name\n");
|
||||
return FREERDP_ARGS_PARSE_FAILURE;
|
||||
} else {
|
||||
return index;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,6 +46,21 @@
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX_STATIC_PLUGINS 50
|
||||
|
||||
struct static_plugin
|
||||
{
|
||||
const char* name;
|
||||
const char* entry_name;
|
||||
void* entry_addr;
|
||||
};
|
||||
typedef struct static_plugin staticPlugin;
|
||||
|
||||
static staticPlugin g_static_plugins[MAX_STATIC_PLUGINS];
|
||||
static int g_static_plugins_count;
|
||||
|
||||
|
||||
/**
|
||||
* UNUSED
|
||||
* This function opens a handle on the specified library in order to load symbols from it.
|
||||
@ -185,6 +200,10 @@ void* freerdp_load_plugin(const char* name, const char* entry_name)
|
||||
void* entry;
|
||||
char* suffixed_name;
|
||||
|
||||
/* first attempt to load a static plugin */
|
||||
entry = freerdp_load_static_plugin(name, entry_name);
|
||||
if (entry != NULL) return entry;
|
||||
|
||||
suffixed_name = freerdp_append_shared_library_suffix((char*) name);
|
||||
|
||||
if (!freerdp_path_contains_separator(suffixed_name))
|
||||
@ -276,3 +295,58 @@ void* freerdp_load_channel_plugin(rdpSettings* settings, const char* name, const
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to register a static plugin so that it can be loaded later on using freerdp_load_plugin.
|
||||
*
|
||||
* @param name [IN] - name of the library to load
|
||||
* @param entry_name [IN] - name of the symbol to register for later loading
|
||||
* @param entry [IN] - function pointer to the entry function
|
||||
*
|
||||
* @return true on success, otherwise false.
|
||||
*/
|
||||
boolean freerdp_register_static_plugin(const char* name, const char* entry_name, void* entry_addr)
|
||||
{
|
||||
staticPlugin* plugin;
|
||||
|
||||
if (g_static_plugins_count >= MAX_STATIC_PLUGINS)
|
||||
{
|
||||
printf("freerdp_register_static_plugin: cannot register %s/%s", name, entry_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* add the static plugin to the vector */
|
||||
plugin = &g_static_plugins[g_static_plugins_count++];
|
||||
plugin->name = name;
|
||||
plugin->entry_name = entry_name;
|
||||
plugin->entry_addr = entry_addr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper function, used by freerdp_load_plugin to return a function pointer from the static plugin table
|
||||
*
|
||||
* @param name [IN] - name of the library to load
|
||||
* @param entry_name [IN] - name of the symbol to register for later loading
|
||||
*
|
||||
* @return Pointer to the entry function, NULL if no matching plugin could be found
|
||||
*/
|
||||
void* freerdp_load_static_plugin(const char* name, const char* entry_name)
|
||||
{
|
||||
staticPlugin* plugin;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < g_static_plugins_count; i++)
|
||||
{
|
||||
plugin = &g_static_plugins[i];
|
||||
if (!strcmp(plugin->name, name) && !strcmp(plugin->entry_name, entry_name))
|
||||
{
|
||||
return plugin->entry_addr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <errno.h>
|
||||
#include <freerdp/utils/passphrase.h>
|
||||
#ifdef _WIN32
|
||||
char* freerdp_passphrase_read(const char* prompt, char* buf, size_t bufsiz)
|
||||
char* freerdp_passphrase_read(const char* prompt, char* buf, size_t bufsiz, int from_stdin)
|
||||
{
|
||||
errno=ENOSYS;
|
||||
return NULL;
|
||||
@ -34,7 +34,7 @@ char* freerdp_passphrase_read(const char* prompt, char* buf, size_t bufsiz)
|
||||
#include <unistd.h>
|
||||
#include <freerdp/utils/signal.h>
|
||||
|
||||
char* freerdp_passphrase_read(const char* prompt, char* buf, size_t bufsiz)
|
||||
char* freerdp_passphrase_read(const char* prompt, char* buf, size_t bufsiz, int from_stdin)
|
||||
{
|
||||
char read_char;
|
||||
char* buf_iter;
|
||||
@ -50,7 +50,7 @@ char* freerdp_passphrase_read(const char* prompt, char* buf, size_t bufsiz)
|
||||
}
|
||||
|
||||
ctermid(term_name);
|
||||
if(strcmp(term_name, "") == 0
|
||||
if(from_stdin || strcmp(term_name, "") == 0
|
||||
|| (term_file = open(term_name, O_RDWR)) == -1)
|
||||
{
|
||||
write_file = STDERR_FILENO;
|
||||
|
@ -23,13 +23,13 @@
|
||||
#include <freerdp/utils/rail.h>
|
||||
#include <freerdp/rail.h>
|
||||
|
||||
void rail_unicode_string_alloc(UNICODE_STRING* unicode_string, uint16 cbString)
|
||||
void rail_unicode_string_alloc(RAIL_UNICODE_STRING* unicode_string, uint16 cbString)
|
||||
{
|
||||
unicode_string->length = cbString;
|
||||
unicode_string->string = xzalloc(cbString);
|
||||
}
|
||||
|
||||
void rail_unicode_string_free(UNICODE_STRING* unicode_string)
|
||||
void rail_unicode_string_free(RAIL_UNICODE_STRING* unicode_string)
|
||||
{
|
||||
unicode_string->length = 0;
|
||||
|
||||
@ -37,7 +37,7 @@ void rail_unicode_string_free(UNICODE_STRING* unicode_string)
|
||||
xfree(unicode_string->string);
|
||||
}
|
||||
|
||||
void rail_read_unicode_string(STREAM* s, UNICODE_STRING* unicode_string)
|
||||
void rail_read_unicode_string(STREAM* s, RAIL_UNICODE_STRING* unicode_string)
|
||||
{
|
||||
stream_read_uint16(s, unicode_string->length); /* cbString (2 bytes) */
|
||||
|
||||
@ -49,14 +49,14 @@ void rail_read_unicode_string(STREAM* s, UNICODE_STRING* unicode_string)
|
||||
stream_read(s, unicode_string->string, unicode_string->length);
|
||||
}
|
||||
|
||||
void rail_write_unicode_string(STREAM* s, UNICODE_STRING* unicode_string)
|
||||
void rail_write_unicode_string(STREAM* s, RAIL_UNICODE_STRING* unicode_string)
|
||||
{
|
||||
stream_check_size(s, 2 + unicode_string->length);
|
||||
stream_write_uint16(s, unicode_string->length); /* cbString (2 bytes) */
|
||||
stream_write(s, unicode_string->string, unicode_string->length); /* string */
|
||||
}
|
||||
|
||||
void rail_write_unicode_string_value(STREAM* s, UNICODE_STRING* unicode_string)
|
||||
void rail_write_unicode_string_value(STREAM* s, RAIL_UNICODE_STRING* unicode_string)
|
||||
{
|
||||
if (unicode_string->length > 0)
|
||||
{
|
||||
|
@ -32,4 +32,6 @@ if(NOT WIN32)
|
||||
|
||||
# Build Server Channels library
|
||||
add_subdirectory(channels)
|
||||
else()
|
||||
add_subdirectory(Windows)
|
||||
endif()
|
||||
|
26
server/Windows/CMakeLists.txt
Normal file
26
server/Windows/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Client
|
||||
# FreeRDP Windows Server cmake build script
|
||||
#
|
||||
# Copyright 2011 O.S. Systems Software Ltda.
|
||||
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
|
||||
# Copyright 2011 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.
|
||||
|
||||
add_executable(wfreerdp-server
|
||||
wfreerdp.c)
|
||||
|
||||
target_link_libraries(wfreerdp-server freerdp-core)
|
||||
target_link_libraries(wfreerdp-server freerdp-utils)
|
||||
target_link_libraries(wfreerdp-server freerdp-codec)
|
||||
target_link_libraries(wfreerdp-server freerdp-channels)
|
17
server/Windows/server.crt
Normal file
17
server/Windows/server.crt
Normal file
@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICyzCCAbOgAwIBAgIJANbqtAWwlQZuMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV
|
||||
BAMTB0ZyZWVSRFAwHhcNMDkxMDI5MDA0MTQ5WhcNMDkxMTI4MDA0MTQ5WjASMRAw
|
||||
DgYDVQQDEwdGcmVlUkRQMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||
q7mxFgRbS2FYJZX7BzpNd4T/n4nEVDBY6YaObLjGpaB1TptzXTcmfDrDslTGwcEY
|
||||
hTFAC4ZvY6yOURExqbph4LSgvkoa6J722RjVPfshGa4mlh2SXvTiaV26VPPxddGb
|
||||
o6fbs2u029lbtBlpIVbhx5RN9vstNkll26oSZ6wfEdBNHQJLd2SU4ItWHj8zjz1f
|
||||
eGxjgChHihUlwcBYKDJsKFkzHZmLrMgB37KsGlXi/WV+eEsjgvz4yP7I3TL8+GsN
|
||||
MjV8fRGVEKTbKSmgunO67d5u+IaqUQb0Ad1ha1jzDQ+a6hdymrulJSIhoOVfKkwi
|
||||
ptTe43FgwxVRIygJP9HjHQIDAQABoyQwIjATBgNVHSUEDDAKBggrBgEFBQcDATAL
|
||||
BgNVHQ8EBAMCBDAwDQYJKoZIhvcNAQEFBQADggEBAIOdEDhOX2kbl02znltd9hCr
|
||||
nV4kRPKm979RKwBNkrEuwYSlcsjAHg5MZ5itH3wFOUo2s5pjt7/vMOAg+6rOBbIa
|
||||
nqr22/gKBtOmuaJLG1yjxDC2vfez7f3B26pKgxa/krM8oxiFdT9n8QbdxdkN7/D9
|
||||
3RLU/aCfgrMzXxRus7eq3kR00jnSs6ggnAfE1E9gric3vFgr1wCzdcriRXmXDfUb
|
||||
hRq+4VG+ZWk16TwCofV5GVU39XWCv5HNO2swAdjkNXgI5e3tQbV3wWLZLqqYzBco
|
||||
iWulAXtoCGmE81+u1Ms7hLLzpXitLZSGPu1r+sDdkKPLCmOvkAaljDQ4nBz7fIA=
|
||||
-----END CERTIFICATE-----
|
27
server/Windows/server.key
Normal file
27
server/Windows/server.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAq7mxFgRbS2FYJZX7BzpNd4T/n4nEVDBY6YaObLjGpaB1Tptz
|
||||
XTcmfDrDslTGwcEYhTFAC4ZvY6yOURExqbph4LSgvkoa6J722RjVPfshGa4mlh2S
|
||||
XvTiaV26VPPxddGbo6fbs2u029lbtBlpIVbhx5RN9vstNkll26oSZ6wfEdBNHQJL
|
||||
d2SU4ItWHj8zjz1feGxjgChHihUlwcBYKDJsKFkzHZmLrMgB37KsGlXi/WV+eEsj
|
||||
gvz4yP7I3TL8+GsNMjV8fRGVEKTbKSmgunO67d5u+IaqUQb0Ad1ha1jzDQ+a6hdy
|
||||
mrulJSIhoOVfKkwiptTe43FgwxVRIygJP9HjHQIDAQABAoIBAAVv5K54xtc1JtBR
|
||||
1lfdPbSqDlnjx8aOnVIPg5TnqMp3sR8jBt0NsPc/+RA9ZOmfjoIxFAEJaZ9zSDJC
|
||||
5BqmnxC5R1mfCQkSd2haQ+4pdFvWyrv4Bblh8YU6hXrJGn0LfO0KlIcywtAvKpsi
|
||||
LtTyZkWmaW2HeF/+pO32jYygw38R1wd8Tl6GwjOXwTF6lFACJXOT4YAzcfp3FKSB
|
||||
AiKBIGuMzozoSND7KPFNRrhGhNumJpdS5A8Fb8D2c/ZMv6Cq5IbwOgTfKun+Bz+s
|
||||
mFbnzeb1uWRqQbsVXOBBW/zHfuG3SU5qeZsaAyuu4DTy+LE1oAHF9uhBSHuT5C6i
|
||||
vCJ8A8ECgYEA1iaOmiEJYBrs25iAc4SjCKqhY0mwR3wtu3I06vmgUoML5fhPMv36
|
||||
SvYQIqDyNw3p7TE6mZtw9+G+kK3PqhuJhogwSwg0a6o51RdKnhXH3/68oNWtKCLC
|
||||
1AmR8q/Gd3FwAR3b49CuOIZ9uOiJrc/ejzKdFEJTDR1/TX1frWfZznECgYEAzUiz
|
||||
XxFf7YrGel7JgmfRD2eZRYngOoteFlg5Tee42UjeAY2Pt2aiDLk+2TqQEdI9+Xg7
|
||||
LcFdBqcSNd8bh33xSzgNthIkX+lTDzx0SmKGfyxfFBJcY8nzsLvvnNt3YeuMeaJQ
|
||||
CPszwoZ0jcD46jTCjbrKhaLyEWmUkDp1O71NTW0CgYAXKF49Xpsz8FVyvcAOPeaf
|
||||
dkwzf3F3mX8ciRId4taqdY9g1AREgGCDoK5IAF2RBIkqZCtxFvUVaS0BWjpdq9Ko
|
||||
YKvQQVfh2KueVoF0LOjLWTGutsydzXyCD3Lf6pAstHCnPkJcFWHxrOGFkGfrCtKH
|
||||
a7K+0RlIDsuIZqllCBjukQKBgA31+MTpYJW+D1t5IMkumEgs6n6RLt+sZLyuSU9k
|
||||
B+03CGogn3qAj1rAKmcJlYywuKhDpfqpoNL3/8QMJUokpYlRCZWtTC39pzltCheY
|
||||
9b6mXNz3lrLupBUL4vLO9iKBq28GO90wgEelbz3ItuTuq6CJ6IYIG+BVRtY8M4bZ
|
||||
i+1NAoGANXZjYnJYDnh8Je9SDxDSc5byzK7ddkQoId64RCIfNHqNKH63P81vjgnH
|
||||
YBIPtagY75ZVVNxujCF7m8Rety+d8tEFwfQKDin2EVI7PD2rOJra385/izp7HuBR
|
||||
vqxvLzG9Xv3cNOU2l7PttVw4Pa2i5E37atKi3V3Zp2kMW+KaKPQ=
|
||||
-----END RSA PRIVATE KEY-----
|
288
server/Windows/wfreerdp.c
Normal file
288
server/Windows/wfreerdp.c
Normal file
@ -0,0 +1,288 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Client
|
||||
* FreeRDP Windows Server
|
||||
*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <winpr/windows.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/sleep.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
#include <freerdp/utils/thread.h>
|
||||
#include <freerdp/codec/rfx.h>
|
||||
#include <freerdp/codec/nsc.h>
|
||||
#include <freerdp/listener.h>
|
||||
|
||||
HANDLE g_done_event;
|
||||
int g_thread_count = 0;
|
||||
|
||||
struct wf_peer_context
|
||||
{
|
||||
rdpContext _p;
|
||||
boolean activated;
|
||||
};
|
||||
typedef struct wf_peer_context wfPeerContext;
|
||||
|
||||
void wf_peer_context_new(freerdp_peer* client, wfPeerContext* context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void wf_peer_context_free(freerdp_peer* client, wfPeerContext* context)
|
||||
{
|
||||
if (context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
static void wf_peer_init(freerdp_peer* client)
|
||||
{
|
||||
client->context_size = sizeof(wfPeerContext);
|
||||
client->ContextNew = (psPeerContextNew) wf_peer_context_new;
|
||||
client->ContextFree = (psPeerContextFree) wf_peer_context_free;
|
||||
freerdp_peer_context_new(client);
|
||||
}
|
||||
|
||||
boolean wf_peer_post_connect(freerdp_peer* client)
|
||||
{
|
||||
wfPeerContext* context = (wfPeerContext*) client->context;
|
||||
|
||||
/**
|
||||
* This callback is called when the entire connection sequence is done, i.e. we've received the
|
||||
* Font List PDU from the client and sent out the Font Map PDU.
|
||||
* The server may start sending graphics output and receiving keyboard/mouse input after this
|
||||
* callback returns.
|
||||
*/
|
||||
|
||||
printf("Client %s is activated (osMajorType %d osMinorType %d)", client->local ? "(local)" : client->hostname,
|
||||
client->settings->os_major_type, client->settings->os_minor_type);
|
||||
|
||||
if (client->settings->autologon)
|
||||
{
|
||||
printf(" and wants to login automatically as %s\\%s",
|
||||
client->settings->domain ? client->settings->domain : "",
|
||||
client->settings->username);
|
||||
|
||||
/* A real server may perform OS login here if NLA is not executed previously. */
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Client requested desktop: %dx%dx%d\n",
|
||||
client->settings->width, client->settings->height, client->settings->color_depth);
|
||||
|
||||
/* A real server should tag the peer as activated here and start sending updates in main loop. */
|
||||
|
||||
/* Return false here would stop the execution of the peer mainloop. */
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean wf_peer_activate(freerdp_peer* client)
|
||||
{
|
||||
wfPeerContext* context = (wfPeerContext*) client->context;
|
||||
|
||||
context->activated = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wf_peer_synchronize_event(rdpInput* input, uint32 flags)
|
||||
{
|
||||
printf("Client sent a synchronize event (flags:0x%X)\n", flags);
|
||||
}
|
||||
|
||||
void wf_peer_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
|
||||
{
|
||||
freerdp_peer* client = input->context->peer;
|
||||
rdpUpdate* update = client->update;
|
||||
wfPeerContext* context = (wfPeerContext*) input->context;
|
||||
|
||||
printf("Client sent a keyboard event (flags:0x%X code:0x%X)\n", flags, code);
|
||||
|
||||
if ((flags & 0x4000) && code == 0x1F) /* 's' key */
|
||||
{
|
||||
if (client->settings->width != 800)
|
||||
{
|
||||
client->settings->width = 800;
|
||||
client->settings->height = 600;
|
||||
}
|
||||
else
|
||||
{
|
||||
client->settings->width = 640;
|
||||
client->settings->height = 480;
|
||||
}
|
||||
update->DesktopResize(update->context);
|
||||
context->activated = false;
|
||||
}
|
||||
else if ((flags & 0x4000) && code == 0x2D) /* 'x' key */
|
||||
{
|
||||
client->Close(client);
|
||||
}
|
||||
}
|
||||
|
||||
void wf_peer_unicode_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
|
||||
{
|
||||
printf("Client sent a unicode keyboard event (flags:0x%X code:0x%X)\n", flags, code);
|
||||
}
|
||||
|
||||
void wf_peer_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
|
||||
{
|
||||
printf("Client sent a mouse event (flags:0x%X pos:%d,%d)\n", flags, x, y);
|
||||
}
|
||||
|
||||
void wf_peer_extended_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
|
||||
{
|
||||
printf("Client sent an extended mouse event (flags:0x%X pos:%d,%d)\n", flags, x, y);
|
||||
}
|
||||
|
||||
static DWORD WINAPI wf_peer_main_loop(LPVOID lpParam)
|
||||
{
|
||||
int rcount;
|
||||
void* rfds[32];
|
||||
wfPeerContext* context;
|
||||
freerdp_peer* client = (freerdp_peer*) lpParam;
|
||||
|
||||
memset(rfds, 0, sizeof(rfds));
|
||||
|
||||
wf_peer_init(client);
|
||||
|
||||
/* Initialize the real server settings here */
|
||||
client->settings->cert_file = xstrdup("server.crt");
|
||||
client->settings->privatekey_file = xstrdup("server.key");
|
||||
|
||||
client->settings->nla_security = true;
|
||||
client->settings->tls_security = false;
|
||||
client->settings->rdp_security = false;
|
||||
|
||||
client->PostConnect = wf_peer_post_connect;
|
||||
client->Activate = wf_peer_activate;
|
||||
|
||||
client->input->SynchronizeEvent = wf_peer_synchronize_event;
|
||||
client->input->KeyboardEvent = wf_peer_keyboard_event;
|
||||
client->input->UnicodeKeyboardEvent = wf_peer_unicode_keyboard_event;
|
||||
client->input->MouseEvent = wf_peer_mouse_event;
|
||||
client->input->ExtendedMouseEvent = wf_peer_extended_mouse_event;
|
||||
|
||||
client->Initialize(client);
|
||||
context = (wfPeerContext*) client->context;
|
||||
|
||||
printf("We've got a client %s\n", client->local ? "(local)" : client->hostname);
|
||||
|
||||
while (1)
|
||||
{
|
||||
rcount = 0;
|
||||
|
||||
if (client->GetFileDescriptor(client, rfds, &rcount) != true)
|
||||
{
|
||||
printf("Failed to get FreeRDP file descriptor\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (client->CheckFileDescriptor(client) != true)
|
||||
{
|
||||
printf("Failed to check FreeRDP file descriptor\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Client %s disconnected.\n", client->local ? "(local)" : client->hostname);
|
||||
|
||||
client->Disconnect(client);
|
||||
freerdp_peer_context_free(client);
|
||||
freerdp_peer_free(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wf_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
|
||||
{
|
||||
/* start peer main loop thread */
|
||||
|
||||
if (CreateThread(NULL, 0, wf_peer_main_loop, client, 0, NULL) != 0)
|
||||
g_thread_count++;
|
||||
}
|
||||
|
||||
static void wf_server_main_loop(freerdp_listener* instance)
|
||||
{
|
||||
int rcount;
|
||||
void* rfds[32];
|
||||
|
||||
memset(rfds, 0, sizeof(rfds));
|
||||
|
||||
while (1)
|
||||
{
|
||||
rcount = 0;
|
||||
|
||||
if (instance->GetFileDescriptor(instance, rfds, &rcount) != true)
|
||||
{
|
||||
printf("Failed to get FreeRDP file descriptor\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (instance->CheckFileDescriptor(instance) != true)
|
||||
{
|
||||
printf("Failed to check FreeRDP file descriptor\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
instance->Close(instance);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int port = 3389;
|
||||
WSADATA wsa_data;
|
||||
freerdp_listener* instance;
|
||||
|
||||
instance = freerdp_listener_new();
|
||||
|
||||
instance->PeerAccepted = wf_peer_accepted;
|
||||
|
||||
if (WSAStartup(0x101, &wsa_data) != 0)
|
||||
return 1;
|
||||
|
||||
g_done_event = CreateEvent(0, 1, 0, 0);
|
||||
|
||||
if (argc == 2)
|
||||
port = atoi(argv[1]);
|
||||
|
||||
/* Open the server socket and start listening. */
|
||||
|
||||
if (instance->Open(instance, NULL, port))
|
||||
{
|
||||
/* Entering the server main loop. In a real server the listener can be run in its own thread. */
|
||||
wf_server_main_loop(instance);
|
||||
}
|
||||
|
||||
if (g_thread_count > 0)
|
||||
WaitForSingleObject(g_done_event, INFINITE);
|
||||
else
|
||||
MessageBox(GetConsoleWindow(),
|
||||
L"Failed to start wfreerdp-server.\n\nPlease check the debug output.",
|
||||
L"FreeRDP Error", MB_ICONSTOP);
|
||||
|
||||
WSACleanup();
|
||||
|
||||
freerdp_listener_free(instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -273,7 +273,6 @@ void xf_peer_context_free(freerdp_peer* client, xfPeerContext* context)
|
||||
{
|
||||
stream_free(context->s);
|
||||
rfx_context_free(context->rfx_context);
|
||||
xfree(context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -634,6 +633,8 @@ void* xf_peer_main_loop(void* arg)
|
||||
settings->privatekey_file = freerdp_construct_path(server_file_path, "server.key");
|
||||
|
||||
settings->nla_security = true;
|
||||
settings->tls_security = false;
|
||||
settings->rdp_security = false;
|
||||
|
||||
settings->rfx_codec = true;
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
set(FREERDP_SERVER_CHANNELS_SRCS
|
||||
audin.c
|
||||
rdpsnd.c
|
||||
)
|
||||
|
||||
|
427
server/channels/audin.c
Normal file
427
server/channels/audin.c
Normal file
@ -0,0 +1,427 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* Server Audio Input Virtual Channel
|
||||
*
|
||||
* Copyright 2012 Vic Lee
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/utils/stream.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
#include <freerdp/utils/dsp.h>
|
||||
#include <freerdp/utils/thread.h>
|
||||
#include <freerdp/utils/wait_obj.h>
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
#include <freerdp/server/audin.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MSG_SNDIN_VERSION 0x01
|
||||
#define MSG_SNDIN_FORMATS 0x02
|
||||
#define MSG_SNDIN_OPEN 0x03
|
||||
#define MSG_SNDIN_OPEN_REPLY 0x04
|
||||
#define MSG_SNDIN_DATA_INCOMING 0x05
|
||||
#define MSG_SNDIN_DATA 0x06
|
||||
#define MSG_SNDIN_FORMATCHANGE 0x07
|
||||
|
||||
typedef struct _audin_server
|
||||
{
|
||||
audin_server_context context;
|
||||
|
||||
void* audin_channel;
|
||||
freerdp_thread* audin_channel_thread;
|
||||
|
||||
FREERDP_DSP_CONTEXT* dsp_context;
|
||||
|
||||
boolean opened;
|
||||
} audin_server;
|
||||
|
||||
static void audin_server_select_format(audin_server_context* context, int client_format_index)
|
||||
{
|
||||
audin_server* audin = (audin_server*) context;
|
||||
|
||||
if (client_format_index >= context->num_client_formats)
|
||||
return;
|
||||
context->selected_client_format = client_format_index;
|
||||
if (audin->opened)
|
||||
{
|
||||
/* TODO: send MSG_SNDIN_FORMATCHANGE */
|
||||
}
|
||||
}
|
||||
|
||||
static void audin_server_send_version(audin_server* audin, STREAM* s)
|
||||
{
|
||||
stream_write_uint8(s, MSG_SNDIN_VERSION);
|
||||
stream_write_uint32(s, 1); /* Version (4 bytes) */
|
||||
WTSVirtualChannelWrite(audin->audin_channel, stream_get_head(s), stream_get_length(s), NULL);
|
||||
}
|
||||
|
||||
static boolean audin_server_recv_version(audin_server* audin, STREAM* s, uint32 length)
|
||||
{
|
||||
uint32 Version;
|
||||
|
||||
if (length < 4)
|
||||
return false;
|
||||
stream_read_uint32(s, Version);
|
||||
if (Version < 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void audin_server_send_formats(audin_server* audin, STREAM* s)
|
||||
{
|
||||
int i;
|
||||
uint32 nAvgBytesPerSec;
|
||||
|
||||
stream_set_pos(s, 0);
|
||||
stream_write_uint8(s, MSG_SNDIN_FORMATS);
|
||||
stream_write_uint32(s, audin->context.num_server_formats); /* NumFormats (4 bytes) */
|
||||
stream_write_uint32(s, 0); /* cbSizeFormatsPacket (4 bytes), client-to-server only */
|
||||
|
||||
for (i = 0; i < audin->context.num_server_formats; i++)
|
||||
{
|
||||
nAvgBytesPerSec = audin->context.server_formats[i].nSamplesPerSec *
|
||||
audin->context.server_formats[i].nChannels *
|
||||
audin->context.server_formats[i].wBitsPerSample / 8;
|
||||
stream_check_size(s, 18);
|
||||
stream_write_uint16(s, audin->context.server_formats[i].wFormatTag);
|
||||
stream_write_uint16(s, audin->context.server_formats[i].nChannels);
|
||||
stream_write_uint32(s, audin->context.server_formats[i].nSamplesPerSec);
|
||||
stream_write_uint32(s, nAvgBytesPerSec);
|
||||
stream_write_uint16(s, audin->context.server_formats[i].nBlockAlign);
|
||||
stream_write_uint16(s, audin->context.server_formats[i].wBitsPerSample);
|
||||
stream_write_uint16(s, audin->context.server_formats[i].cbSize);
|
||||
if (audin->context.server_formats[i].cbSize)
|
||||
{
|
||||
stream_check_size(s, audin->context.server_formats[i].cbSize);
|
||||
stream_write(s, audin->context.server_formats[i].data,
|
||||
audin->context.server_formats[i].cbSize);
|
||||
}
|
||||
}
|
||||
|
||||
WTSVirtualChannelWrite(audin->audin_channel, stream_get_head(s), stream_get_length(s), NULL);
|
||||
}
|
||||
|
||||
static boolean audin_server_recv_formats(audin_server* audin, STREAM* s, uint32 length)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (length < 8)
|
||||
return false;
|
||||
|
||||
stream_read_uint32(s, audin->context.num_client_formats); /* NumFormats (4 bytes) */
|
||||
stream_seek_uint32(s); /* cbSizeFormatsPacket (4 bytes) */
|
||||
length -= 8;
|
||||
|
||||
if (audin->context.num_client_formats <= 0)
|
||||
return false;
|
||||
|
||||
audin->context.client_formats = xzalloc(audin->context.num_client_formats * sizeof(rdpsndFormat));
|
||||
for (i = 0; i < audin->context.num_client_formats; i++)
|
||||
{
|
||||
if (length < 18)
|
||||
{
|
||||
xfree(audin->context.client_formats);
|
||||
audin->context.client_formats = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
stream_read_uint16(s, audin->context.client_formats[i].wFormatTag);
|
||||
stream_read_uint16(s, audin->context.client_formats[i].nChannels);
|
||||
stream_read_uint32(s, audin->context.client_formats[i].nSamplesPerSec);
|
||||
stream_seek_uint32(s); /* nAvgBytesPerSec */
|
||||
stream_read_uint16(s, audin->context.client_formats[i].nBlockAlign);
|
||||
stream_read_uint16(s, audin->context.client_formats[i].wBitsPerSample);
|
||||
stream_read_uint16(s, audin->context.client_formats[i].cbSize);
|
||||
if (audin->context.client_formats[i].cbSize > 0)
|
||||
{
|
||||
stream_seek(s, audin->context.client_formats[i].cbSize);
|
||||
}
|
||||
}
|
||||
|
||||
IFCALL(audin->context.Opening, &audin->context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void audin_server_send_open(audin_server* audin, STREAM* s)
|
||||
{
|
||||
if (audin->context.selected_client_format < 0)
|
||||
return;
|
||||
|
||||
audin->opened = true;
|
||||
|
||||
stream_set_pos(s, 0);
|
||||
stream_write_uint8(s, MSG_SNDIN_OPEN);
|
||||
stream_write_uint32(s, audin->context.frames_per_packet); /* FramesPerPacket (4 bytes) */
|
||||
stream_write_uint32(s, audin->context.selected_client_format); /* initialFormat (4 bytes) */
|
||||
/*
|
||||
* [MS-RDPEAI] 3.2.5.1.6
|
||||
* The second format specify the format that SHOULD be used to capture data from
|
||||
* the actual audio input device.
|
||||
*/
|
||||
stream_write_uint16(s, 1); /* wFormatTag = PCM */
|
||||
stream_write_uint16(s, 2); /* nChannels */
|
||||
stream_write_uint32(s, 44100); /* nSamplesPerSec */
|
||||
stream_write_uint32(s, 44100 * 2 * 2); /* nAvgBytesPerSec */
|
||||
stream_write_uint16(s, 4); /* nBlockAlign */
|
||||
stream_write_uint16(s, 16); /* wBitsPerSample */
|
||||
stream_write_uint16(s, 0); /* cbSize */
|
||||
|
||||
WTSVirtualChannelWrite(audin->audin_channel, stream_get_head(s), stream_get_length(s), NULL);
|
||||
}
|
||||
|
||||
static boolean audin_server_recv_open_reply(audin_server* audin, STREAM* s, uint32 length)
|
||||
{
|
||||
uint32 Result;
|
||||
|
||||
if (length < 4)
|
||||
return false;
|
||||
stream_read_uint32(s, Result);
|
||||
|
||||
IFCALL(audin->context.OpenResult, &audin->context, Result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean audin_server_recv_data(audin_server* audin, STREAM* s, uint32 length)
|
||||
{
|
||||
rdpsndFormat* format;
|
||||
int sbytes_per_sample;
|
||||
int sbytes_per_frame;
|
||||
uint8* src;
|
||||
int size;
|
||||
int frames;
|
||||
|
||||
if (audin->context.selected_client_format < 0)
|
||||
return false;
|
||||
|
||||
format = &audin->context.client_formats[audin->context.selected_client_format];
|
||||
|
||||
if (format->wFormatTag == 2)
|
||||
{
|
||||
audin->dsp_context->decode_ms_adpcm(audin->dsp_context,
|
||||
stream_get_tail(s), length, format->nChannels, format->nBlockAlign);
|
||||
size = audin->dsp_context->adpcm_size;
|
||||
src = audin->dsp_context->adpcm_buffer;
|
||||
sbytes_per_sample = 2;
|
||||
sbytes_per_frame = format->nChannels * 2;
|
||||
}
|
||||
else if (format->wFormatTag == 0x11)
|
||||
{
|
||||
audin->dsp_context->decode_ima_adpcm(audin->dsp_context,
|
||||
stream_get_tail(s), length, format->nChannels, format->nBlockAlign);
|
||||
size = audin->dsp_context->adpcm_size;
|
||||
src = audin->dsp_context->adpcm_buffer;
|
||||
sbytes_per_sample = 2;
|
||||
sbytes_per_frame = format->nChannels * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = length;
|
||||
src = stream_get_tail(s);
|
||||
sbytes_per_sample = format->wBitsPerSample / 8;
|
||||
sbytes_per_frame = format->nChannels * sbytes_per_sample;
|
||||
}
|
||||
|
||||
if (format->nSamplesPerSec == audin->context.dst_format.nSamplesPerSec && format->nChannels == audin->context.dst_format.nChannels)
|
||||
{
|
||||
frames = size / sbytes_per_frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
audin->dsp_context->resample(audin->dsp_context, src, sbytes_per_sample,
|
||||
format->nChannels, format->nSamplesPerSec, size / sbytes_per_frame,
|
||||
audin->context.dst_format.nChannels, audin->context.dst_format.nSamplesPerSec);
|
||||
frames = audin->dsp_context->resampled_frames;
|
||||
src = audin->dsp_context->resampled_buffer;
|
||||
}
|
||||
|
||||
IFCALL(audin->context.ReceiveSamples, &audin->context, src, frames);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void* audin_server_thread_func(void* arg)
|
||||
{
|
||||
void* fd;
|
||||
STREAM* s;
|
||||
void* buffer;
|
||||
uint8 MessageId;
|
||||
boolean ready = false;
|
||||
uint32 bytes_returned = 0;
|
||||
audin_server* audin = (audin_server*) arg;
|
||||
freerdp_thread* thread = audin->audin_channel_thread;
|
||||
|
||||
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == true)
|
||||
{
|
||||
fd = *((void**)buffer);
|
||||
WTSFreeMemory(buffer);
|
||||
thread->signals[thread->num_signals++] = wait_obj_new_with_fd(fd);
|
||||
}
|
||||
|
||||
/* Wait for the client to confirm that the Audio Input dynamic channel is ready */
|
||||
while (1)
|
||||
{
|
||||
freerdp_thread_wait(thread);
|
||||
if (freerdp_thread_is_stopped(thread))
|
||||
break;
|
||||
|
||||
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &bytes_returned) == false)
|
||||
break;
|
||||
ready = *((boolean*)buffer);
|
||||
WTSFreeMemory(buffer);
|
||||
if (ready)
|
||||
break;
|
||||
}
|
||||
|
||||
s = stream_new(4096);
|
||||
|
||||
if (ready)
|
||||
{
|
||||
audin_server_send_version(audin, s);
|
||||
}
|
||||
|
||||
while (ready)
|
||||
{
|
||||
freerdp_thread_wait(thread);
|
||||
if (freerdp_thread_is_stopped(thread))
|
||||
break;
|
||||
|
||||
stream_set_pos(s, 0);
|
||||
if (WTSVirtualChannelRead(audin->audin_channel, 0, stream_get_head(s),
|
||||
stream_get_size(s), &bytes_returned) == false)
|
||||
{
|
||||
if (bytes_returned == 0)
|
||||
break;
|
||||
stream_check_size(s, bytes_returned);
|
||||
if (WTSVirtualChannelRead(audin->audin_channel, 0, stream_get_head(s),
|
||||
stream_get_size(s), &bytes_returned) == false)
|
||||
break;
|
||||
}
|
||||
if (bytes_returned < 1)
|
||||
continue;
|
||||
|
||||
stream_read_uint8(s, MessageId);
|
||||
bytes_returned--;
|
||||
switch (MessageId)
|
||||
{
|
||||
case MSG_SNDIN_VERSION:
|
||||
if (audin_server_recv_version(audin, s, bytes_returned))
|
||||
audin_server_send_formats(audin, s);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_FORMATS:
|
||||
if (audin_server_recv_formats(audin, s, bytes_returned))
|
||||
audin_server_send_open(audin, s);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_OPEN_REPLY:
|
||||
audin_server_recv_open_reply(audin, s, bytes_returned);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_DATA_INCOMING:
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_DATA:
|
||||
audin_server_recv_data(audin, s, bytes_returned);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_FORMATCHANGE:
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("audin_server_thread_func: unknown MessageId %d\n", MessageId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stream_free(s);
|
||||
WTSVirtualChannelClose(audin->audin_channel);
|
||||
audin->audin_channel = NULL;
|
||||
freerdp_thread_quit(thread);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static boolean audin_server_open(audin_server_context* context)
|
||||
{
|
||||
audin_server* audin = (audin_server*) context;
|
||||
|
||||
if (audin->audin_channel_thread == NULL)
|
||||
{
|
||||
audin->audin_channel = WTSVirtualChannelOpenEx(context->vcm, "AUDIO_INPUT", WTS_CHANNEL_OPTION_DYNAMIC);
|
||||
if (audin->audin_channel == NULL)
|
||||
return false;
|
||||
|
||||
audin->audin_channel_thread = freerdp_thread_new();
|
||||
freerdp_thread_start(audin->audin_channel_thread, audin_server_thread_func, audin);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean audin_server_close(audin_server_context* context)
|
||||
{
|
||||
audin_server* audin = (audin_server*) context;
|
||||
|
||||
if (audin->audin_channel_thread)
|
||||
{
|
||||
freerdp_thread_stop(audin->audin_channel_thread);
|
||||
freerdp_thread_free(audin->audin_channel_thread);
|
||||
audin->audin_channel_thread = NULL;
|
||||
}
|
||||
if (audin->audin_channel)
|
||||
{
|
||||
WTSVirtualChannelClose(audin->audin_channel);
|
||||
audin->audin_channel = NULL;
|
||||
}
|
||||
audin->context.selected_client_format = -1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
audin_server_context* audin_server_context_new(WTSVirtualChannelManager* vcm)
|
||||
{
|
||||
audin_server* audin;
|
||||
|
||||
audin = xnew(audin_server);
|
||||
audin->context.vcm = vcm;
|
||||
audin->context.selected_client_format = -1;
|
||||
audin->context.frames_per_packet = 4096;
|
||||
audin->context.SelectFormat = audin_server_select_format;
|
||||
audin->context.Open = audin_server_open;
|
||||
audin->context.Close = audin_server_close;
|
||||
|
||||
audin->dsp_context = freerdp_dsp_context_new();
|
||||
|
||||
return (audin_server_context*) audin;
|
||||
}
|
||||
|
||||
void audin_server_context_free(audin_server_context* context)
|
||||
{
|
||||
audin_server* audin = (audin_server*) context;
|
||||
|
||||
audin_server_close(context);
|
||||
if (audin->dsp_context)
|
||||
freerdp_dsp_context_free(audin->dsp_context);
|
||||
if (audin->context.client_formats)
|
||||
xfree(audin->context.client_formats);
|
||||
xfree(audin);
|
||||
}
|
@ -24,3 +24,4 @@ target_link_libraries(tfreerdp-server freerdp-core)
|
||||
target_link_libraries(tfreerdp-server freerdp-utils)
|
||||
target_link_libraries(tfreerdp-server freerdp-codec)
|
||||
target_link_libraries(tfreerdp-server freerdp-channels)
|
||||
target_link_libraries(tfreerdp-server freerdp-server-channels)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user